Skip to content

Commit

Permalink
Merge pull request #29 from lxsmnsyc/feat-global
Browse files Browse the repository at this point in the history
feat: new jsx global
  • Loading branch information
lxsmnsyc authored Nov 26, 2023
2 parents 8eddf0d + 3895963 commit decad97
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 42 deletions.
1 change: 1 addition & 0 deletions packages/solid-styled/compiler/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export const RUNTIME_IDENTIFIERS = {
createCSSVars: 'createCSSVars',
mergeStyles: 'mergeStyles',
useSolidStyled: 'useSolidStyled',
useSolidStyledGlobal: 'useSolidStyledGlobal',
};
7 changes: 4 additions & 3 deletions packages/solid-styled/compiler/core/process-css-template.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as t from '@babel/types';
import type { StateContext } from '../types';
import preprocessCSS from './preprocess-css';
import processScopedSheet from './process-scoped-sheet';
import processScopedSheet from './process-scoped-sheet.old';
import { getPrefix, getUniqueId } from './utils';

interface DynamicTemplateResult {
Expand Down Expand Up @@ -52,10 +52,11 @@ export default function processCSSTemplate(
): DynamicTemplateResult {
// Replace the template's dynamic parts with CSS variables
const { sheet, variables } = replaceDynamicTemplate(ctx, templateLiteral);
const preprocessed = preprocessCSS(ctx, sheet);
return {
sheet: isScoped
? processScopedSheet(ctx, sheetID, sheet)
: preprocessCSS(ctx, sheet),
? preprocessCSS(ctx, processScopedSheet(ctx, sheetID, preprocessed))
: preprocessed,
variables,
};
}
10 changes: 8 additions & 2 deletions packages/solid-styled/compiler/core/process-scoped-sheet.old.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import * as csstree from 'css-tree';
import { GLOBAL_SELECTOR, SOLID_STYLED_NS } from './constants';
import type { StateContext } from '../types';

export default function processScopedSheet(
ctx: StateContext,
sheetID: string,
ast: csstree.CssNode,
): void {
content: string,
): string {
console.log(content);
const ast = csstree.parse(content);
// This selector is going to be inserted
// on every non-global selector
// [s\:${sheetID}]
Expand Down Expand Up @@ -173,4 +177,6 @@ export default function processScopedSheet(
}
},
});

return csstree.generate(ast);
}
57 changes: 37 additions & 20 deletions packages/solid-styled/compiler/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,27 +259,44 @@ function processJSXTemplate(
const current = sheet.count + 1;
sheet.count = current;

const vars = generateVars(ctx, path, functionParent);
statement.insertBefore(t.expressionStatement(
t.sequenceExpression([
t.callExpression(
getImportIdentifier(ctx, path, SOURCE_MODULE, RUNTIME_IDENTIFIERS.useSolidStyled),
[
sheet.id,
t.numericLiteral(current),
cssID,
],
),
...(
variables.length
? [t.callExpression(
vars,
[t.arrowFunctionExpression([], t.objectExpression(variables))],
)]
: []
const computedVars = variables.length
? t.arrowFunctionExpression([], t.objectExpression(variables))
: undefined;
if (isGlobal) {
const args: t.Expression[] = [
sheet.id,
t.numericLiteral(current),
cssID,
];
if (computedVars) {
args.push(computedVars);
}
statement.insertBefore(
t.expressionStatement(
t.callExpression(
getImportIdentifier(ctx, path, SOURCE_MODULE, RUNTIME_IDENTIFIERS.useSolidStyledGlobal),
args,
)
),
]),
));
);
} else {
const setup = t.callExpression(
getImportIdentifier(ctx, path, SOURCE_MODULE, RUNTIME_IDENTIFIERS.useSolidStyled),
[
sheet.id,
t.numericLiteral(current),
cssID,
],
);
statement.insertBefore(t.expressionStatement(
computedVars
? t.sequenceExpression([setup, t.callExpression(
generateVars(ctx, path, functionParent),
[computedVars],
)])
: setup,
));
}

transformJSX(ctx, functionParent);
}
Expand Down
44 changes: 36 additions & 8 deletions packages/solid-styled/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import type { JSX } from 'solid-js';
import {
createComponent,
createContext,
createEffect,
createMemo,
createRoot,
onCleanup,
untrack,
useContext,
} from 'solid-js';
import { isServer } from 'solid-js/web';
Expand Down Expand Up @@ -107,6 +109,40 @@ export function useSolidStyled(
});
}

function serializeStyle(source: JSX.CSSProperties): string {
let result = '';
for (const key in source) {
result = `${result}${key}:${String(source[key as keyof JSX.CSSProperties])};`;
}
return result;
}

function serializeRootStyle(vars?: () => Record<string, string>): string {
return vars ? ':root{' + serializeStyle(untrack(vars)) + '}' : '';
}

export function useSolidStyledGlobal(
id: string,
offset: string,
sheet: string,
vars?: () => Record<string, string>,
): void {
const index = `${id}-${offset}`;
const ctx = useContext(StyleRegistryContext) ?? { insert, remove };
ctx.insert(index, serializeRootStyle(vars) + sheet);
createEffect(() => {
if (vars) {
const current = vars();
for (const key in current) {
document.documentElement.style.setProperty(key, current[key]);
}
}
});
onCleanup(() => {
ctx.remove(index);
});
}

type CSSVarsMerge = () => Record<string, string>;

interface CSSVars {
Expand Down Expand Up @@ -151,14 +187,6 @@ export function createCSSVars(): CSSVars {
};
}

function serializeStyle(source: JSX.CSSProperties): string {
let result = '';
for (const key of Object.keys(source)) {
result = `${result}${key}:${String(source[key as keyof JSX.CSSProperties])};`;
}
return result;
}

export function mergeStyles(
source: JSX.CSSProperties | string | null | undefined,
other: JSX.CSSProperties,
Expand Down
59 changes: 50 additions & 9 deletions packages/solid-styled/test/__snapshots__/jsx.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@

exports[`jsx > should transform 1`] = `
"import { useSolidStyled as _useSolidStyled } from \\"solid-styled\\";
import { createCSSVars as _createCSSVars } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1[s\\\\\\\\:c-f0b3b6fa-0]{color:red}\\";
export default function Example() {
const _vars = _createCSSVars();
_useSolidStyled(_sheet, 1, _css);
return <>
<h1 s:c-f0b3b6fa-0 style={_vars()}>Hello World</h1>
<h1 s:c-f0b3b6fa-0>Hello World</h1>
</>;
}"
`;
exports[`jsx > should transform dynamic templates 1`] = `
"import { useSolidStyled as _useSolidStyled } from \\"solid-styled\\";
import { createCSSVars as _createCSSVars } from \\"solid-styled\\";
"import { createCSSVars as _createCSSVars } from \\"solid-styled\\";
import { useSolidStyled as _useSolidStyled } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1[s\\\\\\\\:c-f0b3b6fa-0]{color:var(--s-v-f0b3b6fa-1)}\\";
export default function Example() {
Expand All @@ -34,19 +32,62 @@ export default function Example() {
exports[`jsx > should work with multiple templates 1`] = `
"import { useSolidStyled as _useSolidStyled } from \\"solid-styled\\";
import { createCSSVars as _createCSSVars } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1[s\\\\\\\\:c-f0b3b6fa-0]{color:red}\\";
const _css2 = \\"h2[s\\\\\\\\:c-f0b3b6fa-0]{color:#00f}\\";
export default function Example() {
const _vars = _createCSSVars();
_useSolidStyled(_sheet, 1, _css);
_useSolidStyled(_sheet, 2, _css2);
return <>
<h1 s:c-f0b3b6fa-0 style={_vars()}>Hello World</h1>
<h1 s:c-f0b3b6fa-0>Hello World</h1>
<h2 s:c-f0b3b6fa-0>Hello World</h2>
</>;
}"
`;
exports[`jsx.global > should transform 1`] = `
"import { useSolidStyledGlobal as _useSolidStyledGlobal } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1{color:red}\\";
export default function Example() {
_useSolidStyledGlobal(_sheet, 1, _css);
return <>
<h1 s:c-f0b3b6fa-0>Hello World</h1>
</>;
}"
`;
exports[`jsx.global > should transform dynamic templates 1`] = `
"import { useSolidStyledGlobal as _useSolidStyledGlobal } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1{color:var(--s-v-f0b3b6fa-1)}\\";
export default function Example() {
_useSolidStyledGlobal(_sheet, 1, _css, () => ({
\\"--s-v-f0b3b6fa-1\\": props.color
}));
return <>
<h1 s:c-f0b3b6fa-0>Hello World</h1>
</>;
}"
`;
exports[`jsx.global > should work with multiple templates 1`] = `
"import { useSolidStyledGlobal as _useSolidStyledGlobal } from \\"solid-styled\\";
const _sheet = \\"c-f0b3b6fa-0\\";
const _css = \\"h1{color:red}\\";
const _css2 = \\"h2{color:#00f}\\";
export default function Example() {
_useSolidStyledGlobal(_sheet, 1, _css);
_useSolidStyledGlobal(_sheet, 2, _css2);
return <>
<h1 s:c-f0b3b6fa-0>Hello World</h1>
<h2 s:c-f0b3b6fa-0 style={_vars()}>Hello World</h2>
<h2 s:c-f0b3b6fa-0>Hello World</h2>
</>;
}"
`;
67 changes: 67 additions & 0 deletions packages/solid-styled/test/jsx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,70 @@ export default function Example() {
expect((await compile(FILE, code, options)).code).toMatchSnapshot();
});
});
describe('jsx.global', () => {
it('should transform', async () => {
const code = `
export default function Example() {
return (
<>
<style jsx global>
{\`
h1 {
color: red;
}
\`}
</style>
<h1>Hello World</h1>
</>
);
}
`;
expect((await compile(FILE, code, options)).code).toMatchSnapshot();
});
it('should work with multiple templates', async () => {
const code = `
export default function Example() {
return (
<>
<style jsx global>
{\`
h1 {
color: red;
}
\`}
</style>
<h1>Hello World</h1>
<style jsx global>
{\`
h2 {
color: blue;
}
\`}
</style>
<h2>Hello World</h2>
</>
);
}
`;
expect((await compile(FILE, code, options)).code).toMatchSnapshot();
});
it('should transform dynamic templates', async () => {
const code = `
export default function Example() {
return (
<>
<style jsx global>
{\`
h1 {
color: \${props.color};
}
\`}
</style>
<h1>Hello World</h1>
</>
);
}
`;
expect((await compile(FILE, code, options)).code).toMatchSnapshot();
});
});

0 comments on commit decad97

Please sign in to comment.