Skip to content

Commit

Permalink
feat: support reactive themes up to 4 levels deep
Browse files Browse the repository at this point in the history
  • Loading branch information
nmn committed Oct 31, 2024
1 parent 1c21e88 commit 2e9dde6
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,35 +92,44 @@ describe('Evaluation of imported values works based on configuration', () => {
const transformation = transform(`
import stylex from 'stylex';
import { MyTheme } from 'otherFile.stylex';
const styles = stylex.create({
red: {
color: MyTheme.__themeName__,
}
import { DepToken } from 'dependency.stylex';
export const dark = stylex.createTheme(MyTheme, {
primary: DepToken.black,
});
stylex(styles.red);
`);

const expectedVarName =
options.classNamePrefix + hash('otherFile.stylex.js//MyTheme');
expect(expectedVarName).toMatchInlineSnapshot(`"__hashed_var__jvfbhb"`);
const expectedDepName =
options.classNamePrefix + hash('dependency.stylex.js//DepToken');
expect(expectedDepName).toMatchInlineSnapshot(`"__hashed_var__1hqhwsz"`);

expect(transformation.code).toContain(expectedVarName);
expect(transformation.code).toMatchInlineSnapshot(`
"import _inject from "@stylexjs/stylex/lib/stylex-inject";
var _inject2 = _inject;
import stylex from 'stylex';
import 'otherFile.stylex';
import { MyTheme } from 'otherFile.stylex';
_inject2(".__hashed_var__1yh36a2{color:__hashed_var__jvfbhb}", 3000);
"__hashed_var__1yh36a2";"
import 'dependency.stylex';
import { DepToken } from 'dependency.stylex';
_inject2(".__hashed_var__1jub2fi, .__hashed_var__1jub2fi:root, __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz{--__hashed_var__pr5b8h:var(--__hashed_var__672cz0);}", 0.5);
export const dark = {
$$css: true,
__hashed_var__jvfbhb: "__hashed_var__1jub2fi __hashed_var__jvfbhb"
};"
`);
expect(transformation.metadata.stylex).toMatchInlineSnapshot(`
[
[
"__hashed_var__1yh36a2",
"__hashed_var__1jub2fi",
{
"ltr": ".__hashed_var__1yh36a2{color:__hashed_var__jvfbhb}",
"ltr": ".__hashed_var__1jub2fi, .__hashed_var__1jub2fi:root, __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz, __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__jvfbhb __hashed_var__1jub2fi .__hashed_var__1hqhwsz{--__hashed_var__pr5b8h:var(--__hashed_var__672cz0);}",
"rtl": null,
},
3000,
0.5,
],
]
`);
Expand Down
11 changes: 11 additions & 0 deletions packages/babel-plugin/src/utils/evaluate-path.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ function evaluateThemeRef(
{},
{
get(_, key: string) {
proxyTracker?.add(resolveKey('__themeName__'));
return resolveKey(key);
},
set(_, key: string, value: string) {
Expand Down Expand Up @@ -800,6 +801,16 @@ function evaluateQuasis(
// so the logic can be localized this file.
const importsForState = new WeakMap<StateManager, Set<string>>();

let proxyTracker: ?Set<string> = null;

export const setProxyTracker = (valueToSet: Set<string>): void => {
proxyTracker = valueToSet;
};

export const resetProxyTracker = (): void => {
proxyTracker = null;
};

export function evaluate(
path: NodePath<>,
traversalState: StateManager,
Expand Down
12 changes: 11 additions & 1 deletion packages/babel-plugin/src/visitors/stylex-create-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import {
type InjectableStyle,
} from '@stylexjs/shared';
import { convertObjectToAST } from '../utils/js-to-ast';
import { evaluate } from '../utils/evaluate-path';
import {
evaluate,
resetProxyTracker,
setProxyTracker,
} from '../utils/evaluate-path';
import * as pathUtils from '../babel-path-utils';
import path from 'path';
import type { FunctionConfig } from '../utils/evaluate-path';
Expand Down Expand Up @@ -112,6 +116,9 @@ export default function transformStyleXCreateTheme(
identifiers[name] = { ...(identifiers[name] ?? {}), types };
});

const dependencies = new Set<string>();
setProxyTracker(dependencies);

const { confident: confident2, value: overrides } = evaluate(
secondArg,
state,
Expand All @@ -120,6 +127,8 @@ export default function transformStyleXCreateTheme(
memberExpressions,
},
);
resetProxyTracker();

if (!confident2) {
throw callExpressionPath.buildCodeFrameError(
messages.NON_STATIC_VALUE,
Expand Down Expand Up @@ -149,6 +158,7 @@ export default function transformStyleXCreateTheme(
variables,
overrides,
state.options,
dependencies,
);

if (state.isTest) {
Expand Down
28 changes: 22 additions & 6 deletions packages/shared/src/stylex-create-theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export default function styleXCreateTheme(
themeVars: { +__themeName__: string, +[string]: string },
variables: { +[string]: string | { default: string, +[string]: string } },
options?: StyleXOptions,
dependencies?: Set<string>,
): [{ $$css: true, +[string]: string }, { [string]: InjectableStyle }] {
if (typeof themeVars.__themeName__ !== 'string') {
throw new Error(
Expand Down Expand Up @@ -63,9 +64,27 @@ export default function styleXCreateTheme(

const stylesToInject: { [string]: InjectableStyle } = {};

const baseClassName = themeVars.__themeName__;
let baseSelectors = `.${overrideClassName}, .${overrideClassName}:root`;
if (dependencies != null && dependencies.size > 0) {
const depList = Array.from(dependencies);
const reactiveSelectorList = depList
.map((dep) =>
[
`${overrideClassName} .${dep}`,
`${baseClassName} ${overrideClassName} .${dep}`,
`${baseClassName} ${baseClassName} ${overrideClassName} .${dep}`,
`${baseClassName} ${baseClassName} ${baseClassName} ${overrideClassName} .${dep}`,
].join(', '),
)
.join(', ');
baseSelectors = [baseSelectors, reactiveSelectorList].join(', ');
}
for (const atRule of sortedAtRules) {
const decls = rulesByAtRule[atRule].join('');
const rule = `.${overrideClassName}, .${overrideClassName}:root{${decls}}`;
const rule = `${baseSelectors}{${decls}}`;
if (atRule === 'default') {
stylesToInject[overrideClassName] = {
Expand All @@ -82,10 +101,7 @@ export default function styleXCreateTheme(
}
}
const themeClass = `${overrideClassName} ${themeVars.__themeName__}`;
const themeClass = `${overrideClassName} ${baseClassName}`;

return [
{ $$css: true, [themeVars.__themeName__]: themeClass },
stylesToInject,
];
return [{ $$css: true, [baseClassName]: themeClass }, stylesToInject];
}

0 comments on commit 2e9dde6

Please sign in to comment.