Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/__tests__/native/root-variable-registry.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { rootVariables, universalVariables } from "../../native-internal/root";

test("the module's exports are the registries published on globalThis", () => {
const registries = globalThis.__react_native_css_root_variable_registries;

expect(registries).toBeDefined();
expect(rootVariables).toBe(registries?.root);
expect(universalVariables).toBe(registries?.universal);
});

test("a second copy of the module shares the registries and does not re-seed", () => {
// resetModules evaluates the module again against the same globalThis, as a second build in one bundle does
const firstCopy = jest.requireActual<
typeof import("../../native-internal/root")
>("../../native-internal/root");

expect(firstCopy.rootVariables("__rn-css-rem").get()).toBe(14);
firstCopy.rootVariables("__rn-css-rem").set([[16]]);

jest.resetModules();
const secondCopy = jest.requireActual<
typeof import("../../native-internal/root")
>("../../native-internal/root");

// The module body really re-ran, so the assertions below are about two copies
expect(secondCopy).not.toBe(firstCopy);

expect(secondCopy.rootVariables).toBe(firstCopy.rootVariables);
expect(secondCopy.rootVariables("__rn-css-rem").get()).toBe(16);
});
53 changes: 40 additions & 13 deletions src/native-internal/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,43 @@ const rootVariableFamily = () => {
});
};

export const rootVariables = rootVariableFamily();
export const universalVariables = rootVariableFamily();

rootVariables("__rn-css-rem").set([[14]]);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
rootVariables("__rn-css-color").set([
[
Platform.OS === "ios"
? PlatformColor("label", "labelColor")
: PlatformColor("?attr/textColorPrimary", "SystemBaseHighColor"),
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any);
interface RootVariableRegistries {
root: ReturnType<typeof rootVariableFamily>;
universal: ReturnType<typeof rootVariableFamily>;
}

declare global {
var __react_native_css_root_variable_registries:
| RootVariableRegistries
| undefined;
}

// Seeded with the registries, so a copy that loads after the stylesheet inject keeps the project's rem
function createRootVariableRegistries(): RootVariableRegistries {
const registries: RootVariableRegistries = {
root: rootVariableFamily(),
universal: rootVariableFamily(),
};

registries.root("__rn-css-rem").set([[14]]);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
registries.root("__rn-css-color").set([
[
Platform.OS === "ios"
? PlatformColor("label", "labelColor")
: PlatformColor("?attr/textColorPrimary", "SystemBaseHighColor"),
],
// eslint-disable-next-line @typescript-eslint/no-explicit-any
] as any);

return registries;
}

// The exports map gives import and require different builds, and Metro resolves each per requesting module
globalThis.__react_native_css_root_variable_registries ??=
createRootVariableRegistries();

export const rootVariables =
globalThis.__react_native_css_root_variable_registries.root;
export const universalVariables =
globalThis.__react_native_css_root_variable_registries.universal;