@tenphi/tasty 3.0.2 → 3.2.0

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.
Files changed (51) hide show
  1. package/README.md +1 -0
  2. package/dist/{babel-R2qT7yLN.d.ts → babel-D8dm92E_.d.ts} +2 -2
  3. package/dist/{collector-D8o4Wdq-.d.ts → collector-BFuqdF2F.d.ts} +2 -2
  4. package/dist/{collector-BpkjNQDo.js → collector-Di3C8btw.js} +3 -3
  5. package/dist/{collector-BpkjNQDo.js.map → collector-Di3C8btw.js.map} +1 -1
  6. package/dist/{config-DOCuTykY.js → config-BrDt11hO.js} +861 -290
  7. package/dist/config-BrDt11hO.js.map +1 -0
  8. package/dist/{config-De8L9NWM.d.ts → config-DH7I0Ggx.d.ts} +73 -2
  9. package/dist/core/index.d.ts +5 -5
  10. package/dist/core/index.js +6 -6
  11. package/dist/{core-p6iTbQnn.js → core-YWn1zgh4.js} +9 -10
  12. package/dist/core-YWn1zgh4.js.map +1 -0
  13. package/dist/{css-writer-BHjTF0YN.js → css-writer-CQYbT4g_.js} +3 -3
  14. package/dist/{css-writer-BHjTF0YN.js.map → css-writer-CQYbT4g_.js.map} +1 -1
  15. package/dist/{format-rules-Cb0YIjyS.js → format-rules-DdmLdntR.js} +11 -9
  16. package/dist/format-rules-DdmLdntR.js.map +1 -0
  17. package/dist/{hydrate-xnaB3SDm.js → hydrate-D2ivfS-B.js} +2 -2
  18. package/dist/{hydrate-xnaB3SDm.js.map → hydrate-D2ivfS-B.js.map} +1 -1
  19. package/dist/{index-DzGxoeyN.d.ts → index-DljBkZhV.d.ts} +59 -6
  20. package/dist/{index-KUYya3x7.d.ts → index-LC3O3Jj4.d.ts} +102 -2
  21. package/dist/index.d.ts +5 -5
  22. package/dist/index.js +62 -8
  23. package/dist/index.js.map +1 -1
  24. package/dist/{keyframes-DiXjNoBZ.js → keyframes-CoLLjBcd.js} +2 -2
  25. package/dist/{keyframes-DiXjNoBZ.js.map → keyframes-CoLLjBcd.js.map} +1 -1
  26. package/dist/{merge-styles-DLm4wdnb.d.ts → merge-styles-Cx_6ySBv.d.ts} +2 -2
  27. package/dist/{merge-styles-B0lMso5W.js → merge-styles-bdh7-1uh.js} +2 -2
  28. package/dist/{merge-styles-B0lMso5W.js.map → merge-styles-bdh7-1uh.js.map} +1 -1
  29. package/dist/{resolve-recipes-C9nAuwgR.js → resolve-recipes-9JYSgubn.js} +3 -3
  30. package/dist/{resolve-recipes-C9nAuwgR.js.map → resolve-recipes-9JYSgubn.js.map} +1 -1
  31. package/dist/ssr/astro-client.js +1 -1
  32. package/dist/ssr/astro.js +3 -3
  33. package/dist/ssr/index.d.ts +1 -1
  34. package/dist/ssr/index.js +3 -3
  35. package/dist/ssr/next.d.ts +1 -1
  36. package/dist/ssr/next.js +4 -4
  37. package/dist/static/index.d.ts +2 -2
  38. package/dist/static/index.js +1 -1
  39. package/dist/zero/babel.d.ts +1 -1
  40. package/dist/zero/babel.js +4 -4
  41. package/dist/zero/index.d.ts +1 -1
  42. package/dist/zero/index.js +1 -1
  43. package/dist/zero/next.d.ts +1 -1
  44. package/docs/configuration.md +137 -6
  45. package/docs/dsl.md +99 -2
  46. package/docs/injector.md +11 -0
  47. package/docs/styles.md +3 -1
  48. package/package.json +6 -6
  49. package/dist/config-DOCuTykY.js.map +0 -1
  50. package/dist/core-p6iTbQnn.js.map +0 -1
  51. package/dist/format-rules-Cb0YIjyS.js.map +0 -1
package/docs/dsl.md CHANGED
@@ -111,7 +111,7 @@ const List = tasty({
111
111
  Named color prefixed with `#` that maps to CSS custom properties. Supports opacity with `.N` suffix:
112
112
 
113
113
  ```jsx
114
- fill: '#purple.5' // → var(--purple-color) with 50% opacity
114
+ fill: '#purple.5' // → oklch(from var(--purple-color) l c h / .5)
115
115
  ```
116
116
 
117
117
  ### Modifier
@@ -133,11 +133,108 @@ Modifiers can also be exposed as top-level component props via `modProps` — se
133
133
  color: '#purple', // Full opacity
134
134
  color: '#purple.5', // 50% opacity
135
135
  color: '#purple.05', // 5% opacity
136
+ color: '#purple.$fade', // Opacity from a custom property
136
137
  fill: '#current', // → currentcolor
137
- fill: '#current.5', // → color-mix(in oklab, currentcolor 50%, transparent)
138
138
  color: '(#primary, #secondary)', // Fallback syntax
139
139
  ```
140
140
 
141
+ The suffix sets the alpha on the token's color with CSS relative color syntax:
142
+
143
+ ```jsx
144
+ fill: '#purple.5';
145
+ // → oklch(from var(--purple-color) l c h / .5)
146
+ ```
147
+
148
+ The channels are copied over and the alpha slot is written, which asks nothing of
149
+ the color beyond *being* a color. That means the suffix works on every one of
150
+ these:
151
+
152
+ - a token holding a `color-mix()`, a `light-dark()`, or a `color()` in a space
153
+ Tasty cannot convert — none of which have channels to decompose
154
+ - `#current`, which resolves to `currentcolor`
155
+ - a `--name-color` variable declared in your own CSS, with no Tasty token
156
+ definition and no companion variable behind it
157
+
158
+ Two properties follow from writing the alpha slot rather than compositing:
159
+
160
+ - **Alpha is replaced, not multiplied.** A token holding `rgb(255 0 0 / .8)`
161
+ faded to `.5` is alpha `.5`, not `.4`.
162
+ - **The alpha may be a number or a percentage.** `#purple.$fade` emits
163
+ `/ var(--fade)` unchanged, so it works whether `$fade` holds `.5` or `50%` —
164
+ which is what `--*-opacity` properties are registered to accept.
165
+
166
+ ### `#current` composes instead
167
+
168
+ `#current` is the one exception, and the difference is deliberate. A token *names*
169
+ a color, so fading it sets its alpha. `currentcolor` is the color an element
170
+ **inherits**, which an ancestor may already have faded — `#current.4` means "40%
171
+ of what reaches me":
172
+
173
+ ```jsx
174
+ fill: '#current.4';
175
+ // → color-mix(in oklab, currentcolor 40%, transparent)
176
+ ```
177
+
178
+ So a `#current` fade nested inside another one composes: a label at `#current.4`
179
+ with a fill of `#current.18` under it lands at `.072`. Color ramps built on
180
+ `#current` depend on that — replacing would double the opacity of every nested
181
+ step. Because a `color-mix()` percentage cannot be a `<number>`, an opacity
182
+ custom property used as `#current.$fade` must hold a unitless number; a token
183
+ accepts either form.
184
+
185
+ The space is always `oklch`, whatever [`colorSpace`](configuration.md#color-space)
186
+ is set to: it is unbounded, so a wide-gamut color survives a round trip that a
187
+ gamut-limited space would clamp.
188
+
189
+ ---
190
+
191
+ ## CSS Color Functions
192
+
193
+ Every CSS color function is recognized as a color, so it lands in the color slot
194
+ of whichever style property you use it in — and tokens inside it are expanded:
195
+
196
+ ```jsx
197
+ fill: 'color-mix(in oklab, #primary 50%, #surface)',
198
+ color: 'light-dark(#dark, #light)',
199
+ color: 'contrast-color(#primary)',
200
+ fill: 'color(display-p3 1 .5 0)',
201
+ border: '1bw solid oklch(from #primary l c h / 50%)', // relative color syntax
202
+ shadow: '0 0 1x color-mix(in oklab, #dark 20%, transparent)',
203
+ ```
204
+
205
+ `light-dark()` is the one exception to "always a color": CSS lets it pick between
206
+ values of any type, so it is treated as a color only when its arguments are
207
+ colors. `padding: 'light-dark(1x, 2x)'` still reaches the padding slot.
208
+
209
+ A color token defined as one of these functions takes the
210
+ [opacity suffix](#color-tokens--opacity) like any other:
211
+
212
+ ```jsx
213
+ const Card = tasty({
214
+ styles: {
215
+ '#brand': 'color-mix(in oklab, #primary 50%, #surface)',
216
+ fill: '#brand.5',
217
+ },
218
+ });
219
+ ```
220
+
221
+ A [replace token](configuration.md#replace-tokens-parse-time-substitution) is
222
+ substituted while parsing, so its color is right there to fade in place. A
223
+ channel function takes the alpha after a slash; a derived function has no alpha
224
+ channel, so it gets wrapped:
225
+
226
+ ```jsx
227
+ configure({
228
+ replaceTokens: {
229
+ '#solid': 'hsl(220 90% 50%)',
230
+ '#adaptive': 'light-dark(#dark, #light)',
231
+ },
232
+ });
233
+
234
+ fill: '#solid.5'; // → hsl(220 90% 50% / .5)
235
+ fill: '#adaptive.5'; // → oklch(from light-dark(…) l c h / .5)
236
+ ```
237
+
141
238
  ---
142
239
 
143
240
  ## Built-in Units
package/docs/injector.md CHANGED
@@ -300,6 +300,17 @@ const styleRule: StyleResult = {
300
300
  };
301
301
  ```
302
302
 
303
+ ### Batched Injection
304
+
305
+ `configure({ batchInjection: true })` queues every sheet write — component
306
+ rules, global rules, raw CSS and at-rules — into one FIFO and applies them
307
+ together, so the document is style-invalidated once per flush instead of once per
308
+ component. `<TastyBatchProvider>` flushes in `useInsertionEffect`, before any
309
+ layout effect, so a queued write can never be observed by a measurement. See
310
+ [Batched injection](configuration.md#batched-injection) for the modes and the
311
+ ordering guarantee. `flushStyles()` applies pending writes on demand; every read
312
+ API here calls it for you.
313
+
303
314
  ### Deduplication & Performance
304
315
 
305
316
  ```typescript
package/docs/styles.md CHANGED
@@ -254,6 +254,7 @@ Background color with design token support. Preferred over `backgroundColor` and
254
254
  | `"#purple.10"` | Token color at 10% opacity |
255
255
  | `"#surface #primary.10"` | Background `#surface` with `#primary.10` overlay (two colors enable smooth transitions between both) |
256
256
  | `"rgb(255 128 0)"` | CSS color value |
257
+ | `"color-mix(in oklab, #primary 50%, #surface)"` | CSS color function — see [CSS Color Functions](dsl.md#css-color-functions) |
257
258
  | `true` | Default fill color |
258
259
 
259
260
  When two colors are provided, the first sets the background color and the second is applied as an overlay gradient layer. This enables independent CSS transitions on each color. The overlay is only applied when no explicit `image` or `backgroundImage` is set.
@@ -286,9 +287,10 @@ Text color with design token support.
286
287
  | `"#current"` | Current inherited color |
287
288
  | `"#current.5"` | Current inherited color at 50% opacity |
288
289
  | `"(#primary, #secondary)"` | Fallback: use `#primary`, fall back to `#secondary` |
290
+ | `"light-dark(#dark, #light)"` | CSS color function — see [CSS Color Functions](dsl.md#css-color-functions) |
289
291
  | `true` | `currentColor` |
290
292
 
291
- When set to a named color token, also sets `$current-color` and `$current-color-{colorSpace}` custom properties for downstream use (suffix depends on the configured `colorSpace`, default `oklch`).
293
+ When set to a named color token, also sets `$current-color` and `$current-color-{colorSpace}` custom properties for downstream use (suffix depends on the configured `colorSpace`, default `oklch`). An opacity suffix does not move the companion: `color="#purple.5"` still reports `#purple`'s channels, since components carry no alpha.
292
294
 
293
295
  ### `svgFill`
294
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenphi/tasty",
3
- "version": "3.0.2",
3
+ "version": "3.2.0",
4
4
  "description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -178,19 +178,19 @@
178
178
  "name": "main (import *)",
179
179
  "path": "dist/index.js",
180
180
  "import": "*",
181
- "limit": "57.5 kB"
181
+ "limit": "59 kB"
182
182
  },
183
183
  {
184
184
  "name": "core (import *)",
185
185
  "path": "dist/core/index.js",
186
186
  "import": "*",
187
- "limit": "54.5 kB"
187
+ "limit": "55.75 kB"
188
188
  },
189
189
  {
190
190
  "name": "static",
191
191
  "path": "dist/static/index.js",
192
192
  "import": "*",
193
- "limit": "18.75 kB"
193
+ "limit": "19.25 kB"
194
194
  },
195
195
  {
196
196
  "name": "zero",
@@ -201,7 +201,7 @@
201
201
  "path",
202
202
  "crypto"
203
203
  ],
204
- "limit": "33.25 kB"
204
+ "limit": "33.75 kB"
205
205
  },
206
206
  {
207
207
  "name": "babel-plugin",
@@ -212,7 +212,7 @@
212
212
  "path",
213
213
  "crypto"
214
214
  ],
215
- "limit": "50.75 kB"
215
+ "limit": "52 kB"
216
216
  }
217
217
  ],
218
218
  "scripts": {