@pyreon/styler 0.11.5 → 0.11.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -23
- package/lib/index.d.ts +9 -2
- package/lib/index.js +47 -4
- package/package.json +22 -22
- package/src/ThemeProvider.ts +10 -3
- package/src/__tests__/ThemeProvider.test.ts +21 -21
- package/src/__tests__/benchmark.bench.ts +56 -45
- package/src/__tests__/composition-chain.test.ts +200 -151
- package/src/__tests__/forward.test.ts +122 -122
- package/src/__tests__/globalStyle.test.ts +18 -18
- package/src/__tests__/hash.test.ts +27 -27
- package/src/__tests__/hybrid-injection.test.ts +83 -59
- package/src/__tests__/index.ts +10 -10
- package/src/__tests__/insertion-effect.test.ts +45 -32
- package/src/__tests__/integration.test.ts +81 -51
- package/src/__tests__/keyframes.test.ts +13 -13
- package/src/__tests__/memory-growth.test.ts +21 -21
- package/src/__tests__/p3-features.test.ts +162 -104
- package/src/__tests__/shared.test.ts +51 -33
- package/src/__tests__/sheet-advanced.test.ts +227 -227
- package/src/__tests__/sheet-split-atrules.test.ts +85 -85
- package/src/__tests__/sheet.test.ts +69 -69
- package/src/__tests__/styled-ssr.test.ts +36 -28
- package/src/__tests__/styled.test.ts +214 -145
- package/src/__tests__/theme.test.ts +11 -11
- package/src/__tests__/useCSS.test.ts +89 -59
- package/src/css.ts +1 -1
- package/src/forward.ts +187 -187
- package/src/globalStyle.ts +5 -5
- package/src/index.ts +15 -15
- package/src/keyframes.ts +3 -3
- package/src/resolve.ts +14 -14
- package/src/shared.ts +2 -2
- package/src/sheet.ts +26 -26
- package/src/styled.tsx +145 -100
- package/src/useCSS.ts +4 -4
package/README.md
CHANGED
|
@@ -71,7 +71,9 @@ const Text = styled('p')`
|
|
|
71
71
|
Render as a different element at runtime:
|
|
72
72
|
|
|
73
73
|
```ts
|
|
74
|
-
const Box = styled('div')`
|
|
74
|
+
const Box = styled('div')`
|
|
75
|
+
padding: 16px;
|
|
76
|
+
`
|
|
75
77
|
|
|
76
78
|
// Renders as a <section>
|
|
77
79
|
Box({ as: 'section', children: 'Content' })
|
|
@@ -83,7 +85,7 @@ Props prefixed with `$` are not forwarded to the DOM:
|
|
|
83
85
|
|
|
84
86
|
```ts
|
|
85
87
|
const Box = styled('div')`
|
|
86
|
-
color: ${(p) => p.$active ? 'blue' : 'gray'};
|
|
88
|
+
color: ${(p) => (p.$active ? 'blue' : 'gray')};
|
|
87
89
|
`
|
|
88
90
|
|
|
89
91
|
// $active is used for styling but won't appear on the <div>
|
|
@@ -122,10 +124,12 @@ Supports conditional patterns:
|
|
|
122
124
|
```ts
|
|
123
125
|
const Box = styled('div')`
|
|
124
126
|
display: flex;
|
|
125
|
-
${(props) =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
${(props) =>
|
|
128
|
+
props.$bordered &&
|
|
129
|
+
css`
|
|
130
|
+
border: 1px solid #e0e0e0;
|
|
131
|
+
border-radius: 4px;
|
|
132
|
+
`};
|
|
129
133
|
`
|
|
130
134
|
```
|
|
131
135
|
|
|
@@ -253,29 +257,29 @@ const Card = styled('div')`
|
|
|
253
257
|
|
|
254
258
|
### Bundle Size
|
|
255
259
|
|
|
256
|
-
| Library
|
|
257
|
-
|
|
258
|
-
| goober
|
|
259
|
-
| **@pyreon/styler**
|
|
260
|
-
| styled-components
|
|
261
|
-
| @emotion/react + styled |
|
|
260
|
+
| Library | Minified | Gzipped |
|
|
261
|
+
| ----------------------- | -----------: | ----------: |
|
|
262
|
+
| goober | 2.32 KB | 1.31 KB |
|
|
263
|
+
| **@pyreon/styler** | **10.13 KB** | **3.81 KB** |
|
|
264
|
+
| styled-components | 44.93 KB | 17.89 KB |
|
|
265
|
+
| @emotion/react + styled | 48.26 KB | 16.59 KB |
|
|
262
266
|
|
|
263
267
|
### Performance (ops/sec, higher is better)
|
|
264
268
|
|
|
265
|
-
| Benchmark
|
|
266
|
-
|
|
267
|
-
| css() creation
|
|
268
|
-
| css() with interpolations | **24.9M** |
|
|
269
|
-
| Template resolution
|
|
270
|
-
| Nested composition
|
|
271
|
-
| SSR renderToString
|
|
272
|
-
| styled() factory
|
|
269
|
+
| Benchmark | styler | styled-components | @emotion | goober |
|
|
270
|
+
| ------------------------- | --------: | ----------------: | -------: | -----: |
|
|
271
|
+
| css() creation | **25.2M** | 9.0M | 2.2M | 26K |
|
|
272
|
+
| css() with interpolations | **24.9M** | 5.6M | 2.3M | 28K |
|
|
273
|
+
| Template resolution | **21.4M** | 3.9M | — | — |
|
|
274
|
+
| Nested composition | **8.3M** | 2.2M | 1.4M | 8K |
|
|
275
|
+
| SSR renderToString | **307K** | 69K | 192K | 18K |
|
|
276
|
+
| styled() factory | **17.3M** | 109K | 933K | 18.2M |
|
|
273
277
|
|
|
274
278
|
## Peer Dependencies
|
|
275
279
|
|
|
276
|
-
| Package
|
|
277
|
-
|
|
|
278
|
-
| @pyreon/core
|
|
280
|
+
| Package | Version |
|
|
281
|
+
| ------------------ | -------- |
|
|
282
|
+
| @pyreon/core | >= 0.0.1 |
|
|
279
283
|
| @pyreon/reactivity | >= 0.0.1 |
|
|
280
284
|
|
|
281
285
|
## License
|
package/lib/index.d.ts
CHANGED
|
@@ -7,7 +7,14 @@ type Theme = DefaultTheme & Record<string, unknown>;
|
|
|
7
7
|
declare const ThemeContext: _pyreon_core0.Context<Theme>;
|
|
8
8
|
/** Hook to read the current theme from the nearest ThemeProvider. */
|
|
9
9
|
declare const useTheme: <T extends object = Theme>() => T;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.
|
|
12
|
+
*
|
|
13
|
+
* Provides a theme object to all nested styled components via Pyreon context.
|
|
14
|
+
*
|
|
15
|
+
* @deprecated Prefer `<PyreonUI theme={theme}>` which provides theme to
|
|
16
|
+
* all three context layers (styler, core, mode) in one component.
|
|
17
|
+
*/
|
|
11
18
|
declare function ThemeProvider({
|
|
12
19
|
theme,
|
|
13
20
|
children
|
|
@@ -201,7 +208,7 @@ interface StyledOptions {
|
|
|
201
208
|
boost?: boolean;
|
|
202
209
|
}
|
|
203
210
|
type TagTemplateFn = (strings: TemplateStringsArray, ...values: Interpolation[]) => ComponentFn;
|
|
204
|
-
type HtmlTags =
|
|
211
|
+
type HtmlTags = 'a' | 'abbr' | 'address' | 'article' | 'aside' | 'audio' | 'b' | 'blockquote' | 'body' | 'br' | 'button' | 'canvas' | 'caption' | 'code' | 'col' | 'colgroup' | 'dd' | 'details' | 'div' | 'dl' | 'dt' | 'em' | 'fieldset' | 'figcaption' | 'figure' | 'footer' | 'form' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'head' | 'header' | 'hr' | 'html' | 'i' | 'iframe' | 'img' | 'input' | 'label' | 'legend' | 'li' | 'link' | 'main' | 'mark' | 'menu' | 'meta' | 'nav' | 'ol' | 'optgroup' | 'option' | 'output' | 'p' | 'picture' | 'pre' | 'progress' | 'q' | 'section' | 'select' | 'small' | 'source' | 'span' | 'strong' | 'style' | 'sub' | 'summary' | 'sup' | 'svg' | 'table' | 'tbody' | 'td' | 'template' | 'textarea' | 'tfoot' | 'th' | 'thead' | 'time' | 'tr' | 'u' | 'ul' | 'video';
|
|
205
212
|
type StyledFunction = ((tag: Tag, options?: StyledOptions) => TagTemplateFn) & { [K in HtmlTags]: TagTemplateFn };
|
|
206
213
|
declare const styled: StyledFunction;
|
|
207
214
|
//#endregion
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createContext, h, provide, useContext } from "@pyreon/core";
|
|
2
|
+
import { effect } from "@pyreon/reactivity";
|
|
2
3
|
|
|
3
4
|
//#region src/resolve.ts
|
|
4
5
|
/**
|
|
@@ -689,7 +690,14 @@ const createSheet = (options) => new StyleSheet(options);
|
|
|
689
690
|
const ThemeContext = createContext({});
|
|
690
691
|
/** Hook to read the current theme from the nearest ThemeProvider. */
|
|
691
692
|
const useTheme = () => useContext(ThemeContext);
|
|
692
|
-
/**
|
|
693
|
+
/**
|
|
694
|
+
* @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.
|
|
695
|
+
*
|
|
696
|
+
* Provides a theme object to all nested styled components via Pyreon context.
|
|
697
|
+
*
|
|
698
|
+
* @deprecated Prefer `<PyreonUI theme={theme}>` which provides theme to
|
|
699
|
+
* all three context layers (styler, core, mode) in one component.
|
|
700
|
+
*/
|
|
693
701
|
function ThemeProvider({ theme, children }) {
|
|
694
702
|
provide(ThemeContext, theme);
|
|
695
703
|
return children ?? null;
|
|
@@ -790,13 +798,48 @@ const createStyledComponent = (tag, strings, values, options) => {
|
|
|
790
798
|
}
|
|
791
799
|
const DynamicStyled = (rawProps) => {
|
|
792
800
|
const theme = useTheme();
|
|
801
|
+
const $rs = rawProps.$rocketstyle;
|
|
802
|
+
const isReactiveRS = typeof $rs === "function";
|
|
803
|
+
const resolvedRS = isReactiveRS ? $rs() : $rs;
|
|
793
804
|
const cssText = normalizeCSS(resolve(strings, values, {
|
|
794
|
-
...
|
|
805
|
+
...isReactiveRS ? {
|
|
806
|
+
...rawProps,
|
|
807
|
+
$rocketstyle: resolvedRS
|
|
808
|
+
} : rawProps,
|
|
795
809
|
theme
|
|
796
810
|
}));
|
|
797
|
-
const
|
|
811
|
+
const initialClassName = cssText.length > 0 ? sheet.insert(cssText, boost) : "";
|
|
798
812
|
const finalTag = rawProps.as || tag;
|
|
799
|
-
|
|
813
|
+
const isDOM = typeof finalTag === "string";
|
|
814
|
+
let el = null;
|
|
815
|
+
let currentClassName = initialClassName;
|
|
816
|
+
const originalRef = rawProps.ref;
|
|
817
|
+
const refCallback = (node) => {
|
|
818
|
+
el = node;
|
|
819
|
+
if (originalRef) {
|
|
820
|
+
if (typeof originalRef === "function") originalRef(node);
|
|
821
|
+
else if (originalRef && typeof originalRef === "object") originalRef.current = node;
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
const finalProps = buildProps({
|
|
825
|
+
...rawProps,
|
|
826
|
+
ref: isReactiveRS ? refCallback : rawProps.ref
|
|
827
|
+
}, initialClassName, isDOM, customFilter);
|
|
828
|
+
if (isReactiveRS) effect(() => {
|
|
829
|
+
const newRS = $rs();
|
|
830
|
+
const newCss = normalizeCSS(resolve(strings, values, {
|
|
831
|
+
...rawProps,
|
|
832
|
+
$rocketstyle: newRS,
|
|
833
|
+
theme
|
|
834
|
+
}));
|
|
835
|
+
const newClass = newCss.length > 0 ? sheet.insert(newCss, boost) : "";
|
|
836
|
+
if (el && newClass !== currentClassName) {
|
|
837
|
+
if (currentClassName) el.classList.remove(currentClassName);
|
|
838
|
+
if (newClass) el.classList.add(newClass);
|
|
839
|
+
currentClassName = newClass;
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
return h(finalTag, finalProps, ...Array.isArray(rawProps.children) ? rawProps.children : rawProps.children != null ? [rawProps.children] : []);
|
|
800
843
|
};
|
|
801
844
|
DynamicStyled.displayName = `styled(${getDisplayName(tag)})`;
|
|
802
845
|
return DynamicStyled;
|
package/package.json
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/styler",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.6",
|
|
4
|
+
"description": "Lightweight CSS-in-JS engine for Pyreon",
|
|
5
|
+
"license": "MIT",
|
|
4
6
|
"repository": {
|
|
5
7
|
"type": "git",
|
|
6
8
|
"url": "https://github.com/pyreon/pyreon",
|
|
7
9
|
"directory": "packages/ui-system/styler"
|
|
8
10
|
},
|
|
9
|
-
"description": "Lightweight CSS-in-JS engine for Pyreon",
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"type": "module",
|
|
12
|
-
"sideEffects": false,
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"bun": "./src/index.ts",
|
|
16
|
-
"import": "./lib/index.js",
|
|
17
|
-
"types": "./lib/index.d.ts"
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
"types": "./lib/index.d.ts",
|
|
21
|
-
"main": "./lib/index.js",
|
|
22
11
|
"files": [
|
|
23
12
|
"lib",
|
|
24
13
|
"!lib/**/*.map",
|
|
@@ -27,8 +16,16 @@
|
|
|
27
16
|
"LICENSE",
|
|
28
17
|
"src"
|
|
29
18
|
],
|
|
30
|
-
"
|
|
31
|
-
|
|
19
|
+
"type": "module",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"main": "./lib/index.js",
|
|
22
|
+
"types": "./lib/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"bun": "./src/index.ts",
|
|
26
|
+
"import": "./lib/index.js",
|
|
27
|
+
"types": "./lib/index.d.ts"
|
|
28
|
+
}
|
|
32
29
|
},
|
|
33
30
|
"publishConfig": {
|
|
34
31
|
"access": "public"
|
|
@@ -37,18 +34,21 @@
|
|
|
37
34
|
"prepublish": "bun run build",
|
|
38
35
|
"build": "bun run vl_rolldown_build",
|
|
39
36
|
"build:watch": "bun run vl_rolldown_build-watch",
|
|
40
|
-
"lint": "
|
|
37
|
+
"lint": "oxlint .",
|
|
41
38
|
"test": "vitest run",
|
|
42
39
|
"test:coverage": "vitest run --coverage",
|
|
43
40
|
"test:watch": "vitest",
|
|
44
41
|
"typecheck": "tsc --noEmit"
|
|
45
42
|
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@pyreon/typescript": "^0.11.6",
|
|
45
|
+
"@vitus-labs/tools-rolldown": "^1.15.3"
|
|
46
|
+
},
|
|
46
47
|
"peerDependencies": {
|
|
47
|
-
"@pyreon/core": "^0.11.
|
|
48
|
-
"@pyreon/reactivity": "^0.11.
|
|
48
|
+
"@pyreon/core": "^0.11.6",
|
|
49
|
+
"@pyreon/reactivity": "^0.11.6"
|
|
49
50
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"@pyreon/typescript": "^0.11.5"
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">= 22"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/src/ThemeProvider.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* }
|
|
12
12
|
* }
|
|
13
13
|
*/
|
|
14
|
-
import type { VNode, VNodeChild } from
|
|
15
|
-
import { createContext, provide, useContext } from
|
|
14
|
+
import type { VNode, VNodeChild } from '@pyreon/core'
|
|
15
|
+
import { createContext, provide, useContext } from '@pyreon/core'
|
|
16
16
|
|
|
17
17
|
// biome-ignore lint/suspicious/noEmptyInterface: augmentable via module declaration merging
|
|
18
18
|
export interface DefaultTheme {}
|
|
@@ -24,7 +24,14 @@ export const ThemeContext = createContext<Theme>({} as Theme)
|
|
|
24
24
|
/** Hook to read the current theme from the nearest ThemeProvider. */
|
|
25
25
|
export const useTheme = <T extends object = Theme>(): T => useContext(ThemeContext) as T
|
|
26
26
|
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.
|
|
29
|
+
*
|
|
30
|
+
* Provides a theme object to all nested styled components via Pyreon context.
|
|
31
|
+
*
|
|
32
|
+
* @deprecated Prefer `<PyreonUI theme={theme}>` which provides theme to
|
|
33
|
+
* all three context layers (styler, core, mode) in one component.
|
|
34
|
+
*/
|
|
28
35
|
export function ThemeProvider({
|
|
29
36
|
theme,
|
|
30
37
|
children,
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { popContext } from
|
|
2
|
-
import { afterEach, describe, expect, it } from
|
|
3
|
-
import { ThemeContext, ThemeProvider, useTheme } from
|
|
1
|
+
import { popContext } from '@pyreon/core'
|
|
2
|
+
import { afterEach, describe, expect, it } from 'vitest'
|
|
3
|
+
import { ThemeContext, ThemeProvider, useTheme } from '../ThemeProvider'
|
|
4
4
|
|
|
5
|
-
describe(
|
|
6
|
-
it(
|
|
5
|
+
describe('ThemeContext', () => {
|
|
6
|
+
it('is a Context object with an id', () => {
|
|
7
7
|
expect(ThemeContext).toBeDefined()
|
|
8
8
|
expect(ThemeContext.id).toBeDefined()
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
-
it(
|
|
12
|
-
expect(typeof ThemeContext.id).toBe(
|
|
11
|
+
it('has a symbol id for context identification', () => {
|
|
12
|
+
expect(typeof ThemeContext.id).toBe('symbol')
|
|
13
13
|
})
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
describe(
|
|
16
|
+
describe('ThemeProvider', () => {
|
|
17
17
|
afterEach(() => {
|
|
18
18
|
try {
|
|
19
19
|
popContext()
|
|
@@ -22,41 +22,41 @@ describe("ThemeProvider", () => {
|
|
|
22
22
|
}
|
|
23
23
|
})
|
|
24
24
|
|
|
25
|
-
it(
|
|
26
|
-
const children =
|
|
25
|
+
it('returns children when provided', () => {
|
|
26
|
+
const children = 'Hello world'
|
|
27
27
|
const result = ThemeProvider({ theme: {}, children })
|
|
28
|
-
expect(result).toBe(
|
|
28
|
+
expect(result).toBe('Hello world')
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
it(
|
|
31
|
+
it('returns null when no children are provided', () => {
|
|
32
32
|
const result = ThemeProvider({ theme: {} })
|
|
33
33
|
expect(result).toBeNull()
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
it(
|
|
36
|
+
it('returns null when children is undefined', () => {
|
|
37
37
|
const result = ThemeProvider({ theme: {}, children: undefined })
|
|
38
38
|
expect(result).toBeNull()
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
it(
|
|
42
|
-
const theme = { colors: { primary:
|
|
43
|
-
ThemeProvider({ theme, children:
|
|
41
|
+
it('provides theme via context (useTheme returns it)', () => {
|
|
42
|
+
const theme = { colors: { primary: 'red' }, spacing: 8 }
|
|
43
|
+
ThemeProvider({ theme, children: 'child' })
|
|
44
44
|
const result = useTheme()
|
|
45
45
|
expect(result).toEqual(theme)
|
|
46
46
|
})
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
describe(
|
|
50
|
-
it(
|
|
51
|
-
expect(typeof useTheme).toBe(
|
|
49
|
+
describe('useTheme', () => {
|
|
50
|
+
it('is a function', () => {
|
|
51
|
+
expect(typeof useTheme).toBe('function')
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
it(
|
|
54
|
+
it('returns the default theme (empty object) when called outside a provider', () => {
|
|
55
55
|
const theme = useTheme()
|
|
56
56
|
expect(theme).toEqual({})
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
-
it(
|
|
59
|
+
it('can be called with a type parameter', () => {
|
|
60
60
|
interface MyTheme {
|
|
61
61
|
primary: string
|
|
62
62
|
spacing: number
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
* 7. styled() component factory
|
|
14
14
|
* 8. normalizeCSS — Comment Stripping & Cleanup
|
|
15
15
|
*/
|
|
16
|
-
import { bench, describe } from
|
|
17
|
-
import { css } from
|
|
18
|
-
import { hash } from
|
|
19
|
-
import { normalizeCSS, resolve } from
|
|
20
|
-
import { styled } from
|
|
16
|
+
import { bench, describe } from 'vitest'
|
|
17
|
+
import { css } from '../css'
|
|
18
|
+
import { hash } from '../hash'
|
|
19
|
+
import { normalizeCSS, resolve } from '../resolve'
|
|
20
|
+
import { styled } from '../styled'
|
|
21
21
|
|
|
22
22
|
// ============================================================================
|
|
23
23
|
// 1. CSS Tagged Template — Creation Speed
|
|
24
24
|
// ============================================================================
|
|
25
|
-
describe(
|
|
26
|
-
bench(
|
|
25
|
+
describe('css() tagged template creation', () => {
|
|
26
|
+
bench('@pyreon/styler', () => {
|
|
27
27
|
css`
|
|
28
28
|
display: flex;
|
|
29
29
|
align-items: center;
|
|
@@ -32,7 +32,7 @@ describe("css() tagged template creation", () => {
|
|
|
32
32
|
margin: 8px;
|
|
33
33
|
background-color: #f0f0f0;
|
|
34
34
|
border-radius: 4px;
|
|
35
|
-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
35
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
36
36
|
`
|
|
37
37
|
})
|
|
38
38
|
})
|
|
@@ -40,11 +40,11 @@ describe("css() tagged template creation", () => {
|
|
|
40
40
|
// ============================================================================
|
|
41
41
|
// 2. CSS Tagged Template with Interpolations
|
|
42
42
|
// ============================================================================
|
|
43
|
-
describe(
|
|
44
|
-
const color =
|
|
45
|
-
const size =
|
|
43
|
+
describe('css() with interpolations', () => {
|
|
44
|
+
const color = '#ff0000'
|
|
45
|
+
const size = '16px'
|
|
46
46
|
|
|
47
|
-
bench(
|
|
47
|
+
bench('@pyreon/styler', () => {
|
|
48
48
|
css`
|
|
49
49
|
color: ${color};
|
|
50
50
|
font-size: ${size};
|
|
@@ -57,15 +57,15 @@ describe("css() with interpolations", () => {
|
|
|
57
57
|
// ============================================================================
|
|
58
58
|
// 3. Template Resolution (strings + values -> CSS string)
|
|
59
59
|
// ============================================================================
|
|
60
|
-
describe(
|
|
61
|
-
const strings = Object.assign([
|
|
62
|
-
raw: [
|
|
60
|
+
describe('template resolution to CSS string', () => {
|
|
61
|
+
const strings = Object.assign(['display: flex; color: ', '; font-size: ', '; padding: 8px;'], {
|
|
62
|
+
raw: ['display: flex; color: ', '; font-size: ', '; padding: 8px;'],
|
|
63
63
|
}) as unknown as TemplateStringsArray
|
|
64
64
|
|
|
65
|
-
const values = [
|
|
66
|
-
const props = { theme: { primary:
|
|
65
|
+
const values = ['red', '16px']
|
|
66
|
+
const props = { theme: { primary: 'blue' } }
|
|
67
67
|
|
|
68
|
-
bench(
|
|
68
|
+
bench('@pyreon/styler resolve()', () => {
|
|
69
69
|
resolve(strings, values, props)
|
|
70
70
|
})
|
|
71
71
|
})
|
|
@@ -73,20 +73,20 @@ describe("template resolution to CSS string", () => {
|
|
|
73
73
|
// ============================================================================
|
|
74
74
|
// 4. Dynamic Interpolation (function interpolations)
|
|
75
75
|
// ============================================================================
|
|
76
|
-
describe(
|
|
77
|
-
const props = { theme: { primary:
|
|
76
|
+
describe('dynamic function interpolation', () => {
|
|
77
|
+
const props = { theme: { primary: 'blue', size: '14px' }, active: true }
|
|
78
78
|
|
|
79
|
-
const strings = Object.assign([
|
|
80
|
-
raw: [
|
|
79
|
+
const strings = Object.assign(['color: ', '; font-size: ', '; opacity: ', ';'], {
|
|
80
|
+
raw: ['color: ', '; font-size: ', '; opacity: ', ';'],
|
|
81
81
|
}) as unknown as TemplateStringsArray
|
|
82
82
|
|
|
83
83
|
const stylerValues = [
|
|
84
84
|
(p: any) => p.theme.primary,
|
|
85
85
|
(p: any) => p.theme.size,
|
|
86
|
-
(p: any) => (p.active ?
|
|
86
|
+
(p: any) => (p.active ? '1' : '0.5'),
|
|
87
87
|
]
|
|
88
88
|
|
|
89
|
-
bench(
|
|
89
|
+
bench('@pyreon/styler resolve()', () => {
|
|
90
90
|
resolve(strings, stylerValues, props)
|
|
91
91
|
})
|
|
92
92
|
})
|
|
@@ -94,21 +94,21 @@ describe("dynamic function interpolation", () => {
|
|
|
94
94
|
// ============================================================================
|
|
95
95
|
// 5. Hash Function Throughput
|
|
96
96
|
// ============================================================================
|
|
97
|
-
describe(
|
|
98
|
-
const shortCSS =
|
|
97
|
+
describe('hash function throughput', () => {
|
|
98
|
+
const shortCSS = 'display: flex; color: red;'
|
|
99
99
|
const mediumCSS =
|
|
100
|
-
|
|
100
|
+
'display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; margin: 0 auto; max-width: 1200px; background-color: #ffffff; border: 1px solid #e0e0e0; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.12);'
|
|
101
101
|
const longCSS = mediumCSS.repeat(5)
|
|
102
102
|
|
|
103
|
-
bench(
|
|
103
|
+
bench('@pyreon/styler FNV-1a (short)', () => {
|
|
104
104
|
hash(shortCSS)
|
|
105
105
|
})
|
|
106
106
|
|
|
107
|
-
bench(
|
|
107
|
+
bench('@pyreon/styler FNV-1a (medium)', () => {
|
|
108
108
|
hash(mediumCSS)
|
|
109
109
|
})
|
|
110
110
|
|
|
111
|
-
bench(
|
|
111
|
+
bench('@pyreon/styler FNV-1a (long)', () => {
|
|
112
112
|
hash(longCSS)
|
|
113
113
|
})
|
|
114
114
|
})
|
|
@@ -116,13 +116,20 @@ describe("hash function throughput", () => {
|
|
|
116
116
|
// ============================================================================
|
|
117
117
|
// 6. Nested css() Composition
|
|
118
118
|
// ============================================================================
|
|
119
|
-
describe(
|
|
120
|
-
bench(
|
|
121
|
-
const base = css`
|
|
122
|
-
|
|
119
|
+
describe('nested css() composition', () => {
|
|
120
|
+
bench('@pyreon/styler', () => {
|
|
121
|
+
const base = css`
|
|
122
|
+
display: flex;
|
|
123
|
+
padding: 8px;
|
|
124
|
+
`
|
|
125
|
+
const hover = css`
|
|
126
|
+
background: #eee;
|
|
127
|
+
`
|
|
123
128
|
const result = css`
|
|
124
129
|
${base};
|
|
125
|
-
&:hover {
|
|
130
|
+
&:hover {
|
|
131
|
+
${hover};
|
|
132
|
+
}
|
|
126
133
|
color: red;
|
|
127
134
|
`
|
|
128
135
|
result.toString()
|
|
@@ -132,18 +139,22 @@ describe("nested css() composition", () => {
|
|
|
132
139
|
// ============================================================================
|
|
133
140
|
// 7. Styled Component Creation (factory call)
|
|
134
141
|
// ============================================================================
|
|
135
|
-
describe(
|
|
136
|
-
bench(
|
|
137
|
-
styled(
|
|
142
|
+
describe('styled() component factory', () => {
|
|
143
|
+
bench('@pyreon/styler', () => {
|
|
144
|
+
styled('div')`
|
|
145
|
+
display: flex;
|
|
146
|
+
color: red;
|
|
147
|
+
padding: 8px;
|
|
148
|
+
`
|
|
138
149
|
})
|
|
139
150
|
})
|
|
140
151
|
|
|
141
152
|
// ============================================================================
|
|
142
153
|
// 8. normalizeCSS — Comment Stripping & Cleanup
|
|
143
154
|
// ============================================================================
|
|
144
|
-
describe(
|
|
155
|
+
describe('normalizeCSS', () => {
|
|
145
156
|
const plain =
|
|
146
|
-
|
|
157
|
+
' display: flex; align-items: center; justify-content: center; padding: 16px; margin: 8px; background-color: #f0f0f0; border-radius: 4px; '
|
|
147
158
|
|
|
148
159
|
const withBlockComments = `
|
|
149
160
|
/* -------------------------------------------------------- */
|
|
@@ -169,21 +180,21 @@ describe("normalizeCSS", () => {
|
|
|
169
180
|
background: url(https://example.com/img.png);
|
|
170
181
|
`
|
|
171
182
|
|
|
172
|
-
const withSemicolonJunk =
|
|
183
|
+
const withSemicolonJunk = ' ; display: flex;; ; color: red; ; font-size: 1rem;; ; '
|
|
173
184
|
|
|
174
|
-
bench(
|
|
185
|
+
bench('plain CSS (no comments)', () => {
|
|
175
186
|
normalizeCSS(plain)
|
|
176
187
|
})
|
|
177
188
|
|
|
178
|
-
bench(
|
|
189
|
+
bench('CSS with /* */ block comments', () => {
|
|
179
190
|
normalizeCSS(withBlockComments)
|
|
180
191
|
})
|
|
181
192
|
|
|
182
|
-
bench(
|
|
193
|
+
bench('CSS with // line comments', () => {
|
|
183
194
|
normalizeCSS(withLineComments)
|
|
184
195
|
})
|
|
185
196
|
|
|
186
|
-
bench(
|
|
197
|
+
bench('CSS with semicolon junk', () => {
|
|
187
198
|
normalizeCSS(withSemicolonJunk)
|
|
188
199
|
})
|
|
189
200
|
})
|