@tenphi/tasty 0.0.0-snapshot.d2dcdeb → 0.0.0-snapshot.d4ccea8
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 +181 -131
- package/dist/{ssr/async-storage.js → async-storage-DKK-wTD4.js} +2 -2
- package/dist/async-storage-DKK-wTD4.js.map +1 -0
- package/dist/babel-eMs_zZjM.d.ts +83 -0
- package/dist/{ssr/collector.js → collector-BjkQEtbh.js} +111 -38
- package/dist/collector-BjkQEtbh.js.map +1 -0
- package/dist/{ssr/collector.d.ts → collector-DzeNxHOq.d.ts} +58 -7
- package/dist/config-DMslHK_e.d.ts +1298 -0
- package/dist/config-DX126v_w.js +12318 -0
- package/dist/config-DX126v_w.js.map +1 -0
- package/dist/{ssr/context.js → context-CA8YKeMn.js} +11 -3
- package/dist/context-CA8YKeMn.js.map +1 -0
- package/dist/core/index.d.ts +5 -34
- package/dist/core/index.js +6 -27
- package/dist/core-CMn-Tj2X.js +1573 -0
- package/dist/core-CMn-Tj2X.js.map +1 -0
- package/dist/{zero/extractor.js → css-writer-C8ShXK5R.js} +148 -24
- package/dist/css-writer-C8ShXK5R.js.map +1 -0
- package/dist/{ssr/format-global-rules.js → format-global-rules-DklyaXv-.js} +2 -2
- package/dist/format-global-rules-DklyaXv-.js.map +1 -0
- package/dist/{ssr/format-rules.js → format-rules-BkstDvlN.js} +59 -2
- package/dist/format-rules-BkstDvlN.js.map +1 -0
- package/dist/{ssr/hydrate.js → hydrate-DXXWZgm0.js} +4 -12
- package/dist/hydrate-DXXWZgm0.js.map +1 -0
- package/dist/index-BcsaHo8x.d.ts +1568 -0
- package/dist/index-CC0wykKn.d.ts +1909 -0
- package/dist/index.d.ts +5 -51
- package/dist/index.js +922 -36
- package/dist/index.js.map +1 -0
- package/dist/keyframes-Z0YLVOWq.js +493 -0
- package/dist/keyframes-Z0YLVOWq.js.map +1 -0
- package/dist/{utils/merge-styles.d.ts → merge-styles-BTFAkYSD.d.ts} +3 -3
- package/dist/{utils/merge-styles.js → merge-styles-Dpueyn82.js} +3 -4
- package/dist/merge-styles-Dpueyn82.js.map +1 -0
- package/dist/{utils/resolve-recipes.js → resolve-recipes-B2Vjr7ET.js} +4 -6
- package/dist/resolve-recipes-B2Vjr7ET.js.map +1 -0
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro-client.js.map +1 -1
- package/dist/ssr/astro-middleware-static.d.ts +16 -0
- package/dist/ssr/astro-middleware-static.js +18 -0
- package/dist/ssr/astro-middleware-static.js.map +1 -0
- package/dist/ssr/astro-middleware.d.ts +8 -6
- package/dist/ssr/astro-middleware.js +10 -10
- package/dist/ssr/astro-middleware.js.map +1 -1
- package/dist/ssr/astro.d.ts +2 -17
- package/dist/ssr/astro.js +29 -21
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/index.d.ts +37 -4
- package/dist/ssr/index.js +5 -5
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +2 -3
- package/dist/ssr/next.js +7 -8
- package/dist/ssr/next.js.map +1 -1
- package/dist/static/index.d.ts +91 -5
- package/dist/static/index.js +49 -3
- package/dist/static/index.js.map +1 -0
- package/dist/static/inject.js.map +1 -1
- package/dist/zero/babel.d.ts +2 -81
- package/dist/zero/babel.js +45 -29
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +81 -3
- package/dist/zero/index.js +2 -3
- package/dist/zero/next.d.ts +1 -1
- package/dist/zero/next.js +1 -1
- package/dist/zero/next.js.map +1 -1
- package/docs/README.md +18 -10
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +224 -0
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +501 -72
- package/docs/debug.md +22 -18
- package/docs/design-system.md +43 -24
- package/docs/dsl.md +512 -179
- package/docs/getting-started.md +60 -39
- package/docs/injector.md +110 -32
- package/docs/methodology.md +68 -36
- package/docs/migration-v3.md +285 -0
- package/docs/pipeline.md +741 -0
- package/docs/plugins.md +353 -0
- package/docs/react-api.md +164 -40
- package/docs/runtime-benchmarks.md +216 -0
- package/docs/ssr.md +92 -81
- package/docs/styles.md +65 -16
- package/docs/tasty-static.md +149 -99
- package/package.json +49 -21
- package/tasty.config.ts +6 -0
- package/dist/_virtual/_rolldown/runtime.js +0 -7
- package/dist/chunks/cacheKey.d.ts +0 -1
- package/dist/chunks/cacheKey.js +0 -77
- package/dist/chunks/cacheKey.js.map +0 -1
- package/dist/chunks/definitions.d.ts +0 -37
- package/dist/chunks/definitions.js +0 -258
- package/dist/chunks/definitions.js.map +0 -1
- package/dist/chunks/index.d.ts +0 -1
- package/dist/chunks/renderChunk.d.ts +0 -1
- package/dist/chunks/renderChunk.js +0 -59
- package/dist/chunks/renderChunk.js.map +0 -1
- package/dist/compute-styles.d.ts +0 -31
- package/dist/compute-styles.js +0 -335
- package/dist/compute-styles.js.map +0 -1
- package/dist/config.d.ts +0 -407
- package/dist/config.js +0 -587
- package/dist/config.js.map +0 -1
- package/dist/counter-style/index.js +0 -51
- package/dist/counter-style/index.js.map +0 -1
- package/dist/debug.d.ts +0 -89
- package/dist/debug.js +0 -453
- package/dist/debug.js.map +0 -1
- package/dist/font-face/index.js +0 -63
- package/dist/font-face/index.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -7
- package/dist/hooks/useCounterStyle.d.ts +0 -36
- package/dist/hooks/useCounterStyle.js +0 -65
- package/dist/hooks/useCounterStyle.js.map +0 -1
- package/dist/hooks/useFontFace.d.ts +0 -45
- package/dist/hooks/useFontFace.js +0 -66
- package/dist/hooks/useFontFace.js.map +0 -1
- package/dist/hooks/useGlobalStyles.d.ts +0 -46
- package/dist/hooks/useGlobalStyles.js +0 -88
- package/dist/hooks/useGlobalStyles.js.map +0 -1
- package/dist/hooks/useKeyframes.d.ts +0 -58
- package/dist/hooks/useKeyframes.js +0 -55
- package/dist/hooks/useKeyframes.js.map +0 -1
- package/dist/hooks/useProperty.d.ts +0 -81
- package/dist/hooks/useProperty.js +0 -96
- package/dist/hooks/useProperty.js.map +0 -1
- package/dist/hooks/useRawCSS.d.ts +0 -22
- package/dist/hooks/useRawCSS.js +0 -103
- package/dist/hooks/useRawCSS.js.map +0 -1
- package/dist/hooks/useStyles.d.ts +0 -40
- package/dist/hooks/useStyles.js +0 -31
- package/dist/hooks/useStyles.js.map +0 -1
- package/dist/injector/index.d.ts +0 -182
- package/dist/injector/index.js +0 -185
- package/dist/injector/index.js.map +0 -1
- package/dist/injector/injector.d.ts +0 -198
- package/dist/injector/injector.js +0 -651
- package/dist/injector/injector.js.map +0 -1
- package/dist/injector/sheet-manager.d.ts +0 -132
- package/dist/injector/sheet-manager.js +0 -699
- package/dist/injector/sheet-manager.js.map +0 -1
- package/dist/injector/types.d.ts +0 -235
- package/dist/keyframes/index.js +0 -206
- package/dist/keyframes/index.js.map +0 -1
- package/dist/parser/classify.js +0 -319
- package/dist/parser/classify.js.map +0 -1
- package/dist/parser/const.js +0 -60
- package/dist/parser/const.js.map +0 -1
- package/dist/parser/lru.js +0 -109
- package/dist/parser/lru.js.map +0 -1
- package/dist/parser/parser.d.ts +0 -25
- package/dist/parser/parser.js +0 -115
- package/dist/parser/parser.js.map +0 -1
- package/dist/parser/tokenizer.js +0 -69
- package/dist/parser/tokenizer.js.map +0 -1
- package/dist/parser/types.d.ts +0 -51
- package/dist/parser/types.js +0 -46
- package/dist/parser/types.js.map +0 -1
- package/dist/pipeline/conditions.d.ts +0 -134
- package/dist/pipeline/conditions.js +0 -406
- package/dist/pipeline/conditions.js.map +0 -1
- package/dist/pipeline/exclusive.js +0 -230
- package/dist/pipeline/exclusive.js.map +0 -1
- package/dist/pipeline/index.d.ts +0 -55
- package/dist/pipeline/index.js +0 -708
- package/dist/pipeline/index.js.map +0 -1
- package/dist/pipeline/materialize.js +0 -1103
- package/dist/pipeline/materialize.js.map +0 -1
- package/dist/pipeline/parseStateKey.d.ts +0 -15
- package/dist/pipeline/parseStateKey.js +0 -446
- package/dist/pipeline/parseStateKey.js.map +0 -1
- package/dist/pipeline/simplify.js +0 -515
- package/dist/pipeline/simplify.js.map +0 -1
- package/dist/pipeline/warnings.js +0 -18
- package/dist/pipeline/warnings.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -2
- package/dist/plugins/okhsl-plugin.d.ts +0 -35
- package/dist/plugins/okhsl-plugin.js +0 -97
- package/dist/plugins/okhsl-plugin.js.map +0 -1
- package/dist/plugins/types.d.ts +0 -87
- package/dist/properties/index.js +0 -222
- package/dist/properties/index.js.map +0 -1
- package/dist/properties/property-type-resolver.d.ts +0 -24
- package/dist/properties/property-type-resolver.js +0 -90
- package/dist/properties/property-type-resolver.js.map +0 -1
- package/dist/rsc-cache.js +0 -79
- package/dist/rsc-cache.js.map +0 -1
- package/dist/ssr/async-storage.d.ts +0 -17
- package/dist/ssr/async-storage.js.map +0 -1
- package/dist/ssr/collect-auto-properties.js +0 -58
- package/dist/ssr/collect-auto-properties.js.map +0 -1
- package/dist/ssr/collector.js.map +0 -1
- package/dist/ssr/context.js.map +0 -1
- package/dist/ssr/format-global-rules.js.map +0 -1
- package/dist/ssr/format-keyframes.js +0 -69
- package/dist/ssr/format-keyframes.js.map +0 -1
- package/dist/ssr/format-property.js +0 -49
- package/dist/ssr/format-property.js.map +0 -1
- package/dist/ssr/format-rules.js.map +0 -1
- package/dist/ssr/hydrate.d.ts +0 -29
- package/dist/ssr/hydrate.js.map +0 -1
- package/dist/ssr/ssr-collector-ref.js +0 -29
- package/dist/ssr/ssr-collector-ref.js.map +0 -1
- package/dist/states/index.d.ts +0 -49
- package/dist/states/index.js +0 -170
- package/dist/states/index.js.map +0 -1
- package/dist/static/tastyStatic.d.ts +0 -46
- package/dist/static/tastyStatic.js +0 -30
- package/dist/static/tastyStatic.js.map +0 -1
- package/dist/static/types.d.ts +0 -49
- package/dist/static/types.js +0 -24
- package/dist/static/types.js.map +0 -1
- package/dist/styles/border.d.ts +0 -25
- package/dist/styles/border.js +0 -120
- package/dist/styles/border.js.map +0 -1
- package/dist/styles/color.d.ts +0 -14
- package/dist/styles/color.js +0 -26
- package/dist/styles/color.js.map +0 -1
- package/dist/styles/const.js +0 -17
- package/dist/styles/const.js.map +0 -1
- package/dist/styles/createStyle.js +0 -79
- package/dist/styles/createStyle.js.map +0 -1
- package/dist/styles/dimension.js +0 -109
- package/dist/styles/dimension.js.map +0 -1
- package/dist/styles/directional.js +0 -133
- package/dist/styles/directional.js.map +0 -1
- package/dist/styles/display.d.ts +0 -30
- package/dist/styles/display.js +0 -73
- package/dist/styles/display.js.map +0 -1
- package/dist/styles/fade.d.ts +0 -15
- package/dist/styles/fade.js +0 -62
- package/dist/styles/fade.js.map +0 -1
- package/dist/styles/fill.d.ts +0 -42
- package/dist/styles/fill.js +0 -51
- package/dist/styles/fill.js.map +0 -1
- package/dist/styles/flow.d.ts +0 -16
- package/dist/styles/flow.js +0 -12
- package/dist/styles/flow.js.map +0 -1
- package/dist/styles/gap.d.ts +0 -31
- package/dist/styles/gap.js +0 -38
- package/dist/styles/gap.js.map +0 -1
- package/dist/styles/height.d.ts +0 -17
- package/dist/styles/height.js +0 -19
- package/dist/styles/height.js.map +0 -1
- package/dist/styles/index.d.ts +0 -1
- package/dist/styles/index.js +0 -8
- package/dist/styles/index.js.map +0 -1
- package/dist/styles/inset.d.ts +0 -24
- package/dist/styles/inset.js +0 -34
- package/dist/styles/inset.js.map +0 -1
- package/dist/styles/list.d.ts +0 -16
- package/dist/styles/list.js +0 -100
- package/dist/styles/list.js.map +0 -1
- package/dist/styles/margin.d.ts +0 -24
- package/dist/styles/margin.js +0 -32
- package/dist/styles/margin.js.map +0 -1
- package/dist/styles/outline.d.ts +0 -29
- package/dist/styles/outline.js +0 -55
- package/dist/styles/outline.js.map +0 -1
- package/dist/styles/padding.d.ts +0 -24
- package/dist/styles/padding.js +0 -32
- package/dist/styles/padding.js.map +0 -1
- package/dist/styles/placement.d.ts +0 -37
- package/dist/styles/placement.js +0 -74
- package/dist/styles/placement.js.map +0 -1
- package/dist/styles/predefined.d.ts +0 -71
- package/dist/styles/predefined.js +0 -237
- package/dist/styles/predefined.js.map +0 -1
- package/dist/styles/preset.d.ts +0 -52
- package/dist/styles/preset.js +0 -127
- package/dist/styles/preset.js.map +0 -1
- package/dist/styles/radius.d.ts +0 -12
- package/dist/styles/radius.js +0 -83
- package/dist/styles/radius.js.map +0 -1
- package/dist/styles/scrollMargin.d.ts +0 -24
- package/dist/styles/scrollMargin.js +0 -32
- package/dist/styles/scrollMargin.js.map +0 -1
- package/dist/styles/scrollbar.d.ts +0 -25
- package/dist/styles/scrollbar.js +0 -51
- package/dist/styles/scrollbar.js.map +0 -1
- package/dist/styles/shadow.d.ts +0 -14
- package/dist/styles/shadow.js +0 -25
- package/dist/styles/shadow.js.map +0 -1
- package/dist/styles/shared.js +0 -17
- package/dist/styles/shared.js.map +0 -1
- package/dist/styles/transition.d.ts +0 -14
- package/dist/styles/transition.js +0 -159
- package/dist/styles/transition.js.map +0 -1
- package/dist/styles/types.d.ts +0 -564
- package/dist/styles/width.d.ts +0 -17
- package/dist/styles/width.js +0 -19
- package/dist/styles/width.js.map +0 -1
- package/dist/tasty.d.ts +0 -134
- package/dist/tasty.js +0 -248
- package/dist/tasty.js.map +0 -1
- package/dist/types.d.ts +0 -184
- package/dist/utils/cache-wrapper.js +0 -21
- package/dist/utils/cache-wrapper.js.map +0 -1
- package/dist/utils/case-converter.js +0 -8
- package/dist/utils/case-converter.js.map +0 -1
- package/dist/utils/color-math.d.ts +0 -46
- package/dist/utils/color-math.js +0 -749
- package/dist/utils/color-math.js.map +0 -1
- package/dist/utils/color-space.d.ts +0 -5
- package/dist/utils/color-space.js +0 -228
- package/dist/utils/color-space.js.map +0 -1
- package/dist/utils/colors.d.ts +0 -5
- package/dist/utils/colors.js +0 -10
- package/dist/utils/colors.js.map +0 -1
- package/dist/utils/css-types.d.ts +0 -7
- package/dist/utils/deps-equal.js +0 -15
- package/dist/utils/deps-equal.js.map +0 -1
- package/dist/utils/dotize.d.ts +0 -26
- package/dist/utils/dotize.js +0 -122
- package/dist/utils/dotize.js.map +0 -1
- package/dist/utils/filter-base-props.d.ts +0 -15
- package/dist/utils/filter-base-props.js +0 -45
- package/dist/utils/filter-base-props.js.map +0 -1
- package/dist/utils/get-display-name.d.ts +0 -7
- package/dist/utils/get-display-name.js +0 -10
- package/dist/utils/get-display-name.js.map +0 -1
- package/dist/utils/has-keys.js +0 -13
- package/dist/utils/has-keys.js.map +0 -1
- package/dist/utils/hash.js +0 -14
- package/dist/utils/hash.js.map +0 -1
- package/dist/utils/is-dev-env.js +0 -19
- package/dist/utils/is-dev-env.js.map +0 -1
- package/dist/utils/is-valid-element-type.js +0 -15
- package/dist/utils/is-valid-element-type.js.map +0 -1
- package/dist/utils/merge-styles.js.map +0 -1
- package/dist/utils/mod-attrs.d.ts +0 -6
- package/dist/utils/mod-attrs.js +0 -20
- package/dist/utils/mod-attrs.js.map +0 -1
- package/dist/utils/process-tokens.d.ts +0 -17
- package/dist/utils/process-tokens.js +0 -83
- package/dist/utils/process-tokens.js.map +0 -1
- package/dist/utils/resolve-recipes.d.ts +0 -17
- package/dist/utils/resolve-recipes.js.map +0 -1
- package/dist/utils/selector-transform.js +0 -32
- package/dist/utils/selector-transform.js.map +0 -1
- package/dist/utils/string.js +0 -8
- package/dist/utils/string.js.map +0 -1
- package/dist/utils/styles.d.ts +0 -99
- package/dist/utils/styles.js +0 -220
- package/dist/utils/styles.js.map +0 -1
- package/dist/utils/typography.d.ts +0 -58
- package/dist/utils/typography.js +0 -51
- package/dist/utils/typography.js.map +0 -1
- package/dist/utils/warnings.d.ts +0 -16
- package/dist/utils/warnings.js +0 -16
- package/dist/utils/warnings.js.map +0 -1
- package/dist/zero/css-writer.d.ts +0 -45
- package/dist/zero/css-writer.js +0 -73
- package/dist/zero/css-writer.js.map +0 -1
- package/dist/zero/extractor.d.ts +0 -24
- package/dist/zero/extractor.js.map +0 -1
- package/docs/PIPELINE.md +0 -519
package/docs/getting-started.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Getting Started
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build one stateful component first. You will see how Tasty expresses priority as a state map, why overlapping states do not compete, and where shared design-system configuration fits afterward.
|
|
4
|
+
|
|
5
|
+
This is the right starting point when you are ready to try Tasty in code. If you are still evaluating it, read the [Introduction](../README.md), [Comparison](comparison.md), and [Adoption Guide](adoption.md).
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
@@ -10,7 +12,7 @@ This guide walks you from zero to a working Tasty component, then through the op
|
|
|
10
12
|
- **React** >= 18 (peer dependency)
|
|
11
13
|
- **Package manager**: pnpm, npm, or yarn
|
|
12
14
|
|
|
13
|
-
Tasty
|
|
15
|
+
No Tasty configuration is required for the first component.
|
|
14
16
|
|
|
15
17
|
---
|
|
16
18
|
|
|
@@ -22,36 +24,57 @@ pnpm add @tenphi/tasty
|
|
|
22
24
|
|
|
23
25
|
---
|
|
24
26
|
|
|
25
|
-
##
|
|
27
|
+
## Build a button whose states don’t fight
|
|
26
28
|
|
|
27
29
|
```tsx
|
|
28
30
|
import { tasty } from '@tenphi/tasty';
|
|
29
31
|
|
|
30
|
-
const
|
|
31
|
-
as: '
|
|
32
|
+
const Button = tasty({
|
|
33
|
+
as: 'button',
|
|
32
34
|
styles: {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
padding: '12px 20px',
|
|
36
|
+
radius: '8px',
|
|
37
|
+
border: '0',
|
|
38
|
+
fill: {
|
|
39
|
+
'': 'royalblue',
|
|
40
|
+
':hover': 'blue',
|
|
41
|
+
':active': 'navy',
|
|
42
|
+
disabled: 'lightgray',
|
|
43
|
+
},
|
|
44
|
+
color: {
|
|
45
|
+
'': 'white',
|
|
46
|
+
disabled: 'dimgray',
|
|
47
|
+
},
|
|
48
|
+
cursor: {
|
|
49
|
+
'': 'pointer',
|
|
50
|
+
disabled: 'not-allowed',
|
|
51
|
+
},
|
|
40
52
|
},
|
|
41
53
|
});
|
|
42
54
|
|
|
43
55
|
export default function App() {
|
|
44
|
-
return
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<Button>Save changes</Button>
|
|
59
|
+
<Button disabled>Disabled</Button>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
45
62
|
}
|
|
46
63
|
```
|
|
47
64
|
|
|
48
|
-
`tasty()` returns a normal React component.
|
|
65
|
+
`tasty()` returns a normal React component. The keys in each state map define priority: later branches win over earlier ones. Because `disabled` is last, a disabled button keeps its disabled styles even while the pointer is over it.
|
|
66
|
+
|
|
67
|
+
`disabled` and `checked` are built-in automatic states. Tasty activates them from the corresponding native prop or attribute, so `disabled` is the concise Tasty form of `[disabled]`, and `checked` is the concise form of `[checked]`.
|
|
68
|
+
|
|
69
|
+
Tasty compiles that priority into selectors that exclude one another. The hover, active, and disabled background rules cannot all match and ask the CSS cascade to decide the winner.
|
|
70
|
+
|
|
71
|
+
The example uses ordinary CSS values so it works without setup. A design system will usually replace them with shared tokens, units, and state aliases in the next step. See the [Style DSL](dsl.md) for the complete state-map syntax and [Style Properties](styles.md) for Tasty’s enhanced CSS properties.
|
|
49
72
|
|
|
50
73
|
---
|
|
51
74
|
|
|
52
|
-
##
|
|
75
|
+
## Add your design system’s language
|
|
53
76
|
|
|
54
|
-
Use `configure()` once, before your app renders, when your app or design system
|
|
77
|
+
The first component needs no configuration. Use `configure()` once, before your app renders, when your app or design system is ready to share tokens, state aliases, recipes, units, or parser extensions:
|
|
55
78
|
|
|
56
79
|
```tsx
|
|
57
80
|
// src/tasty-config.ts
|
|
@@ -91,8 +114,8 @@ configure({
|
|
|
91
114
|
'#primary': 'oklch(55% 0.25 265)',
|
|
92
115
|
'#surface': '#fff',
|
|
93
116
|
'#text': '#111',
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
$gap: '8px',
|
|
118
|
+
$radius: '4px',
|
|
96
119
|
'$border-width': '1px',
|
|
97
120
|
'$outline-width': '2px',
|
|
98
121
|
},
|
|
@@ -148,23 +171,21 @@ export default [
|
|
|
148
171
|
|
|
149
172
|
The `recommended` config enables 18 of the plugin's 27 total rules. It covers the most common issues without turning on the stricter governance rules:
|
|
150
173
|
|
|
151
|
-
| Category
|
|
152
|
-
|
|
153
|
-
| Property validation | `known-property`, `valid-boolean-property`, `valid-sub-element`
|
|
154
|
-
| Value validation
|
|
155
|
-
| State validation
|
|
156
|
-
| Structure
|
|
157
|
-
| Static mode
|
|
158
|
-
| Style properties
|
|
174
|
+
| Category | Rules | Examples |
|
|
175
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ |
|
|
176
|
+
| Property validation | `known-property`, `valid-boolean-property`, `valid-sub-element` | Flags typos like `pading` or invalid boolean usage |
|
|
177
|
+
| Value validation | `valid-value`, `valid-color-token`, `valid-custom-unit` | Catches `#nonexistent` tokens, bad unit syntax |
|
|
178
|
+
| State validation | `valid-state-key`, `no-nested-state-map`, `require-default-state` | Validates state key syntax, ensures `''` default exists |
|
|
179
|
+
| Structure | `valid-styles-structure`, `no-important`, `no-nested-selector` | Prevents `!important`, invalid nesting |
|
|
180
|
+
| Static mode | `static-no-dynamic-values`, `static-valid-selector` | Enforces build-time constraints in `tastyStatic()` |
|
|
181
|
+
| Style properties | `valid-preset`, `valid-recipe`, `valid-transition`, `valid-directional-modifier`, `valid-radius-shape` | Validates preset names, recipe references, transition syntax |
|
|
159
182
|
|
|
160
183
|
### Strict config
|
|
161
184
|
|
|
162
185
|
For stricter governance, use `tasty.configs.strict`. It adds rules that enforce best practices like preferring shorthand properties, consistent token usage, and flagging direct `styles` prop usage:
|
|
163
186
|
|
|
164
187
|
```js
|
|
165
|
-
export default [
|
|
166
|
-
tasty.configs.strict,
|
|
167
|
-
];
|
|
188
|
+
export default [tasty.configs.strict];
|
|
168
189
|
```
|
|
169
190
|
|
|
170
191
|
---
|
|
@@ -179,19 +200,19 @@ export default [
|
|
|
179
200
|
|
|
180
201
|
## Choosing a rendering mode
|
|
181
202
|
|
|
182
|
-
`tasty()` is the default for all React apps. All `tasty()` components and style functions are hook-free and work as React Server Components without `'use client'`.
|
|
203
|
+
`tasty()` is the default for all React apps. All `tasty()` components and style functions are hook-free and work as React Server Components without `'use client'`. Zero-runtime delivery is not tied to one API: both server-only `tasty()` and build-time `tastyStatic()` can ship no Tasty styling runtime to the browser.
|
|
183
204
|
|
|
184
|
-
| Approach |
|
|
185
|
-
|
|
186
|
-
| **
|
|
187
|
-
| **
|
|
188
|
-
| **
|
|
205
|
+
| Approach | Authoring API | CSS is generated | Tasty runtime in the browser | Best for |
|
|
206
|
+
| ------------------------- | ------------------------------------------- | ----------------------------------- | ---------------------------- | ---------------------------------------------------------------- |
|
|
207
|
+
| **Server-only React** | `tasty()`; optional `@tenphi/tasty/ssr/*` | During server or static rendering | None | Astro without islands, server-only RSC, SSG |
|
|
208
|
+
| **Hydrated React** | `tasty()` plus `@tenphi/tasty/ssr/*` | During SSR, then on demand in React | Only in hydrated components | Interactive React apps, Next.js client components, Astro islands |
|
|
209
|
+
| **Build-time extraction** | `tastyStatic()` from `@tenphi/tasty/static` | During the build | None in file mode | Non-React frameworks or extraction before rendering |
|
|
189
210
|
|
|
190
211
|
Both `tasty()` and `tastyStatic()` share the same DSL, tokens, units, and state mappings.
|
|
191
212
|
|
|
192
|
-
- **
|
|
193
|
-
- **
|
|
194
|
-
- **
|
|
213
|
+
- **Server-only `tasty()`** keeps the full feature set (`styleProps`, sub-elements, variants) while generating CSS during server rendering. `tasty()` plus `tastyIntegration({ islands: false })` in Astro is the verified concrete setup and ships no client JavaScript. The same server-only architecture applies to Next.js RSC; verify the generated output for your deployment.
|
|
214
|
+
- **Hydrated `tasty()`** uses the SSR integrations to batch and deduplicate server CSS, prevent FOUC, and hydrate the client cache. The browser styling pipeline is available only where React components hydrate. See [Server-Side Rendering](ssr.md).
|
|
215
|
+
- **Build-time extraction** uses the Babel plugin and additional peer dependencies. Choose `tastyStatic()` when CSS must be generated before rendering or when the consumer is not React. File mode ships no styling runtime; inject mode intentionally includes a tiny CSS injector. See [Build-Time Extraction (`tastyStatic`)](tasty-static.md).
|
|
195
216
|
|
|
196
217
|
---
|
|
197
218
|
|
|
@@ -214,4 +235,4 @@ Both `tasty()` and `tastyStatic()` share the same DSL, tokens, units, and state
|
|
|
214
235
|
|
|
215
236
|
- Styles are missing on first render: make sure the file that calls `configure()` is imported before any `tasty()` component renders.
|
|
216
237
|
- Token or unit values are not what you expect: check your `configure({ tokens, units })` setup, then inspect the generated CSS variables with [Debug Utilities](debug.md).
|
|
217
|
-
- You need
|
|
238
|
+
- You need zero-runtime delivery: use server-only [`tasty()` with server rendering](ssr.md) to keep the full React API, or use [`tastyStatic()` build-time extraction](tasty-static.md) when styles must be compiled before rendering.
|
package/docs/injector.md
CHANGED
|
@@ -9,9 +9,9 @@ A high-performance CSS-in-JS solution that powers the Tasty design system with e
|
|
|
9
9
|
The Style Injector is the core engine behind Tasty's styling system, providing:
|
|
10
10
|
|
|
11
11
|
- **Hash-based deduplication** - Identical CSS gets the same className
|
|
12
|
-
- **
|
|
12
|
+
- **DOM-driven lifetime** - Styles are collected once nothing renders them
|
|
13
13
|
- **CSS nesting flattening** - Handles `&`, `.Class`, `SubElement` patterns
|
|
14
|
-
- **
|
|
14
|
+
- **At-rule injection** - First-class `@keyframes`, `@property`, `@font-face`, `@counter-style`, and `@function` support
|
|
15
15
|
- **Smart cleanup** - CSS rules batched cleanup, keyframes disposed immediately
|
|
16
16
|
- **SSR support** - Deterministic class names and CSS extraction
|
|
17
17
|
- **Multiple roots** - Works with Document and ShadowRoot
|
|
@@ -63,10 +63,16 @@ const result = inject([{
|
|
|
63
63
|
|
|
64
64
|
console.log(result.className); // 't-abc123'
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// Release the pin; the class becomes collectible once nothing renders it
|
|
67
67
|
result.dispose();
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
`inject()` **pins** the class it returns, and `gc()` never evicts a pinned class
|
|
71
|
+
— that is what `dispose()` releases. Pass `{ pin: false }` when the caller keeps
|
|
72
|
+
no handle and the DOM is the only record that the class is in use; `dispose()`
|
|
73
|
+
is then a no-op. The render path (`tasty()` / `computeStyles()`) injects this
|
|
74
|
+
way, because a hook-free render has no unmount signal to dispose on.
|
|
75
|
+
|
|
70
76
|
### `injectGlobal(rules, options?): { dispose: () => void }`
|
|
71
77
|
|
|
72
78
|
Injects global styles that don't reserve tasty class names.
|
|
@@ -224,14 +230,62 @@ configure({
|
|
|
224
230
|
|
|
225
231
|
**Auto-Detection Features:**
|
|
226
232
|
- `devMode`: Automatically enabled in development environments (detected via `isDevEnv()`)
|
|
227
|
-
- `forceTextInjection`: Automatically enabled in test environments (Jest, Vitest, Mocha, jsdom)
|
|
233
|
+
- `forceTextInjection`: Automatically enabled in test environments (Jest, Vitest, Mocha, happy-dom, jsdom)
|
|
234
|
+
|
|
235
|
+
**Injection Modes:**
|
|
236
|
+
|
|
237
|
+
Each sheet picks its write mode once, when it is created, and keeps it for its
|
|
238
|
+
lifetime:
|
|
239
|
+
|
|
240
|
+
| Mode | How rules are written | How rules are removed |
|
|
241
|
+
|---|---|---|
|
|
242
|
+
| CSSOM (default) | `styleSheet.insertRule(rule, index)` | `styleSheet.deleteRule(index)` |
|
|
243
|
+
| Text (`forceTextInjection`, or when `styleElement.sheet` is unavailable) | appended to `<style>.textContent` | rule texts are tracked per sheet and the element's text is rebuilt without them |
|
|
244
|
+
| Adopted (ShadowRoot with constructable sheets) | `insertRule` on the constructable sheet | `deleteRule` on the constructable sheet |
|
|
245
|
+
|
|
246
|
+
Text mode cannot edit a single rule in place the way CSSOM can, so the sheet
|
|
247
|
+
keeps the inserted rule texts in index order and rewrites the element on delete.
|
|
248
|
+
Dispose, ref-counted cleanup and GC therefore behave identically in every mode.
|
|
228
249
|
|
|
229
250
|
**Configuration Notes:**
|
|
230
251
|
- Most options have sensible defaults and auto-detection
|
|
231
252
|
- `configure()` is optional - the injector works with defaults
|
|
232
253
|
- **Configuration is locked after styles are generated** - calling `configure()` after first render will emit a warning and be ignored
|
|
233
|
-
- `gc.
|
|
234
|
-
- `gc.
|
|
254
|
+
- `gc.unsafeAutoCollect`: Sweep automatically as rendering goes, rather than only when you call `gc()` or `cleanup()` (default `false`). See the caveat below.
|
|
255
|
+
- `gc.touchInterval`: Number of touch events between automatic GC cycles, used only with `unsafeAutoCollect`. Each style render counts as a touch. When the counter reaches this value, GC is scheduled via `requestIdleCallback`.
|
|
256
|
+
- `gc.timeoutFallback`: With `unsafeAutoCollect`, schedule the sweep with a timeout where `requestIdleCallback` is unavailable (default `false`). Collection is a background chore, so it otherwise runs only in idle time; opting in trades that for automatic collection on engines that cannot offer any.
|
|
257
|
+
|
|
258
|
+
> **Why `unsafeAutoCollect` is named that.** A sweep decides what is finished by scanning the DOM, and rendering is not commit-aware: a concurrent render can yield between the `inject()` that creates a class and the commit that attaches it. A sweep landing in that window sees no element carrying the class and deletes rules the pending render is about to use, so the element commits unstyled until something re-renders it. A pending render is indistinguishable from one that already committed and unmounted — React reports neither commit nor discard for a class name handed out during render — so no heuristic closes this; only a real commit signal would.
|
|
259
|
+
>
|
|
260
|
+
> Prefer `gc()` or `cleanup()` at a moment of your choosing: a route change, an idle callback of your own, test teardown.
|
|
261
|
+
- `gc.capacity`: Maximum number of unused styles (not in the DOM, not pinned) to retain. When exceeded, the least recently used are evicted first. Rendered and pinned styles don't count against this limit.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### At-rule injection
|
|
266
|
+
|
|
267
|
+
Beyond ordinary rules, the injector has a dedicated entry point per at-rule. All of them deduplicate by name and are **permanent** — there is no ref-counting or dispose, because a rule that other CSS references by name cannot be safely removed while any of it might still apply.
|
|
268
|
+
|
|
269
|
+
| Function | Injects | Notes |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| `keyframes(steps, nameOrOptions?)` | `@keyframes` | The exception: ref-counted and disposed immediately when unused. Returns the injected name, which may differ from the requested one. |
|
|
272
|
+
| `property(name, options?)` | `@property` | `name` accepts `$name`, `#name`, or `--name`. Usually unnecessary — types are inferred automatically unless `configure({ autoPropertyTypes: false })`. |
|
|
273
|
+
| `fontFace(family, descriptors, options?)` | `@font-face` | Deduplicated by family **and** descriptor content, so several faces of one family coexist. |
|
|
274
|
+
| `counterStyle(name, descriptors, options?)` | `@counter-style` | |
|
|
275
|
+
| `func(name, definition, options?)` | `@function` | `name` accepts `$$name`, `$name`, or `--name`. Abbreviated because `function` is a reserved word. |
|
|
276
|
+
|
|
277
|
+
Every one of these takes an optional `root` (a `Document` or `ShadowRoot`).
|
|
278
|
+
|
|
279
|
+
`func()` also accepts `weak: true`, which registers the rule **without** overriding an existing one of the same name. `configure()` uses it for global `@function` definitions so a component-local definition always wins over the global default, regardless of which is injected first.
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import { counterStyle, fontFace, func, property } from '@tenphi/tasty';
|
|
283
|
+
|
|
284
|
+
property('$card-elevation', { syntax: '<number>', initialValue: '0' });
|
|
285
|
+
fontFace('Inter', { src: 'url(/inter.woff2)', fontWeight: '400 700' });
|
|
286
|
+
counterStyle('dashes', { system: 'cyclic', symbols: '"—"', suffix: ' ' });
|
|
287
|
+
func('$$negative', { args: ['$value'], result: '(-1 * $value)' });
|
|
288
|
+
```
|
|
235
289
|
|
|
236
290
|
---
|
|
237
291
|
|
|
@@ -258,6 +312,17 @@ const styleRule: StyleResult = {
|
|
|
258
312
|
};
|
|
259
313
|
```
|
|
260
314
|
|
|
315
|
+
### Batched Injection
|
|
316
|
+
|
|
317
|
+
`configure({ batchInjection: true })` queues every sheet write — component
|
|
318
|
+
rules, global rules, raw CSS and at-rules — into one FIFO and applies them
|
|
319
|
+
together, so the document is style-invalidated once per flush instead of once per
|
|
320
|
+
component. `<TastyBatchProvider>` flushes in `useInsertionEffect`, before any
|
|
321
|
+
layout effect, so a queued write can never be observed by a measurement. See
|
|
322
|
+
[Batched injection](configuration.md#batched-injection) for the modes and the
|
|
323
|
+
ordering guarantee. `flushStyles()` applies pending writes on demand; every read
|
|
324
|
+
API here calls it for you.
|
|
325
|
+
|
|
261
326
|
### Deduplication & Performance
|
|
262
327
|
|
|
263
328
|
```typescript
|
|
@@ -276,23 +341,28 @@ const button2 = inject([{
|
|
|
276
341
|
console.log(button1.className === button2.className); // true
|
|
277
342
|
```
|
|
278
343
|
|
|
279
|
-
###
|
|
344
|
+
### Pinning
|
|
280
345
|
|
|
281
346
|
```typescript
|
|
282
|
-
// Multiple
|
|
347
|
+
// Multiple callers using the same styles
|
|
283
348
|
const comp1 = inject([commonStyle]);
|
|
284
349
|
const comp2 = inject([commonStyle]);
|
|
285
350
|
const comp3 = inject([commonStyle]);
|
|
286
351
|
|
|
287
|
-
// Style is
|
|
288
|
-
comp1.dispose(); //
|
|
289
|
-
comp2.dispose(); //
|
|
290
|
-
comp3.dispose(); //
|
|
352
|
+
// Style is pinned while any caller holds a handle
|
|
353
|
+
comp1.dispose(); // pins: 3 → 2
|
|
354
|
+
comp2.dispose(); // pins: 2 → 1
|
|
355
|
+
comp3.dispose(); // pins: 1 → 0, now up to the DOM and gc()
|
|
291
356
|
|
|
292
|
-
//
|
|
293
|
-
//
|
|
357
|
+
// Unpinned does not mean deleted: the rule stays cached and is reused instantly
|
|
358
|
+
// by the next inject(). gc() decides when it actually goes.
|
|
294
359
|
```
|
|
295
360
|
|
|
361
|
+
Pinning covers callers that hold a handle. Styles that come from rendering are
|
|
362
|
+
never pinned — see `{ pin: false }` under
|
|
363
|
+
[`inject()`](#injectrules-options-injectresult) — so what keeps them alive is
|
|
364
|
+
being in the DOM, and nothing else.
|
|
365
|
+
|
|
296
366
|
### Garbage Collection
|
|
297
367
|
|
|
298
368
|
```typescript
|
|
@@ -300,6 +370,9 @@ import { configure, gc } from '@tenphi/tasty';
|
|
|
300
370
|
|
|
301
371
|
// Keyframes: Disposed immediately when refCount = 0 (safer for global scope)
|
|
302
372
|
// CSS rules: Tracked by touch count and cleaned up via gc()
|
|
373
|
+
//
|
|
374
|
+
// A CSS rule is collectible when no element carries its class AND nobody
|
|
375
|
+
// pinned it with inject().
|
|
303
376
|
|
|
304
377
|
configure({
|
|
305
378
|
gc: {
|
|
@@ -314,15 +387,20 @@ gc();
|
|
|
314
387
|
// Force-remove ALL unused styles (e.g. on route change or test teardown):
|
|
315
388
|
gc({ force: true });
|
|
316
389
|
|
|
317
|
-
//
|
|
318
|
-
|
|
390
|
+
// cleanup() is the same thing:
|
|
391
|
+
cleanup();
|
|
392
|
+
|
|
393
|
+
// Collection is on demand by default: gc() and cleanup() are the whole story,
|
|
394
|
+
// and nothing sweeps behind your back. `gc.unsafeAutoCollect` opts into a sweep
|
|
395
|
+
// every `touchInterval` touches, scheduled via requestIdleCallback — read the
|
|
396
|
+
// caveat below before turning it on.
|
|
319
397
|
|
|
320
398
|
// Benefits:
|
|
321
399
|
// - Activity-proportional: busy apps trigger GC more often
|
|
322
400
|
// - DOM-safe: styles currently in the DOM are never evicted
|
|
323
401
|
// - Oldest-first: least recently used styles are evicted first
|
|
324
402
|
// - Keyframes: Immediate cleanup prevents global namespace pollution
|
|
325
|
-
// - Unused styles
|
|
403
|
+
// - Unused styles stay cached until evicted, so re-rendering them is a cache hit
|
|
326
404
|
```
|
|
327
405
|
|
|
328
406
|
### Shadow DOM Support
|
|
@@ -350,14 +428,14 @@ const shadowAnimation = keyframes({
|
|
|
350
428
|
### Server-Side Rendering
|
|
351
429
|
|
|
352
430
|
```typescript
|
|
353
|
-
import {
|
|
431
|
+
import { getCSSText, getCSSTextForNode } from '@tenphi/tasty';
|
|
354
432
|
|
|
355
433
|
// Extract all CSS for SSR
|
|
356
|
-
const cssText =
|
|
434
|
+
const cssText = getCSSText();
|
|
357
435
|
|
|
358
436
|
// Extract CSS for specific DOM subtree (like jest-styled-components)
|
|
359
437
|
const container = render(<MyComponent />);
|
|
360
|
-
const componentCSS =
|
|
438
|
+
const componentCSS = getCSSTextForNode(container);
|
|
361
439
|
```
|
|
362
440
|
|
|
363
441
|
### Test Environment Detection
|
|
@@ -366,7 +444,7 @@ const componentCSS = getCssTextForNode(container);
|
|
|
366
444
|
// Automatically detected test environments:
|
|
367
445
|
// - NODE_ENV === 'test'
|
|
368
446
|
// - Jest globals (jest, describe, it, expect)
|
|
369
|
-
// - jsdom user agent
|
|
447
|
+
// - jsdom / HappyDOM user agent
|
|
370
448
|
// - Vitest globals (vitest)
|
|
371
449
|
// - Mocha globals (mocha)
|
|
372
450
|
|
|
@@ -417,11 +495,11 @@ const metrics = injector.instance.getMetrics();
|
|
|
417
495
|
console.log({
|
|
418
496
|
cacheHits: metrics.hits, // Successful cache hits
|
|
419
497
|
cacheMisses: metrics.misses, // New styles injected
|
|
420
|
-
unusedHits: metrics.unusedHits, //
|
|
498
|
+
unusedHits: metrics.unusedHits, // Styles currently eligible for eviction (scans the DOM)
|
|
421
499
|
bulkCleanups: metrics.bulkCleanups, // Number of bulk cleanup operations
|
|
422
500
|
stylesCleanedUp: metrics.stylesCleanedUp, // Total styles removed in bulk cleanups
|
|
423
501
|
totalInsertions: metrics.totalInsertions, // Lifetime insertions
|
|
424
|
-
totalUnused: metrics.totalUnused, //
|
|
502
|
+
totalUnused: metrics.totalUnused, // Times a pinned style lost its last pin
|
|
425
503
|
startTime: metrics.startTime, // Metrics collection start timestamp
|
|
426
504
|
cleanupHistory: metrics.cleanupHistory, // Detailed cleanup operation history
|
|
427
505
|
});
|
|
@@ -465,10 +543,10 @@ metrics.cleanupHistory.forEach(cleanup => {
|
|
|
465
543
|
|
|
466
544
|
```typescript
|
|
467
545
|
// ✅ Reuse styles - identical CSS gets deduplicated
|
|
468
|
-
const buttonBase =
|
|
546
|
+
const buttonBase = 'padding: 8px 16px; border-radius: 4px;';
|
|
469
547
|
|
|
470
548
|
// ✅ Avoid frequent disposal and re-injection
|
|
471
|
-
// Let the
|
|
549
|
+
// Let the injector handle cleanup
|
|
472
550
|
|
|
473
551
|
// ✅ Use bulk operations for global styles
|
|
474
552
|
injectGlobal([
|
|
@@ -494,13 +572,13 @@ configure({
|
|
|
494
572
|
// The injector automatically manages memory through:
|
|
495
573
|
|
|
496
574
|
// 1. Hash-based deduplication - same CSS = same className
|
|
497
|
-
// 2.
|
|
498
|
-
// 3.
|
|
499
|
-
// 4.
|
|
500
|
-
// 5.
|
|
575
|
+
// 2. DOM-driven lifetime - a rendered class is never evicted
|
|
576
|
+
// 3. Pinning - inject() callers hold their classes until they dispose
|
|
577
|
+
// 4. Immediate keyframes cleanup - disposed instantly when refCount = 0
|
|
578
|
+
// 5. Touch-count GC - unused CSS rules are evicted oldest-first when over capacity
|
|
501
579
|
|
|
502
580
|
// Manual cleanup is rarely needed but available:
|
|
503
|
-
cleanup(); //
|
|
581
|
+
cleanup(); // Remove every rule that is neither rendered nor pinned
|
|
504
582
|
destroy(); // Nuclear option: remove all stylesheets and reset
|
|
505
583
|
```
|
|
506
584
|
|
|
@@ -522,9 +600,9 @@ const StyledButton = tasty({
|
|
|
522
600
|
|
|
523
601
|
// Internally uses the injector:
|
|
524
602
|
// 1. Styles are parsed into StyleResult objects
|
|
525
|
-
// 2. inject() is called with the parsed results
|
|
603
|
+
// 2. inject() is called with the parsed results, unpinned
|
|
526
604
|
// 3. Component gets the returned className
|
|
527
|
-
// 4.
|
|
605
|
+
// 4. gc() reclaims the class once no element carries it
|
|
528
606
|
```
|
|
529
607
|
|
|
530
608
|
For most development, you'll use the [React API](./react-api.md) rather than the injector directly. The injector provides the high-performance foundation that makes Tasty's declarative styling possible.
|