@tenphi/tasty 0.0.0-snapshot.1d29633 → 0.0.0-snapshot.1f1c00a
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 +152 -134
- package/dist/{babel-Cg-mJV_t.d.ts → babel-rZcEwPLM.d.ts} +2 -3
- package/dist/chunks/async-storage-CG5HnUT5.js +20 -0
- package/dist/chunks/async-storage-CG5HnUT5.js.map +1 -0
- package/dist/chunks/build-config-CL4eRu2z.js +42 -0
- package/dist/chunks/build-config-CL4eRu2z.js.map +1 -0
- package/dist/{collector-BMT05AmU.js → chunks/collector-D2ARGT2L.js} +21 -117
- package/dist/chunks/collector-D2ARGT2L.js.map +1 -0
- package/dist/chunks/config-engine-DEmmPPdp.js +272 -0
- package/dist/chunks/config-engine-DEmmPPdp.js.map +1 -0
- package/dist/chunks/css-definitions-DotDkIXt.js +876 -0
- package/dist/chunks/css-definitions-DotDkIXt.js.map +1 -0
- package/dist/chunks/css-resources-P7IBUUZs.js +142 -0
- package/dist/chunks/css-resources-P7IBUUZs.js.map +1 -0
- package/dist/chunks/debug-D8pg9RGI.js +502 -0
- package/dist/chunks/debug-D8pg9RGI.js.map +1 -0
- package/dist/chunks/dsl-DRhFWQzo.js +1378 -0
- package/dist/chunks/dsl-DRhFWQzo.js.map +1 -0
- package/dist/chunks/hydration-TRcz5vnk.js +41 -0
- package/dist/chunks/hydration-TRcz5vnk.js.map +1 -0
- package/dist/chunks/react-runtime-BpxlOTbO.js +562 -0
- package/dist/chunks/react-runtime-BpxlOTbO.js.map +1 -0
- package/dist/chunks/runtime-engine-CKFXUH-A.js +2416 -0
- package/dist/chunks/runtime-engine-CKFXUH-A.js.map +1 -0
- package/dist/chunks/runtime-state-BxaLhVdP.js +127 -0
- package/dist/chunks/runtime-state-BxaLhVdP.js.map +1 -0
- package/dist/{merge-styles-CkAcnd0Z.js → chunks/shared-utils-y-HjvPN4.js} +60 -55
- package/dist/chunks/shared-utils-y-HjvPN4.js.map +1 -0
- package/dist/chunks/style-engine-BBbBuSkT.js +5260 -0
- package/dist/chunks/style-engine-BBbBuSkT.js.map +1 -0
- package/dist/{css-writer-b02uBqNF.js → chunks/zero-engine-gJrKBRiw.js} +6 -121
- package/dist/chunks/zero-engine-gJrKBRiw.js.map +1 -0
- package/dist/{collector-BFuqdF2F.d.ts → collector-w4mBj5gd.d.ts} +23 -4
- package/dist/{config-DmFxnBxg.d.ts → config-CZWCzBr6.d.ts} +171 -72
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +9 -6
- package/dist/{index-D1nMkpUe.d.ts → index-G9JuwM9p.d.ts} +263 -247
- package/dist/index.d.ts +5 -5
- package/dist/index.js +11 -921
- package/dist/{merge-styles-Cx_6ySBv.d.ts → merge-styles-VXwJ0Frr.d.ts} +2 -3
- package/dist/ssr/astro-client.d.ts +1 -1
- package/dist/ssr/astro-client.js +1 -14
- package/dist/ssr/astro-client.js.map +1 -1
- package/dist/ssr/astro-middleware-extract-static.d.ts +10 -0
- package/dist/ssr/astro-middleware-extract-static.js +9 -0
- package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
- package/dist/ssr/astro-middleware-extract.d.ts +10 -0
- package/dist/ssr/astro-middleware-extract.js +9 -0
- package/dist/ssr/astro-middleware-extract.js.map +1 -0
- package/dist/ssr/astro-middleware-static.d.ts +3 -2
- package/dist/ssr/astro-middleware-static.js +0 -11
- package/dist/ssr/astro-middleware-static.js.map +1 -1
- package/dist/ssr/astro-middleware.d.ts +3 -2
- package/dist/ssr/astro-middleware.js +0 -12
- package/dist/ssr/astro-middleware.js.map +1 -1
- package/dist/ssr/astro.d.ts +40 -6
- package/dist/ssr/astro.js +157 -93
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/index.d.ts +10 -11
- package/dist/ssr/index.js +4 -4
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next-config.d.ts +64 -0
- package/dist/ssr/next-config.js +128 -0
- package/dist/ssr/next-config.js.map +1 -0
- package/dist/ssr/next.d.ts +9 -8
- package/dist/ssr/next.js +29 -43
- package/dist/ssr/next.js.map +1 -1
- package/dist/static/index.d.ts +8 -9
- package/dist/static/index.js +4 -22
- package/dist/static/index.js.map +1 -1
- package/dist/static/inject.d.ts +1 -2
- package/dist/{index-LC3O3Jj4.d.ts → types-JEY8PVYP.d.ts} +862 -811
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +41 -107
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +6 -7
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +3 -5
- package/dist/zero/next.js +0 -31
- package/dist/zero/next.js.map +1 -1
- package/docs/README.md +13 -8
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +107 -80
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +179 -114
- package/docs/debug.md +19 -7
- package/docs/design-system.md +41 -22
- package/docs/dsl.md +310 -201
- package/docs/getting-started.md +64 -41
- package/docs/injector.md +63 -26
- package/docs/methodology.md +44 -38
- package/docs/migration-v3.md +49 -49
- package/docs/pipeline.md +32 -8
- package/docs/plugins.md +38 -34
- package/docs/react-api.md +67 -44
- package/docs/runtime-benchmarks.md +388 -0
- package/docs/ssr.md +219 -61
- package/docs/styles.md +95 -18
- package/docs/tasty-static.md +138 -105
- package/package.json +104 -33
- package/dist/async-storage-DKK-wTD4.js +0 -44
- package/dist/async-storage-DKK-wTD4.js.map +0 -1
- package/dist/collector-BMT05AmU.js.map +0 -1
- package/dist/config-DF93rL3u.js +0 -12661
- package/dist/config-DF93rL3u.js.map +0 -1
- package/dist/context-CA8YKeMn.js +0 -24
- package/dist/context-CA8YKeMn.js.map +0 -1
- package/dist/core-B5ybnMP1.js +0 -1529
- package/dist/core-B5ybnMP1.js.map +0 -1
- package/dist/css-writer-b02uBqNF.js.map +0 -1
- package/dist/format-global-rules-DklyaXv-.js +0 -22
- package/dist/format-global-rules-DklyaXv-.js.map +0 -1
- package/dist/format-rules-Cs4e3M9m.js +0 -130
- package/dist/format-rules-Cs4e3M9m.js.map +0 -1
- package/dist/hydrate-aaUSNJZJ.js +0 -37
- package/dist/hydrate-aaUSNJZJ.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/keyframes-BedEzEXk.js +0 -424
- package/dist/keyframes-BedEzEXk.js.map +0 -1
- package/dist/merge-styles-CkAcnd0Z.js.map +0 -1
- package/dist/resolve-recipes-CiyLtJG9.js +0 -144
- package/dist/resolve-recipes-CiyLtJG9.js.map +0 -1
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Tasty works without upfront configuration. Use `configure()` when your app or design system is ready to define shared tokens, state aliases, units, recipes, presets, or extension points.
|
|
4
|
+
|
|
5
|
+
Call it **before any styles are generated** (before first render). For a guided setup, see [Getting Started](getting-started.md). For the higher-level docs map, see the [Docs Hub](README.md).
|
|
4
6
|
|
|
5
7
|
```jsx
|
|
6
8
|
import { configure } from '@tenphi/tasty';
|
|
@@ -45,35 +47,35 @@ These docs use `data-schema="dark"` in examples. If your app already standardize
|
|
|
45
47
|
|
|
46
48
|
## Options
|
|
47
49
|
|
|
48
|
-
| Option
|
|
49
|
-
|
|
50
|
-
| `nonce`
|
|
51
|
-
| `maxRulesPerSheet`
|
|
52
|
-
| `forceTextInjection` | `boolean`
|
|
53
|
-
| `devMode`
|
|
54
|
-
| `states`
|
|
55
|
-
| `parserCacheSize`
|
|
56
|
-
| `units`
|
|
57
|
-
| `functions`
|
|
58
|
-
| `handlers`
|
|
59
|
-
| `propHandlers`
|
|
60
|
-
| `baseStyleProps`
|
|
61
|
-
| `tokens`
|
|
62
|
-
| `replaceTokens`
|
|
63
|
-
| `keyframes`
|
|
64
|
-
| `properties`
|
|
65
|
-
| `fontFaces`
|
|
66
|
-
| `counterStyles`
|
|
67
|
-
| `polyfills`
|
|
68
|
-
| `autoPropertyTypes`
|
|
69
|
-
| `recipes`
|
|
70
|
-
| `presets`
|
|
71
|
-
| `globalStyles`
|
|
72
|
-
| `plugins`
|
|
73
|
-
| `gc`
|
|
74
|
-
| `batchInjection`
|
|
75
|
-
| `colorSpace`
|
|
76
|
-
| `namePrefix`
|
|
50
|
+
| Option | Type | Default | Description |
|
|
51
|
+
| -------------------- | ------------------------------------------------ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
52
|
+
| `nonce` | `string` | - | CSP nonce for style elements |
|
|
53
|
+
| `maxRulesPerSheet` | `number` | `8192` | Maximum rules per injected stylesheet |
|
|
54
|
+
| `forceTextInjection` | `boolean` | auto (`true` in test envs) | Force text-node CSS injection instead of constructable stylesheets |
|
|
55
|
+
| `devMode` | `boolean` | auto | Enable development-mode features: performance metrics and debug info |
|
|
56
|
+
| `states` | `Record<string, string>` | - | Global state aliases for advanced state mapping |
|
|
57
|
+
| `parserCacheSize` | `number` | `1000` | Parser LRU cache size |
|
|
58
|
+
| `units` | `Record<string, string \| UnitHandler>` | Built-in | Custom units (merged with built-in). See [built-in units](dsl.md#built-in-units) |
|
|
59
|
+
| `functions` | `Record<string, FunctionDefinition \| Function>` | - | Custom functions (merged). Bare keys → parse functions; `$$name` keys → declarative CSS `@function` definitions |
|
|
60
|
+
| `handlers` | `Record<string, StyleHandlerDefinition>` | Built-in | Custom style handlers (replace built-in). See [Custom Style Handlers](#custom-style-handlers) |
|
|
61
|
+
| `propHandlers` | `Record<string, PropHandlerDefinition>` | - | Props middleware for every component — props in, props out. See [Props Middleware](#props-middleware) |
|
|
62
|
+
| `baseStyleProps` | `readonly string[]` | - | Style names exposed as props on **every** component. See [Base Style Props](#base-style-props) |
|
|
63
|
+
| `tokens` | `Record<string, value \| stateMap>` | - | Design tokens injected as `:root` CSS custom properties |
|
|
64
|
+
| `replaceTokens` | `Record<string, string \| number \| boolean>` | - | Parse-time token substitution (inline replacement). `boolean` is allowed for `#` color tokens |
|
|
65
|
+
| `keyframes` | `Record<string, KeyframesSteps>` | - | Global keyframes for animations |
|
|
66
|
+
| `properties` | `Record<string, PropertyDefinition>` | - | Global CSS @property definitions |
|
|
67
|
+
| `fontFaces` | `Record<string, FontFaceInput>` | - | Global @font-face definitions |
|
|
68
|
+
| `counterStyles` | `Record<string, CounterStyleDescriptors>` | - | Global @counter-style definitions |
|
|
69
|
+
| `polyfills` | `{ functions?: boolean }` | `{}` | Opt-in polyfills for not-yet-baseline features. `functions: true` inlines `@function` calls into plain CSS at parse time |
|
|
70
|
+
| `autoPropertyTypes` | `boolean` | `true` | Auto-infer and register `@property` types from values |
|
|
71
|
+
| `recipes` | `Record<string, RecipeStyles>` | - | Predefined style recipes (named style bundles) |
|
|
72
|
+
| `presets` | `Record<string, TypographyPreset>` | - | Typography presets — shorthand for `generateTypographyTokens()` |
|
|
73
|
+
| `globalStyles` | `Record<string, Styles>` | - | Global Tasty styles keyed by CSS selector |
|
|
74
|
+
| `plugins` | `TastyPlugin[]` | - | Plugins that bundle any of the above (processed in order; later override earlier, and direct config wins over all). See [Plugins](plugins.md) |
|
|
75
|
+
| `gc` | `GCConfig` | - | Garbage-collection tuning for unused styles (`{ touchInterval, capacity }`) |
|
|
76
|
+
| `batchInjection` | `boolean \| 'always'` | `false` | Defer stylesheet writes and apply them in one batch. See [Batched injection](#batched-injection) |
|
|
77
|
+
| `colorSpace` | `'rgb' \| 'hsl' \| 'oklch'` | - | **Deprecated** — no longer has any effect. See [Color space](#color-space) |
|
|
78
|
+
| `namePrefix` | `string` | `'t'` (`tasty`) / `'ts'` (build-time) | Prefix prepended to every generated identifier (class, keyframe, counter-style names). Must match `^[a-zA-Z_][a-zA-Z0-9_-]{0,31}$`. See [Name prefix](#name-prefix). |
|
|
77
79
|
|
|
78
80
|
---
|
|
79
81
|
|
|
@@ -107,10 +109,10 @@ createRoot(el).render(
|
|
|
107
109
|
### Why the provider is required
|
|
108
110
|
|
|
109
111
|
Deferring a write past React's layout phase would let a `useLayoutEffect`
|
|
110
|
-
measure an element whose rules are not in the sheet yet and read its
|
|
112
|
+
measure an element whose rules are not in the sheet yet and read its _unstyled_
|
|
111
113
|
box — a wrong number, not a stale one, so it never self-corrects.
|
|
112
114
|
|
|
113
|
-
`TastyBatchProvider` closes that hole. It opens a
|
|
115
|
+
`TastyBatchProvider` closes that hole. It opens a _batch window_ during its
|
|
114
116
|
render and closes it — flushing — in `useInsertionEffect`, which React runs in
|
|
115
117
|
the mutation phase, before any layout effect:
|
|
116
118
|
|
|
@@ -135,11 +137,11 @@ commits it takes part in.
|
|
|
135
137
|
|
|
136
138
|
### Modes
|
|
137
139
|
|
|
138
|
-
| Value
|
|
139
|
-
|
|
140
|
-
| `false` (default) | One `insertRule()` per component, synchronously.
|
|
141
|
-
| `true`
|
|
142
|
-
| `'always'`
|
|
140
|
+
| Value | Behaviour |
|
|
141
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `false` (default) | One `insertRule()` per component, synchronously. |
|
|
143
|
+
| `true` | Batch inside a provider window only. Cannot affect measurement. Without the provider nothing is batched, and dev mode says so once. |
|
|
144
|
+
| `'always'` | Batch every injection, flushing on a microtask when no window is open. Covers more commits; a `useLayoutEffect` measuring a freshly mounted element can read its unstyled box. Paint is unaffected — microtasks always drain before the browser paints. |
|
|
143
145
|
|
|
144
146
|
### Ordering
|
|
145
147
|
|
|
@@ -148,7 +150,7 @@ All writes share one FIFO queue — component rules, global rules, raw CSS,
|
|
|
148
150
|
Draining it in insertion order keeps the sheet byte-identical to unbatched
|
|
149
151
|
output, which matters because equal-specificity rules resolve by document order.
|
|
150
152
|
|
|
151
|
-
###
|
|
153
|
+
### Client rendering, server rendering, and build-time extraction
|
|
152
154
|
|
|
153
155
|
**Server render — nothing to batch, safe to leave enabled.** SSR and RSC collect
|
|
154
156
|
CSS as text through `ServerStyleCollector`; the runtime injector never runs
|
|
@@ -173,12 +175,12 @@ tasty components to be worth it. `'always'` needs no provider and covers every
|
|
|
173
175
|
island, at the cost of the measurement hazard above. Either way, an island that
|
|
174
176
|
only re-hydrates server-rendered classes has nothing to batch.
|
|
175
177
|
|
|
176
|
-
**
|
|
178
|
+
**Build-time extraction (`tastyStatic`) — unaffected.** The Babel plugin never
|
|
177
179
|
touches the injector: the babel plugin emits either a CSS file import or an
|
|
178
180
|
`injectCSS()` call from `@tenphi/tasty/static/inject`, which appends text to a
|
|
179
181
|
single `<style data-tasty-static>` element. `batchInjection` only defers CSSOM
|
|
180
|
-
writes made by the
|
|
181
|
-
that mixes both, it still applies to the
|
|
182
|
+
writes made by the browser injector, so extracted styles are unchanged. In an app
|
|
183
|
+
that mixes both, it still applies to the `tasty()` half.
|
|
182
184
|
|
|
183
185
|
### `flushStyles()`
|
|
184
186
|
|
|
@@ -205,45 +207,84 @@ useLayoutEffect(() => {
|
|
|
205
207
|
|
|
206
208
|
## Color Space
|
|
207
209
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
> **Deprecated.** `configure({ colorSpace })` no longer has any effect and will
|
|
211
|
+
> be removed in the next major. Setting it warns in development.
|
|
212
|
+
|
|
213
|
+
A `#name` token's value used to be rewritten into a configured color space, so
|
|
214
|
+
`#brand: '#ff8800'` declared `--brand-color: oklch(0.75 0.16 55)`. That existed
|
|
215
|
+
to serve the opacity suffix, which needed numeric channels to write an alpha
|
|
216
|
+
into. Opacity now uses CSS relative color syntax —
|
|
217
|
+
`oklch(from var(--brand-color) l c h / .5)` — which has the browser read the
|
|
218
|
+
channels, so there is nothing left for the setting to decide.
|
|
219
|
+
|
|
220
|
+
A color is emitted exactly as authored:
|
|
211
221
|
|
|
212
222
|
```jsx
|
|
213
|
-
configure({
|
|
214
|
-
|
|
215
|
-
|
|
223
|
+
configure({ tokens: { '#brand': '#ff8800' } });
|
|
224
|
+
// → --brand-color: #ff8800
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
That holds for every form: a hex literal, a native color function, a bare CSS
|
|
228
|
+
color name, a `color-mix()`, a `light-dark()`, a fallback chain. A `#token`
|
|
229
|
+
reference still resolves to its `var()` chain, and a plugin color function such
|
|
230
|
+
as `okhsl()` is still resolved by the parser to the color it denotes.
|
|
231
|
+
|
|
232
|
+
To address a token's channels, use relative color syntax against the token:
|
|
233
|
+
|
|
234
|
+
```css
|
|
235
|
+
background: oklch(from var(--brand-color) calc(l * 1.2) c h);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
This works on any `<color>`, including the ones no build-time conversion could
|
|
239
|
+
have evaluated — and it is what the [opacity suffix](dsl.md#color-tokens--opacity)
|
|
240
|
+
itself uses. Its space is always `oklch`, which is unbounded, so a wide-gamut
|
|
241
|
+
color survives a round trip a narrower space would clamp.
|
|
242
|
+
|
|
243
|
+
### Migrating off `colorSpace`
|
|
244
|
+
|
|
245
|
+
Drop the option. If you relied on the uniform output format, nothing in Tasty
|
|
246
|
+
needs it — author your tokens in the space you want them emitted in, since the
|
|
247
|
+
value now passes through untouched:
|
|
248
|
+
|
|
249
|
+
```jsx
|
|
250
|
+
// before: any input, normalized to the configured space on the way out
|
|
251
|
+
configure({ colorSpace: 'oklch', tokens: { '#brand': '#ff8800' } });
|
|
252
|
+
|
|
253
|
+
// after: author it in the space you want
|
|
254
|
+
configure({ tokens: { '#brand': 'oklch(0.75 0.16 55)' } });
|
|
216
255
|
```
|
|
217
256
|
|
|
218
|
-
|
|
219
|
-
|---|---|
|
|
220
|
-
| `rgb` | `--brand-color: rgb(255 136 0)` |
|
|
221
|
-
| `hsl` | `--brand-color: hsl(32 100% 50%)` |
|
|
222
|
-
| `oklch` | `--brand-color: oklch(0.75 0.16 55)` |
|
|
257
|
+
### Migrating off the channel companions
|
|
223
258
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
259
|
+
A `#name` token used to declare a second variable beside `--name-color` holding
|
|
260
|
+
its channels decomposed, suffixed with the configured space —
|
|
261
|
+
`--brand-color-oklch: 0.75 0.16 55` — and a `color` style emitted
|
|
262
|
+
`--current-color-{space}` beside `--current-color`. Both are gone, for the same
|
|
263
|
+
reason: they existed so an opacity suffix had channels to write an alpha into.
|
|
228
264
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
through `var()` — is emitted as authored and left for the browser to resolve.
|
|
265
|
+
These were never part of the public API, but they were visible in the emitted
|
|
266
|
+
CSS, so hand-authored CSS may reference one. Address the token itself instead:
|
|
232
267
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
268
|
+
```css
|
|
269
|
+
/* before */
|
|
270
|
+
color: oklch(var(--brand-color-oklch) / 0.5);
|
|
271
|
+
background: oklch(var(--brand-color-oklch));
|
|
272
|
+
|
|
273
|
+
/* after */
|
|
274
|
+
color: oklch(from var(--brand-color) l c h / 0.5);
|
|
275
|
+
background: var(--brand-color);
|
|
276
|
+
```
|
|
237
277
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
color
|
|
278
|
+
The replacement is strictly more capable — the companion could only be
|
|
279
|
+
decomposed for a color the engine could evaluate at build time, while relative
|
|
280
|
+
color syntax works on every `<color>`, including a `color-mix()`, a
|
|
281
|
+
`light-dark()`, and a variable Tasty never defined.
|
|
241
282
|
|
|
242
283
|
---
|
|
243
284
|
|
|
244
285
|
## Name Prefix
|
|
245
286
|
|
|
246
|
-
Every identifier Tasty generates — class names, keyframe names, counter-style names — starts with a configurable prefix. The
|
|
287
|
+
Every identifier Tasty generates — class names, keyframe names, counter-style names — starts with a configurable prefix. The `tasty()` client, SSR, and RSC paths default to `'t'`; the build-time extraction path (`tastyStatic` via the Babel plugin) defaults to `'ts'` so extracted classes can never collide with `tasty()` classes when both are loaded on the same page.
|
|
247
288
|
|
|
248
289
|
```jsx
|
|
249
290
|
configure({
|
|
@@ -253,12 +294,12 @@ configure({
|
|
|
253
294
|
|
|
254
295
|
The prefix is prepended verbatim to the hash, so include any separator inside the prefix string itself:
|
|
255
296
|
|
|
256
|
-
| Setting
|
|
257
|
-
|
|
258
|
-
| `'t'` (
|
|
259
|
-
| `'ts'` (
|
|
260
|
-
| `'mb'`
|
|
261
|
-
| `'myapp-'`
|
|
297
|
+
| Setting | Class | Keyframe | Counter-style |
|
|
298
|
+
| --------------------------- | ------------- | -------------- | -------------- |
|
|
299
|
+
| `'t'` (`tasty` default) | `t1a2b3` | `tk1a2b3` | `tc1a2b3` |
|
|
300
|
+
| `'ts'` (build-time default) | `ts1a2b3` | `tsk1a2b3` | `tsc1a2b3` |
|
|
301
|
+
| `'mb'` | `mb1a2b3` | `mbk1a2b3` | `mbc1a2b3` |
|
|
302
|
+
| `'myapp-'` | `myapp-1a2b3` | `myapp-k1a2b3` | `myapp-c1a2b3` |
|
|
262
303
|
|
|
263
304
|
The single-letter discriminators (`k` for keyframes, `c` for counter-styles) keep the three kinds visually distinct in devtools — they are not required for correctness because CSS keeps these in separate namespaces.
|
|
264
305
|
|
|
@@ -268,12 +309,12 @@ The single-letter discriminators (`k` for keyframes, `c` for counter-styles) kee
|
|
|
268
309
|
- Validated at `configure()` time; an invalid prefix throws synchronously rather than silently producing broken hydration.
|
|
269
310
|
- Locked once styles have been generated, like all other config.
|
|
270
311
|
|
|
271
|
-
### Coexistence with
|
|
312
|
+
### Coexistence with build-time extraction
|
|
272
313
|
|
|
273
|
-
The
|
|
314
|
+
The `tasty()` and `tastyStatic()` paths **must use different prefixes** when both are loaded on the same page. Defaults already guarantee this; if you customize one, customize the other accordingly:
|
|
274
315
|
|
|
275
316
|
```jsx
|
|
276
|
-
// app config (
|
|
317
|
+
// app config (client / SSR / RSC)
|
|
277
318
|
configure({ namePrefix: 'mb' });
|
|
278
319
|
|
|
279
320
|
// tasty-zero.config.ts (Babel plugin)
|
|
@@ -293,8 +334,8 @@ Tokens support state maps for responsive or theme-aware values:
|
|
|
293
334
|
```jsx
|
|
294
335
|
configure({
|
|
295
336
|
tokens: {
|
|
296
|
-
|
|
297
|
-
|
|
337
|
+
$gap: '4px',
|
|
338
|
+
$radius: '6px',
|
|
298
339
|
'#primary': {
|
|
299
340
|
'': '#purple',
|
|
300
341
|
'@dark': '#light-purple',
|
|
@@ -311,7 +352,7 @@ configure({
|
|
|
311
352
|
- `#name` keys become `--name-color` custom properties
|
|
312
353
|
- Names keep their case, since CSS custom properties are case-sensitive: `$myVar` is `--myVar` and is referenced as `$myVar`. A leading capital is not supported and folds — `$Foo` and `#Purple` become `--foo` and `--purple-color` — so start names lowercase. Kebab-case (`$my-var`) remains the convention.
|
|
313
354
|
|
|
314
|
-
Tokens are automatically emitted in all
|
|
355
|
+
Tokens are automatically emitted in all delivery modes: client rendering, server rendering, and build-time extraction with the Babel plugin.
|
|
315
356
|
|
|
316
357
|
---
|
|
317
358
|
|
|
@@ -365,7 +406,7 @@ configure({
|
|
|
365
406
|
});
|
|
366
407
|
```
|
|
367
408
|
|
|
368
|
-
Now any component can use `
|
|
409
|
+
Now any component can use `font: '"Brand Sans", sans-serif'` and the browser will already have the `@font-face` rules in the stylesheet.
|
|
369
410
|
|
|
370
411
|
See [Font Face (`@font-face`)](dsl.md#font-face-font-face) for inline usage inside component styles and the full list of supported descriptors.
|
|
371
412
|
|
|
@@ -422,7 +463,7 @@ configure({
|
|
|
422
463
|
});
|
|
423
464
|
```
|
|
424
465
|
|
|
425
|
-
Components then invoke parse functions as `double(...)` and CSS functions with the `$$name(...)` sugar, e.g. `
|
|
466
|
+
Components then invoke parse functions as `double(...)` and CSS functions with the `$$name(...)` sugar, e.g. `margin: '$$negative(10px) top'`.
|
|
426
467
|
|
|
427
468
|
> A key whose prefix doesn't match its value type (an object under a bare key, or a function under a `$$` key) is **ignored with a dev-mode warning**.
|
|
428
469
|
|
|
@@ -430,7 +471,7 @@ See [Functions (`@function`)](dsl.md#functions-function) for inline usage inside
|
|
|
430
471
|
|
|
431
472
|
### Custom color functions
|
|
432
473
|
|
|
433
|
-
A parse function whose output is an already-supported color (`rgb`, `hsl`, `#…`, `oklch`, …) is treated as a **color function**: it works everywhere a color is accepted — style values, `#token.alpha` opacity injection,
|
|
474
|
+
A parse function whose output is an already-supported color (`rgb`, `hsl`, `#…`, `oklch`, …) is treated as a **color function**: it works everywhere a color is accepted — style values, `#token.alpha` opacity injection, and `parseColor` — with no extra registration. This is the same mechanism the built-in `okhsl`/`okhst` plugins use; they are ordinary plugins registered by default.
|
|
434
475
|
|
|
435
476
|
```ts
|
|
436
477
|
import { configure, createColorFunc } from '@tenphi/tasty';
|
|
@@ -472,7 +513,7 @@ configure({
|
|
|
472
513
|
},
|
|
473
514
|
});
|
|
474
515
|
|
|
475
|
-
// Now `
|
|
516
|
+
// Now `margin: '$$negative(10px) top'` renders `margin: calc(-1 * 10px) 0 0 0`
|
|
476
517
|
// — no native @function rule is emitted.
|
|
477
518
|
```
|
|
478
519
|
|
|
@@ -508,7 +549,23 @@ configure({
|
|
|
508
549
|
});
|
|
509
550
|
```
|
|
510
551
|
|
|
511
|
-
Recipe values are flat tasty styles (no sub-element keys). They may contain base styles, tokens, local states, `@keyframes`, and `@property`.
|
|
552
|
+
Recipe values are flat tasty styles (no sub-element keys). They may contain base styles, tokens, local states, `@keyframes`, and `@property`.
|
|
553
|
+
|
|
554
|
+
**Recipes cannot reference other recipes.** A `recipe` key inside a configured recipe's value is not recursively resolved:
|
|
555
|
+
|
|
556
|
+
```jsx
|
|
557
|
+
// Unsupported: applying 'elevatedCard' does not expand 'card elevated'.
|
|
558
|
+
configure({
|
|
559
|
+
recipes: {
|
|
560
|
+
elevatedCard: {
|
|
561
|
+
recipe: 'card elevated',
|
|
562
|
+
padding: '6x',
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Instead, compose the names where you apply the styles: `styles: { recipe: 'card elevated', padding: '6x' }`. Recipe references are resolved on the component root and independently inside each sub-element's styles (for example, `styles: { Panel: { recipe: 'card elevated' } }`). This sub-element support does not allow one recipe definition to inherit another. Tasty warns in development when a recipe definition contains a `recipe` key.
|
|
512
569
|
|
|
513
570
|
For how to apply, compose, and override recipes in components, see [Recipes](dsl.md#recipes) in the Style DSL reference.
|
|
514
571
|
|
|
@@ -565,7 +622,7 @@ configure({
|
|
|
565
622
|
color: '#text',
|
|
566
623
|
preset: 't2',
|
|
567
624
|
margin: 0,
|
|
568
|
-
|
|
625
|
+
font: 'system-ui, sans-serif',
|
|
569
626
|
},
|
|
570
627
|
html: {
|
|
571
628
|
overflow: 'hidden',
|
|
@@ -576,7 +633,7 @@ configure({
|
|
|
576
633
|
|
|
577
634
|
Each key is a CSS selector, and each value is a Tasty `Styles` object supporting the full style syntax including style properties, tokens, state maps, and selector-based sub-styling (e.g. `$: '> .app'` for elements outside React scope). Global styles are injected alongside `:root` tokens when the first style is rendered.
|
|
578
635
|
|
|
579
|
-
Global styles are automatically emitted in all
|
|
636
|
+
Global styles are automatically emitted in all delivery modes: client rendering, server rendering, and build-time extraction with the Babel plugin. Plugins can also provide `globalStyles`; they are merged per selector with config global styles (config wins on conflict).
|
|
580
637
|
|
|
581
638
|
---
|
|
582
639
|
|
|
@@ -584,18 +641,18 @@ Global styles are automatically emitted in all rendering modes: runtime (client)
|
|
|
584
641
|
|
|
585
642
|
CSS cannot transition or animate custom properties unless their type is declared via [`@property`](https://developer.mozilla.org/en-US/docs/Web/CSS/@property). Tasty handles this automatically — when a custom property is assigned a concrete value (e.g. `'$scale': 1`, `'$gap': '10px'`, `'#accent': 'purple'`), the type is inferred and a `@property` rule is registered.
|
|
586
643
|
|
|
587
|
-
This works across all declaration contexts: component styles, `@keyframes`, global config, and the
|
|
644
|
+
This works across all declaration contexts: component styles, `@keyframes`, global config, and build-time extraction with the Babel plugin. It also resolves `var()` chains — if `$a` references `var(--b)`, the type propagates once `--b` is resolved.
|
|
588
645
|
|
|
589
646
|
Supported types:
|
|
590
647
|
|
|
591
|
-
| Detection
|
|
592
|
-
|
|
593
|
-
| `1`, `0.5`, `-3` (bare numbers)
|
|
594
|
-
| `10px`, `2rem`, `100vw` (length units) | `<length>`
|
|
595
|
-
| `50%`
|
|
596
|
-
| `45deg`, `0.5turn` (angle units)
|
|
597
|
-
| `300ms`, `1s` (time units)
|
|
598
|
-
| `#name` tokens (by naming convention)
|
|
648
|
+
| Detection | Inferred syntax |
|
|
649
|
+
| -------------------------------------- | --------------- |
|
|
650
|
+
| `1`, `0.5`, `-3` (bare numbers) | `<number>` |
|
|
651
|
+
| `10px`, `2rem`, `100vw` (length units) | `<length>` |
|
|
652
|
+
| `50%` | `<percentage>` |
|
|
653
|
+
| `45deg`, `0.5turn` (angle units) | `<angle>` |
|
|
654
|
+
| `300ms`, `1s` (time units) | `<time>` |
|
|
655
|
+
| `#name` tokens (by naming convention) | `<color>` |
|
|
599
656
|
|
|
600
657
|
Auto-inferred properties use `inherits: true` (the CSS default). Use explicit `@property` when you need different settings:
|
|
601
658
|
|
|
@@ -627,11 +684,11 @@ configure({ autoPropertyTypes: false });
|
|
|
627
684
|
|
|
628
685
|
Override or extend the built-in style property handlers. A handler definition can take three forms:
|
|
629
686
|
|
|
630
|
-
| Form
|
|
631
|
-
|
|
632
|
-
| Function only | `handler`
|
|
633
|
-
| Single dep
|
|
634
|
-
| Multi dep
|
|
687
|
+
| Form | Syntax | Description |
|
|
688
|
+
| ------------- | ---------------------------------- | --------------------------------------------------------------- |
|
|
689
|
+
| Function only | `handler` | Triggered by its key name; receives only that property |
|
|
690
|
+
| Single dep | `['styleName', handler]` | Triggered by the specified style property |
|
|
691
|
+
| Multi dep | `[['dep1', 'dep2', ...], handler]` | Triggered by any of the listed properties; receives all of them |
|
|
635
692
|
|
|
636
693
|
The multi-dep form is useful when output depends on several style properties together (e.g., `gap` needs to know `display` and `flow` to decide the CSS strategy). Use `defineHandler` for it and the dependency types are inferred from the dependency list, so a typo in the destructure is a type error instead of a silent `undefined`.
|
|
637
694
|
|
|
@@ -653,11 +710,19 @@ configure({
|
|
|
653
710
|
// them all through, or the ones you leave out stop working (see below).
|
|
654
711
|
fill: defineHandler(
|
|
655
712
|
[
|
|
656
|
-
'fill',
|
|
657
|
-
'
|
|
713
|
+
'fill',
|
|
714
|
+
'backgroundColor',
|
|
715
|
+
'image',
|
|
716
|
+
'backgroundImage',
|
|
717
|
+
'backgroundPosition',
|
|
718
|
+
'backgroundSize',
|
|
719
|
+
'backgroundRepeat',
|
|
658
720
|
],
|
|
659
721
|
(props) => {
|
|
660
|
-
if (
|
|
722
|
+
if (
|
|
723
|
+
typeof props.fill === 'string' &&
|
|
724
|
+
props.fill.startsWith('gradient:')
|
|
725
|
+
) {
|
|
661
726
|
return { background: props.fill.slice(9) };
|
|
662
727
|
}
|
|
663
728
|
return styleHandlers.fill(props);
|
|
@@ -691,18 +756,18 @@ Built-in handlers are shared across several style names. Registering a handler f
|
|
|
691
756
|
|
|
692
757
|
The shared groups worth knowing:
|
|
693
758
|
|
|
694
|
-
| Registering a handler for
|
|
695
|
-
|
|
696
|
-
| `fill`
|
|
697
|
-
| `display`
|
|
698
|
-
| `preset`
|
|
699
|
-
| `padding` / `margin` / `inset` | their `*Top`/`*Right`/`*Bottom`/`*Left`/`*Block`/`*Inline` longhands
|
|
759
|
+
| Registering a handler for | Also takes over |
|
|
760
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------- |
|
|
761
|
+
| `fill` | `backgroundColor`, `image`, `backgroundImage`, `backgroundPosition`, `backgroundSize`, `backgroundRepeat` |
|
|
762
|
+
| `display` | `hide`, `overflow`, `whiteSpace`, `textOverflow`, `flow`, `gap` |
|
|
763
|
+
| `preset` | `font`, `fontSize`, `fontWeight`, `fontStyle`, `lineHeight`, `letterSpacing`, `textTransform` |
|
|
764
|
+
| `padding` / `margin` / `inset` | their `*Top`/`*Right`/`*Bottom`/`*Left`/`*Block`/`*Inline` longhands |
|
|
700
765
|
|
|
701
766
|
Either declare the whole group and delegate the rest to `styleHandlers.*`, or pick a name that isn't shared.
|
|
702
767
|
|
|
703
768
|
### Chunk membership
|
|
704
769
|
|
|
705
|
-
Tasty renders and caches CSS in independent chunks, and a chunk's cache key covers only its own style values. All of a handler's dependencies must therefore live in one chunk. Custom style names are pulled into their handler's chunk automatically at registration; a handler whose dependencies span two
|
|
770
|
+
Tasty renders and caches CSS in independent chunks, and a chunk's cache key covers only its own style values. All of a handler's dependencies must therefore live in one chunk. Custom style names are pulled into their handler's chunk automatically at registration; a handler whose dependencies span two _built-in_ chunks (say `fill` and `padding`) warns, because it would be invoked once per chunk with a subset of its inputs.
|
|
706
771
|
|
|
707
772
|
`configure({ handlers })` must run before the first render, like every other config option.
|
|
708
773
|
|
|
@@ -710,7 +775,7 @@ Tasty renders and caches CSS in independent chunks, and a chunk's cache key cove
|
|
|
710
775
|
|
|
711
776
|
## Props Middleware
|
|
712
777
|
|
|
713
|
-
`propHandlers` are middleware over a component's props — props in, props out. Where a style
|
|
778
|
+
`propHandlers` are middleware over a component's props — props in, props out. Where a style _handler_ turns a style property into CSS declarations, a prop handler turns a **component prop** into other props, including `styles`. It is the extension point for props whose value isn't a style value.
|
|
714
779
|
|
|
715
780
|
```jsx
|
|
716
781
|
import { configure, mergeStyles } from '@tenphi/tasty';
|
|
@@ -726,7 +791,7 @@ configure({
|
|
|
726
791
|
},
|
|
727
792
|
});
|
|
728
793
|
|
|
729
|
-
<Element glaze="purple"
|
|
794
|
+
<Element glaze="purple" />;
|
|
730
795
|
```
|
|
731
796
|
|
|
732
797
|
The map key is the handler's name and, by default, the prop that triggers it, so an absent prop costs one property check rather than a call. A tuple overrides that: `['glaze', fn]`, `[['glaze', 'tint'], fn]`, or `['*', fn]` for unconditional.
|
|
@@ -735,7 +800,7 @@ Handlers run at the very top of every component's render, before any prop is des
|
|
|
735
800
|
|
|
736
801
|
Handlers must be **pure** and must not mutate their input, and should memoize the styles they build per input value: style values are cached by object identity, so mutating one in place yields stale CSS, and a reference-stable object avoids re-serializing on every render.
|
|
737
802
|
|
|
738
|
-
Injected styles occupy the `styles` slot, so they beat a component's own default styles and lose to a style prop at the call site. Prop handlers do not apply to sub-elements or to
|
|
803
|
+
Injected styles occupy the `styles` slot, so they beat a component's own default styles and lose to a style prop at the call site. Prop handlers do not apply to sub-elements or to build-time `tastyStatic()`, which has no props.
|
|
739
804
|
|
|
740
805
|
See [Plugins → Props middleware](plugins.md#props-middleware) for the full contract and a worked example.
|
|
741
806
|
|
|
@@ -748,7 +813,7 @@ See [Plugins → Props middleware](plugins.md#props-middleware) for the full con
|
|
|
748
813
|
```jsx
|
|
749
814
|
configure({ baseStyleProps: ['radius', 'shadow'] });
|
|
750
815
|
|
|
751
|
-
<Card radius="1r" shadow
|
|
816
|
+
<Card radius="1r" shadow />;
|
|
752
817
|
```
|
|
753
818
|
|
|
754
819
|
`configure()` may run after your components are defined — each factory resolves its prop list lazily.
|
package/docs/debug.md
CHANGED
|
@@ -6,9 +6,7 @@ Runtime CSS inspection and diagnostics for the Tasty styling system. Inspect inj
|
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
`tastyDebug` is a diagnostic object that exposes Tasty's runtime CSS state. It is designed for development use
|
|
10
|
-
|
|
11
|
-
In development mode (`isDevEnv()` returns `true`), `tastyDebug` is automatically installed on `window.tastyDebug`. In production, install it manually when needed.
|
|
9
|
+
`tastyDebug` is a diagnostic object that exposes Tasty's runtime CSS state. It is designed for development use and can be installed on `window` explicitly when needed.
|
|
12
10
|
|
|
13
11
|
All methods **log to the console by default**. Pass `{ raw: true }` to suppress logging and only return data.
|
|
14
12
|
|
|
@@ -19,7 +17,6 @@ All methods **log to the console by default**. Pass `{ raw: true }` to suppress
|
|
|
19
17
|
## Quick Start
|
|
20
18
|
|
|
21
19
|
```typescript
|
|
22
|
-
// Auto-installed in dev mode. Otherwise:
|
|
23
20
|
import { tastyDebug } from '@tenphi/tasty';
|
|
24
21
|
tastyDebug.install();
|
|
25
22
|
|
|
@@ -54,6 +51,19 @@ interface DebugOptions {
|
|
|
54
51
|
|
|
55
52
|
When `raw` is `false` (the default), results are logged to the console **and** returned. When `raw` is `true`, results are returned silently.
|
|
56
53
|
|
|
54
|
+
### Environments Without a DOM
|
|
55
|
+
|
|
56
|
+
`tastyDebug` reads the document, so on a server — SSR, a Node REPL, a test
|
|
57
|
+
runner in the `node` environment — there is nothing for it to read. Every
|
|
58
|
+
method returns its empty result (`''`, an empty `InspectResult`, a summary of
|
|
59
|
+
zeroes, `metrics: null`) instead of throwing, and explains itself once with a
|
|
60
|
+
console warning. `{ raw: true }` suppresses that warning along with the rest of
|
|
61
|
+
the logging.
|
|
62
|
+
|
|
63
|
+
To see the styles a server render produced, read the `ServerStyleCollector`
|
|
64
|
+
instead — `collector.getCSS()` and `collector.getRenderedClassNames()`. See
|
|
65
|
+
[SSR](./ssr.md).
|
|
66
|
+
|
|
57
67
|
---
|
|
58
68
|
|
|
59
69
|
## API Reference
|
|
@@ -68,7 +78,7 @@ Retrieves CSS text for a given target. Logs the result with rule count and size.
|
|
|
68
78
|
|---|---|
|
|
69
79
|
| `'all'` | All tasty CSS (component + global + raw) |
|
|
70
80
|
| `'active'` | CSS for classes currently in the DOM |
|
|
71
|
-
| `'unused'` | CSS
|
|
81
|
+
| `'unused'` | CSS for injected classes no element carries (cached but not rendered) |
|
|
72
82
|
| `'global'` | Only global CSS (from `injectGlobal`) |
|
|
73
83
|
| `'page'` | All CSS on the page (including non-tasty) |
|
|
74
84
|
| `'t3a5f'` | CSS for a specific tasty class (class names are `t` + base36 hash) |
|
|
@@ -241,7 +251,9 @@ tastyDebug.cache();
|
|
|
241
251
|
|
|
242
252
|
### `cleanup(opts?): void`
|
|
243
253
|
|
|
244
|
-
|
|
254
|
+
Removes every injected style that is neither carried by an element nor pinned by
|
|
255
|
+
an outstanding `inject()` handle — the same set `summary()` reports as unused.
|
|
256
|
+
Equivalent to `gc({ force: true })`.
|
|
245
257
|
|
|
246
258
|
```typescript
|
|
247
259
|
tastyDebug.cleanup();
|
|
@@ -262,7 +274,7 @@ tastyDebug.help();
|
|
|
262
274
|
|
|
263
275
|
### `install(): void`
|
|
264
276
|
|
|
265
|
-
Attaches `tastyDebug` to `window.tastyDebug`.
|
|
277
|
+
Attaches `tastyDebug` to `window.tastyDebug`.
|
|
266
278
|
|
|
267
279
|
```typescript
|
|
268
280
|
import { tastyDebug } from '@tenphi/tasty';
|