@tenphi/tasty 2.11.2 → 3.0.1
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 +32 -7
- package/dist/babel-HlEpSZrj.d.ts +83 -0
- package/dist/{collector-yqgjGje7.d.ts → collector-BPzZezAG.d.ts} +36 -5
- package/dist/{collector-D0cgyN6N.js → collector-D14DcZx9.js} +65 -10
- package/dist/collector-D14DcZx9.js.map +1 -0
- package/dist/{config-_cYm9LPl.js → config-CCcE_tqx.js} +2906 -1778
- package/dist/config-CCcE_tqx.js.map +1 -0
- package/dist/{config-V0XC9iz_.d.ts → config-D2INrjr_.d.ts} +239 -25
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +6 -6
- package/dist/{core-DdjoZG0r.js → core-B5d0IPi2.js} +69 -131
- package/dist/core-B5d0IPi2.js.map +1 -0
- package/dist/{css-writer-DTUwLjgD.js → css-writer-B5DBoxhf.js} +54 -15
- package/dist/css-writer-B5DBoxhf.js.map +1 -0
- package/dist/{format-rules-Bu_qoamZ.js → format-rules-BbKDjsfO.js} +2 -2
- package/dist/{format-rules-Bu_qoamZ.js.map → format-rules-BbKDjsfO.js.map} +1 -1
- package/dist/{hydrate-CKk-rgmY.js → hydrate-CwALW3J9.js} +3 -11
- package/dist/{hydrate-CKk-rgmY.js.map → hydrate-CwALW3J9.js.map} +1 -1
- package/dist/{index-BjnGYI5D.d.ts → index-BAAbdfRs.d.ts} +217 -150
- package/dist/{index-tRick_JW.d.ts → index-l_NdJSUS.d.ts} +161 -61
- package/dist/index.d.ts +5 -5
- package/dist/index.js +75 -11
- package/dist/index.js.map +1 -1
- package/dist/{keyframes-5LJYS8_P.js → keyframes-B8M1FmtE.js} +10 -181
- package/dist/keyframes-B8M1FmtE.js.map +1 -0
- package/dist/{merge-styles-Blrs8kLM.js → merge-styles--1zOSFlS.js} +2 -2
- package/dist/{merge-styles-Blrs8kLM.js.map → merge-styles--1zOSFlS.js.map} +1 -1
- package/dist/{merge-styles-DDss7wRH.d.ts → merge-styles-NEvqayL_.d.ts} +2 -2
- package/dist/{resolve-recipes-DR5cSG3X.js → resolve-recipes-Caix5NnH.js} +3 -3
- package/dist/{resolve-recipes-DR5cSG3X.js.map → resolve-recipes-Caix5NnH.js.map} +1 -1
- package/dist/ssr/astro-client.js +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 +1 -5
- package/dist/ssr/astro.js +25 -15
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/index.d.ts +2 -9
- package/dist/ssr/index.js +4 -4
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +1 -1
- package/dist/ssr/next.js +5 -6
- package/dist/ssr/next.js.map +1 -1
- package/dist/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/zero/babel.d.ts +2 -80
- package/dist/zero/babel.js +27 -23
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +16 -2
- package/dist/zero/index.js +2 -2
- 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 +3 -1
- package/docs/ai-agents.md +21 -7
- package/docs/configuration.md +220 -30
- package/docs/debug.md +7 -7
- package/docs/design-system.md +2 -2
- package/docs/dsl.md +68 -8
- package/docs/injector.md +31 -4
- package/docs/methodology.md +1 -1
- package/docs/migration-v3.md +285 -0
- package/docs/pipeline.md +3 -3
- package/docs/plugins.md +349 -0
- package/docs/react-api.md +61 -1
- package/docs/ssr.md +41 -33
- package/docs/styles.md +27 -9
- package/docs/tasty-static.md +8 -6
- package/package.json +20 -8
- package/tasty.config.ts +4 -0
- package/dist/collector-D0cgyN6N.js.map +0 -1
- package/dist/config-_cYm9LPl.js.map +0 -1
- package/dist/core-DdjoZG0r.js.map +0 -1
- package/dist/css-writer-DTUwLjgD.js.map +0 -1
- package/dist/keyframes-5LJYS8_P.js.map +0 -1
package/docs/styles.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Style Properties Reference
|
|
2
2
|
|
|
3
|
-
All standard CSS properties are supported in Tasty and benefit from its syntax sugar: design tokens (`$name`, `#name`), custom units (`2x`, `1r`, `1bw`), color opacity (`#purple.5`), auto-calc (`(100% - 2x)`), and custom functions. Values are parsed through the Tasty engine automatically.
|
|
3
|
+
All standard CSS properties are supported in Tasty and benefit from its syntax sugar: design tokens (`$name`, `#name`), custom units (`2x`, `1r`, `1bw`), color opacity (`#purple.5`), auto-calc (`(100% - 2x)`), and [custom functions](dsl.md#functions-function) (`$$negative(10px)`). Values are parsed through the Tasty engine automatically.
|
|
4
4
|
|
|
5
5
|
The properties documented below have **custom handlers** with enhanced syntax. They should be **preferred** over their raw CSS equivalents because they:
|
|
6
6
|
|
|
@@ -100,18 +100,23 @@ For flex/grid layouts, outputs native `gap`. For block layouts, emulates gap usi
|
|
|
100
100
|
|
|
101
101
|
Element padding with directional modifiers and multi-group support. Use **comma-separated groups** to set a base value and then override specific directions.
|
|
102
102
|
|
|
103
|
-
**Syntax:** `[value]` | `[
|
|
103
|
+
**Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
|
|
104
104
|
|
|
105
105
|
**Direction modifiers:** `top`, `right`, `bottom`, `left`
|
|
106
106
|
|
|
107
107
|
**Output modifier:** `longhand` — forces output as individual CSS longhand properties (`padding-top`, `padding-right`, `padding-bottom`, `padding-left`) instead of the `padding` shorthand. Useful when children need to selectively inherit individual directions.
|
|
108
108
|
|
|
109
|
+
**One value per directional group.** A group that names direction modifiers takes **exactly one** value, applied to every direction it names. For different values per side, use comma-separated groups: `padding: '2x top, 4x right'`. Writing `padding: '2x 4x top right'` ignores `4x` and warns in development — the parser keeps values and modifiers in separate buckets, so their interleaving in the source is not recoverable and `'2x 4x top right'`, `'2x top 4x right'` and `'top 2x right 4x'` are all the same input.
|
|
110
|
+
|
|
111
|
+
A group that names *no* direction keeps plain CSS shorthand order, which is unambiguous and unchanged.
|
|
112
|
+
|
|
109
113
|
| Value | Effect |
|
|
110
114
|
|-------|--------|
|
|
111
115
|
| `"2x"` | All sides `2x` |
|
|
112
116
|
| `"2x 1x"` | Top/bottom `2x`, left/right `1x` |
|
|
113
117
|
| `"2x top"` | Top `2x`, right/bottom/left `0` |
|
|
114
118
|
| `"1x left right"` | Left and right `1x`, top/bottom `0` |
|
|
119
|
+
| `"2x top, 4x right"` | Top `2x`, right `4x`, bottom/left `0` |
|
|
115
120
|
| `"1x, 2x top"` | All sides `1x`, then top overridden to `2x` |
|
|
116
121
|
| `"1x, 2x top bottom"` | Left/right `1x`, top/bottom `2x` |
|
|
117
122
|
| `"2x longhand"` | All sides `2x`, output as 4 individual `padding-*` properties |
|
|
@@ -128,17 +133,20 @@ Individual props `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft`, `
|
|
|
128
133
|
|
|
129
134
|
Element margin. Same syntax, modifiers, and multi-group support as `padding`.
|
|
130
135
|
|
|
131
|
-
**Syntax:** `[value]` | `[
|
|
136
|
+
**Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
|
|
132
137
|
|
|
133
138
|
**Direction modifiers:** `top`, `right`, `bottom`, `left`
|
|
134
139
|
|
|
135
140
|
**Output modifier:** `longhand` — forces output as individual CSS longhand properties (`margin-top`, etc.) instead of the `margin` shorthand.
|
|
136
141
|
|
|
142
|
+
The [one-value-per-directional-group rule](#padding) from `padding` applies here too.
|
|
143
|
+
|
|
137
144
|
| Value | Effect |
|
|
138
145
|
|-------|--------|
|
|
139
146
|
| `"2x"` | All sides `2x` |
|
|
140
147
|
| `"2x 1x"` | Top/bottom `2x`, left/right `1x` |
|
|
141
148
|
| `"2x top"` | Top `2x`, right/bottom/left `0` |
|
|
149
|
+
| `"2x top, 4x right"` | Top `2x`, right `4x`, bottom/left `0` |
|
|
142
150
|
| `"auto left right, 1x top bottom"` | Left/right `auto`, top/bottom `1x` |
|
|
143
151
|
| `true` | All sides `1x` |
|
|
144
152
|
| Number | Converted to `px` |
|
|
@@ -191,17 +199,22 @@ Separate `minHeight` and `maxHeight` props are supported and override values fro
|
|
|
191
199
|
|
|
192
200
|
Positioning offsets with directional modifiers and multi-group support. Same directional syntax as `padding`.
|
|
193
201
|
|
|
194
|
-
**Syntax:** `[value]` | `[
|
|
202
|
+
**Syntax:** `[value]` | `[block inline]` | `[top right bottom left]` | `[value direction...]` — comma-separated for multiple groups
|
|
195
203
|
|
|
196
204
|
**Direction modifiers:** `top`, `right`, `bottom`, `left`
|
|
197
205
|
|
|
206
|
+
The [one-value-per-directional-group rule](#padding) from `padding` applies here too, with `dock`
|
|
207
|
+
as the single exception.
|
|
208
|
+
|
|
198
209
|
**`dock` modifier:** pins the named edge and spans its full length, by also applying the value
|
|
199
210
|
to the two perpendicular sides. `inset: 'bottom dock'` gives `inset: auto 0 0 0` — anchored to
|
|
200
211
|
the bottom, full width. Without a direction, `dock` fills every side.
|
|
201
212
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
213
|
+
`dock` is the one place a directional group takes **two** values: the first insets the named
|
|
214
|
+
edge, the second the sides it spans. `inset: '2x 4x bottom dock'` pins the bottom at `2x` and
|
|
215
|
+
insets the sides by `4x`. A third value, or a second value without `dock`, is ignored and warns
|
|
216
|
+
in development. With several directions the first value applies to each named edge and the
|
|
217
|
+
second to every side they span.
|
|
205
218
|
|
|
206
219
|
**Output modifier:** `longhand` — forces output as individual CSS properties (`top`, `right`, `bottom`, `left`) instead of the `inset` shorthand.
|
|
207
220
|
|
|
@@ -572,15 +585,20 @@ Scrollbar styling using CSS standard properties (`scrollbar-width`, `scrollbar-c
|
|
|
572
585
|
|
|
573
586
|
Gradient-based edge fading using CSS masks. Use **comma-separated groups** to set different widths and colors per direction.
|
|
574
587
|
|
|
575
|
-
**Syntax:** `[width] [
|
|
588
|
+
**Syntax:** `[width] [direction...] [#from-color] [#to-color]` — comma-separated for multiple groups
|
|
576
589
|
|
|
577
590
|
**Direction modifiers:** `top`, `right`, `bottom`, `left`
|
|
578
591
|
|
|
592
|
+
A group that names edges takes a **single** width, applied to every edge it names — different
|
|
593
|
+
widths per edge come from comma groups. A group that names no edge covers all four and keeps
|
|
594
|
+
plain CSS shorthand order, like `padding`. See the [`padding` rule](#padding).
|
|
595
|
+
|
|
579
596
|
| Value | Effect |
|
|
580
597
|
|-------|--------|
|
|
581
598
|
| `"top"` | Fade top edge, default width (`2x`), all other edges unfaded |
|
|
582
599
|
| `"2x left right"` | Fade left and right edges with `2x` width, top/bottom unfaded |
|
|
583
|
-
| `"3x 1x
|
|
600
|
+
| `"3x 1x"` | All edges faded — top/bottom `3x`, left/right `1x` (CSS shorthand order) |
|
|
601
|
+
| `"3x top, 1x bottom"` | Fade top with `3x` width, bottom with `1x` width |
|
|
584
602
|
| `"2x #transparent #dark"` | All edges faded with `2x` width, from `#transparent` to `#dark` |
|
|
585
603
|
| `"top #a #b, bottom #c #d"` | Top fades from `#a` to `#b`, bottom fades from `#c` to `#d` |
|
|
586
604
|
|
package/docs/tasty-static.md
CHANGED
|
@@ -20,7 +20,7 @@ The zero-runtime mode is part of the main `@tenphi/tasty` package but requires a
|
|
|
20
20
|
| `@babel/core` | >= 7.24 | Babel plugin (`@tenphi/tasty/babel-plugin`) |
|
|
21
21
|
| `@babel/helper-plugin-utils` | >= 7.24 | Babel plugin |
|
|
22
22
|
| `@babel/types` | >= 7.24 | Babel plugin |
|
|
23
|
-
| `jiti` | >= 2.6 | Next.js wrapper (`@tenphi/tasty/next`) when using `configFile` option |
|
|
23
|
+
| `jiti` | >= 2.6 | Next.js wrapper (`@tenphi/tasty/zero/next`) when using `configFile` option |
|
|
24
24
|
|
|
25
25
|
All of these are declared as optional peer dependencies of `@tenphi/tasty`. Install only what your setup requires:
|
|
26
26
|
|
|
@@ -168,10 +168,11 @@ module.exports = {
|
|
|
168
168
|
| `config.replaceTokens` | `Record<string, string \| number>` | — | Parse-time token substitution. Keys use `$name` for custom properties and `#name` for color tokens. |
|
|
169
169
|
| `config.recipes` | `Record<string, RecipeStyles>` | `{}` | Predefined style recipes |
|
|
170
170
|
| `config.keyframes` | `Record<string, KeyframesSteps>` | — | Global `@keyframes` definitions available to all `tastyStatic` calls |
|
|
171
|
-
| `config.
|
|
172
|
-
| `config.
|
|
171
|
+
| `config.fontFaces` | `Record<string, FontFaceInput>` | — | Global `@font-face` definitions |
|
|
172
|
+
| `config.counterStyles` | `Record<string, CounterStyleDescriptors>` | — | Global `@counter-style` definitions |
|
|
173
173
|
| `config.units` | `Record<string, string \| UnitHandler>` | — | Custom units for the style parser (merged with built-ins). E.g. `{ em: 'em', vw: 'vw' }` |
|
|
174
|
-
| `config.
|
|
174
|
+
| `config.functions` | `Record<string, FunctionDefinition \| Function>` | — | Custom functions (merged). Bare keys → parse functions; `$$name` keys → declarative CSS `@function` definitions |
|
|
175
|
+
| `config.polyfills` | `{ functions?: boolean }` | `{}` | Opt-in polyfills. `functions: true` inlines `@function` calls into plain CSS at build time |
|
|
175
176
|
| `config.plugins` | `TastyPlugin[]` | — | Plugins that extend tasty with custom functions, units, states, and handlers |
|
|
176
177
|
| `config.handlers` | `Record<string, StyleHandlerDefinition>` | — | Custom style handlers that transform style properties into CSS declarations |
|
|
177
178
|
| `config.presets` | `Record<string, TypographyPreset>` | — | Typography presets — shorthand for `generateTypographyTokens()`. Generated tokens merge under explicit `tokens`. |
|
|
@@ -236,7 +237,7 @@ The `withTastyZero` wrapper configures both **webpack** and **Turbopack** automa
|
|
|
236
237
|
|
|
237
238
|
```typescript
|
|
238
239
|
// next.config.ts
|
|
239
|
-
import { withTastyZero } from '@tenphi/tasty/next';
|
|
240
|
+
import { withTastyZero } from '@tenphi/tasty/zero/next';
|
|
240
241
|
|
|
241
242
|
export default withTastyZero({
|
|
242
243
|
output: 'public/tasty.css',
|
|
@@ -395,7 +396,7 @@ With Next.js:
|
|
|
395
396
|
|
|
396
397
|
```typescript
|
|
397
398
|
// next.config.ts
|
|
398
|
-
import { withTastyZero } from '@tenphi/tasty/next';
|
|
399
|
+
import { withTastyZero } from '@tenphi/tasty/zero/next';
|
|
399
400
|
|
|
400
401
|
export default withTastyZero({
|
|
401
402
|
mode: 'inject',
|
|
@@ -545,3 +546,4 @@ const card = tastyStatic({
|
|
|
545
546
|
- [Style DSL](dsl.md) — State maps, tokens, units, extending semantics (shared by runtime and static)
|
|
546
547
|
- [React API](react-api.md) — Runtime styling: `tasty()` factory, component props, variants, sub-elements, style functions
|
|
547
548
|
- [Configuration](configuration.md) — Global configuration: tokens, recipes, custom units, and style handlers
|
|
549
|
+
- [Plugins & Extension Points](plugins.md) — Which extension points work at build time (`functions`, `units`, `states`, `handlers`, `recipes`) and which do not (`propHandlers` — `tastyStatic()` takes styles objects, not props)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenphi/tasty",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"import": "./dist/zero/index.js",
|
|
33
33
|
"default": "./dist/zero/index.js"
|
|
34
34
|
},
|
|
35
|
-
"./next": {
|
|
35
|
+
"./zero/next": {
|
|
36
36
|
"types": "./dist/zero/next.d.ts",
|
|
37
37
|
"import": "./dist/zero/next.js",
|
|
38
38
|
"default": "./dist/zero/next.js"
|
|
@@ -62,6 +62,16 @@
|
|
|
62
62
|
"import": "./dist/ssr/astro-client.js",
|
|
63
63
|
"default": "./dist/ssr/astro-client.js"
|
|
64
64
|
},
|
|
65
|
+
"./ssr/astro-middleware": {
|
|
66
|
+
"types": "./dist/ssr/astro-middleware.d.ts",
|
|
67
|
+
"import": "./dist/ssr/astro-middleware.js",
|
|
68
|
+
"default": "./dist/ssr/astro-middleware.js"
|
|
69
|
+
},
|
|
70
|
+
"./ssr/astro-middleware-static": {
|
|
71
|
+
"types": "./dist/ssr/astro-middleware-static.d.ts",
|
|
72
|
+
"import": "./dist/ssr/astro-middleware-static.js",
|
|
73
|
+
"default": "./dist/ssr/astro-middleware-static.js"
|
|
74
|
+
},
|
|
65
75
|
"./tasty.config": "./tasty.config.ts"
|
|
66
76
|
},
|
|
67
77
|
"files": [
|
|
@@ -73,7 +83,9 @@
|
|
|
73
83
|
"./dist/ssr/index.js",
|
|
74
84
|
"./dist/ssr/next.js",
|
|
75
85
|
"./dist/ssr/astro.js",
|
|
76
|
-
"./dist/ssr/astro-client.js"
|
|
86
|
+
"./dist/ssr/astro-client.js",
|
|
87
|
+
"./dist/ssr/astro-middleware.js",
|
|
88
|
+
"./dist/ssr/astro-middleware-static.js"
|
|
77
89
|
],
|
|
78
90
|
"engines": {
|
|
79
91
|
"node": ">=20"
|
|
@@ -166,19 +178,19 @@
|
|
|
166
178
|
"name": "main (import *)",
|
|
167
179
|
"path": "dist/index.js",
|
|
168
180
|
"import": "*",
|
|
169
|
-
"limit": "
|
|
181
|
+
"limit": "57 kB"
|
|
170
182
|
},
|
|
171
183
|
{
|
|
172
184
|
"name": "core (import *)",
|
|
173
185
|
"path": "dist/core/index.js",
|
|
174
186
|
"import": "*",
|
|
175
|
-
"limit": "
|
|
187
|
+
"limit": "54 kB"
|
|
176
188
|
},
|
|
177
189
|
{
|
|
178
190
|
"name": "static",
|
|
179
191
|
"path": "dist/static/index.js",
|
|
180
192
|
"import": "*",
|
|
181
|
-
"limit": "
|
|
193
|
+
"limit": "18.5 kB"
|
|
182
194
|
},
|
|
183
195
|
{
|
|
184
196
|
"name": "zero",
|
|
@@ -189,7 +201,7 @@
|
|
|
189
201
|
"path",
|
|
190
202
|
"crypto"
|
|
191
203
|
],
|
|
192
|
-
"limit": "
|
|
204
|
+
"limit": "33 kB"
|
|
193
205
|
},
|
|
194
206
|
{
|
|
195
207
|
"name": "babel-plugin",
|
|
@@ -200,7 +212,7 @@
|
|
|
200
212
|
"path",
|
|
201
213
|
"crypto"
|
|
202
214
|
],
|
|
203
|
-
"limit": "
|
|
215
|
+
"limit": "50.5 kB"
|
|
204
216
|
}
|
|
205
217
|
],
|
|
206
218
|
"scripts": {
|
package/tasty.config.ts
CHANGED
|
@@ -13,4 +13,8 @@ export default {
|
|
|
13
13
|
'$bold-font-weight',
|
|
14
14
|
],
|
|
15
15
|
styles: ['viewTransitionName'],
|
|
16
|
+
// This repo imports its own API relatively, so the plugin's default
|
|
17
|
+
// `@tenphi/tasty` import tracking never matches. List the local entry points so
|
|
18
|
+
// `tasty({ styles })` call sites are actually linted.
|
|
19
|
+
importSources: ['@tenphi/tasty', './tasty', '../tasty', './src/tasty'],
|
|
16
20
|
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collector-D0cgyN6N.js","names":[],"sources":["../src/ssr/collector.ts"],"sourcesContent":["/**\n * ServerStyleCollector — server-safe style collector for SSR.\n *\n * Accumulates CSS rules and cache metadata during server rendering.\n * This is the server-side counterpart to StyleInjector: it allocates\n * hash-based class names using the configured `namePrefix` (defaults\n * to `'t'`), formats CSS rules into text, and tracks rendered class\n * names for lightweight client transfer.\n *\n * One instance is created per HTTP request. Concurrent requests\n * each get their own collector (via AsyncLocalStorage or React context).\n */\n\nimport {\n getEffectiveProperties,\n getGlobalStyles,\n getGlobalCounterStyle,\n getGlobalFontFace,\n getGlobalConfigTokens,\n getNamePrefix,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport {\n makeClassName,\n makeCounterStyleName,\n makeKeyframeName,\n validateNamePrefix,\n} from '../utils/name-prefix';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nexport class ServerStyleCollector {\n private chunks = new Map<string, string>();\n private cacheKeyToClassName = new Map<string, string>();\n private flushedKeys = new Set<string>();\n private propertyRules = new Map<string, string>();\n private flushedPropertyKeys = new Set<string>();\n private keyframeRules = new Map<string, string>();\n private flushedKeyframeKeys = new Set<string>();\n private globalStyles = new Map<string, string>();\n private flushedGlobalKeys = new Set<string>();\n private rawCSS = new Map<string, string>();\n private flushedRawKeys = new Set<string>();\n private fontFaceRules = new Map<string, string>();\n private flushedFontFaceKeys = new Set<string>();\n private counterStyleRules = new Map<string, string>();\n private flushedCounterStyleKeys = new Set<string>();\n private keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\n private namePrefix: string;\n\n /**\n * @param namePrefix - Optional override for the configured prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n * Pass an explicit prefix when constructing a collector outside the\n * normal configure() lifecycle (e.g. in tests). Validated eagerly\n * so misconfiguration fails before any CSS is collected.\n */\n constructor(namePrefix?: string) {\n if (namePrefix !== undefined) {\n validateNamePrefix(namePrefix);\n }\n this.namePrefix = namePrefix ?? getNamePrefix();\n }\n\n private generateClassName(cacheKey: string): string {\n return makeClassName(this.namePrefix, hashString(cacheKey));\n }\n\n /**\n * Collect internal @property rules and :root token defaults.\n * Mirrors markStylesGenerated() from the client-side injector.\n * Called automatically on first chunk collection; idempotent.\n *\n * Internals are always emitted here — the RSC path deliberately\n * defers to SSR so that tokens appear exactly once per page in\n * <style data-tasty-ssr> (avoiding duplication of large token sets).\n */\n collectInternals(): void {\n if (this.internalsCollected) return;\n this.internalsCollected = true;\n\n for (const [token, definition] of Object.entries(\n getEffectiveProperties(),\n )) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n this.collectProperty(`__prop:${token}`, css);\n }\n }\n\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const tokenRules = renderStyles(tokenStyles, ':root') as StyleResult[];\n if (tokenRules.length > 0) {\n const css = formatGlobalRules(tokenRules);\n if (css) {\n this.collectGlobalStyles('__global:tokens', css);\n }\n }\n }\n\n const globalFF = getGlobalFontFace();\n if (globalFF) {\n for (const [family, input] of Object.entries(globalFF)) {\n const descriptors = Array.isArray(input) ? input : [input];\n for (const desc of descriptors) {\n const hash = fontFaceContentHash(family, desc);\n const css = formatFontFaceRule(family, desc);\n this.collectFontFace(hash, css);\n }\n }\n }\n\n const globalCS = getGlobalCounterStyle();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css);\n }\n }\n\n const globalStyles = getGlobalStyles();\n if (globalStyles) {\n for (const [selector, styles] of Object.entries(globalStyles)) {\n if (Object.keys(styles).length > 0) {\n const rules = renderStyles(styles, selector) as StyleResult[];\n if (rules.length > 0) {\n const css = formatGlobalRules(rules);\n if (css) {\n this.collectGlobalStyles(`__global:styles:${selector}`, css);\n }\n }\n }\n }\n }\n }\n\n /**\n * Allocate a className for a cache key, server-side.\n * Mirrors StyleInjector.allocateClassName but without DOM access.\n */\n allocateClassName(cacheKey: string): {\n className: string;\n isNewAllocation: boolean;\n } {\n const existing = this.cacheKeyToClassName.get(cacheKey);\n if (existing) {\n return { className: existing, isNewAllocation: false };\n }\n\n const className = this.generateClassName(cacheKey);\n this.cacheKeyToClassName.set(cacheKey, className);\n\n return { className, isNewAllocation: true };\n }\n\n /**\n * Record CSS rules for a chunk.\n * Called by useStyles during server render.\n */\n collectChunk(\n cacheKey: string,\n className: string,\n rules: StyleResult[],\n ): void {\n if (this.chunks.has(cacheKey)) return;\n const css = formatRules(rules, className);\n if (css) {\n this.chunks.set(cacheKey, css);\n }\n }\n\n /**\n * Record a @property rule. Deduplicated by name.\n */\n collectProperty(name: string, css: string): void {\n if (!this.propertyRules.has(name)) {\n this.propertyRules.set(name, css);\n }\n }\n\n /**\n * Record a @keyframes rule. Deduplicated by name.\n */\n collectKeyframes(name: string, css: string): void {\n if (!this.keyframeRules.has(name)) {\n this.keyframeRules.set(name, css);\n }\n }\n\n /**\n * Allocate a keyframe name for SSR. Uses provided name or generates one.\n */\n allocateKeyframeName(providedName?: string): string {\n return (\n providedName ??\n makeKeyframeName(this.namePrefix, String(this.keyframesCounter++))\n );\n }\n\n /**\n * Record a @font-face rule. Deduplicated by key (content hash).\n */\n collectFontFace(key: string, css: string): void {\n if (!this.fontFaceRules.has(key)) {\n this.fontFaceRules.set(key, css);\n }\n }\n\n /**\n * Record a @counter-style rule. Deduplicated by name.\n */\n collectCounterStyle(name: string, css: string): void {\n if (!this.counterStyleRules.has(name)) {\n this.counterStyleRules.set(name, css);\n }\n }\n\n /**\n * Allocate a counter-style name for SSR. Uses provided name or generates one.\n */\n allocateCounterStyleName(providedName?: string): string {\n return (\n providedName ??\n makeCounterStyleName(this.namePrefix, String(this.counterStyleCounter++))\n );\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectGlobalStyles(key: string, css: string, replace?: boolean): void {\n if (replace || !this.globalStyles.has(key)) {\n this.globalStyles.set(key, css);\n }\n }\n\n /**\n * Record raw CSS text (from useRawCSS). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectRawCSS(key: string, css: string, replace?: boolean): void {\n if (replace || !this.rawCSS.has(key)) {\n this.rawCSS.set(key, css);\n }\n }\n\n /**\n * Extract all CSS collected so far as a single string.\n * Includes @property and @keyframes rules.\n * Used for non-streaming SSR (renderToString).\n */\n getCSS(): string {\n const parts: string[] = [];\n\n for (const css of this.propertyRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.fontFaceRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.counterStyleRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.rawCSS.values()) {\n parts.push(css);\n }\n\n for (const css of this.globalStyles.values()) {\n parts.push(css);\n }\n\n for (const css of this.chunks.values()) {\n parts.push(css);\n }\n\n for (const css of this.keyframeRules.values()) {\n parts.push(css);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Flush only newly collected CSS since the last flush.\n * Used for streaming SSR (renderToPipeableStream + useServerInsertedHTML).\n */\n flushCSS(): string {\n const parts: string[] = [];\n\n for (const [name, css] of this.propertyRules) {\n if (!this.flushedPropertyKeys.has(name)) {\n parts.push(css);\n this.flushedPropertyKeys.add(name);\n }\n }\n\n for (const [key, css] of this.fontFaceRules) {\n if (!this.flushedFontFaceKeys.has(key)) {\n parts.push(css);\n this.flushedFontFaceKeys.add(key);\n }\n }\n\n for (const [key, css] of this.counterStyleRules) {\n if (!this.flushedCounterStyleKeys.has(key)) {\n parts.push(css);\n this.flushedCounterStyleKeys.add(key);\n }\n }\n\n for (const [key, css] of this.rawCSS) {\n if (!this.flushedRawKeys.has(key)) {\n parts.push(css);\n this.flushedRawKeys.add(key);\n }\n }\n\n for (const [key, css] of this.globalStyles) {\n if (!this.flushedGlobalKeys.has(key)) {\n parts.push(css);\n this.flushedGlobalKeys.add(key);\n }\n }\n\n for (const [key, css] of this.chunks) {\n if (!this.flushedKeys.has(key)) {\n parts.push(css);\n this.flushedKeys.add(key);\n }\n }\n\n for (const [name, css] of this.keyframeRules) {\n if (!this.flushedKeyframeKeys.has(name)) {\n parts.push(css);\n this.flushedKeyframeKeys.add(name);\n }\n }\n\n return parts.join('\\n');\n }\n\n private flushedClassNames = new Set<string>();\n\n /**\n * Return class names rendered since the last call (for streaming).\n * Used to emit lightweight class-list scripts for client hydration.\n */\n getRenderedClassNames(): string[] {\n const names: string[] = [];\n for (const className of this.cacheKeyToClassName.values()) {\n if (!this.flushedClassNames.has(className)) {\n this.flushedClassNames.add(className);\n names.push(className);\n }\n }\n return names;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoCA,IAAa,uBAAb,MAAkC;CAChC,yBAAiB,IAAI,IAAoB;CACzC,sCAA8B,IAAI,IAAoB;CACtD,8BAAsB,IAAI,IAAY;CACtC,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,+BAAuB,IAAI,IAAoB;CAC/C,oCAA4B,IAAI,IAAY;CAC5C,yBAAiB,IAAI,IAAoB;CACzC,iCAAyB,IAAI,IAAY;CACzC,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,oCAA4B,IAAI,IAAoB;CACpD,0CAAkC,IAAI,IAAY;CAClD,mBAA2B;CAC3B,sBAA8B;CAC9B,qBAA6B;CAC7B;;;;;;;;CASA,YAAY,YAAqB;EAC/B,IAAI,eAAe,KAAA,GACjB,mBAAmB,UAAU;EAE/B,KAAK,aAAa,cAAc,cAAc;CAChD;CAEA,kBAA0B,UAA0B;EAClD,OAAO,cAAc,KAAK,YAAY,WAAW,QAAQ,CAAC;CAC5D;;;;;;;;;;CAWA,mBAAyB;EACvB,IAAI,KAAK,oBAAoB;EAC7B,KAAK,qBAAqB;EAE1B,KAAK,MAAM,CAAC,OAAO,eAAe,OAAO,QACvC,uBAAuB,CACzB,GAAG;GACD,MAAM,MAAM,kBAAkB,OAAO,UAAU;GAC/C,IAAI,KACF,KAAK,gBAAgB,UAAU,SAAS,GAAG;EAE/C;EAEA,MAAM,cAAc,sBAAsB;EAC1C,IAAI,eAAe,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,GAAG;GACtD,MAAM,aAAa,aAAa,aAAa,OAAO;GACpD,IAAI,WAAW,SAAS,GAAG;IACzB,MAAM,MAAM,kBAAkB,UAAU;IACxC,IAAI,KACF,KAAK,oBAAoB,mBAAmB,GAAG;GAEnD;EACF;EAEA,MAAM,WAAW,kBAAkB;EACnC,IAAI,UACF,KAAK,MAAM,CAAC,QAAQ,UAAU,OAAO,QAAQ,QAAQ,GAAG;GACtD,MAAM,cAAc,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;GACzD,KAAK,MAAM,QAAQ,aAAa;IAC9B,MAAM,OAAO,oBAAoB,QAAQ,IAAI;IAC7C,MAAM,MAAM,mBAAmB,QAAQ,IAAI;IAC3C,KAAK,gBAAgB,MAAM,GAAG;GAChC;EACF;EAGF,MAAM,WAAW,sBAAsB;EACvC,IAAI,UACF,KAAK,MAAM,CAAC,MAAM,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;GAC1D,MAAM,MAAM,uBAAuB,MAAM,WAAW;GACpD,KAAK,oBAAoB,MAAM,GAAG;EACpC;EAGF,MAAM,eAAe,gBAAgB;EACrC,IAAI;QACG,MAAM,CAAC,UAAU,WAAW,OAAO,QAAQ,YAAY,GAC1D,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG;IAClC,MAAM,QAAQ,aAAa,QAAQ,QAAQ;IAC3C,IAAI,MAAM,SAAS,GAAG;KACpB,MAAM,MAAM,kBAAkB,KAAK;KACnC,IAAI,KACF,KAAK,oBAAoB,mBAAmB,YAAY,GAAG;IAE/D;GACF;;CAGN;;;;;CAMA,kBAAkB,UAGhB;EACA,MAAM,WAAW,KAAK,oBAAoB,IAAI,QAAQ;EACtD,IAAI,UACF,OAAO;GAAE,WAAW;GAAU,iBAAiB;EAAM;EAGvD,MAAM,YAAY,KAAK,kBAAkB,QAAQ;EACjD,KAAK,oBAAoB,IAAI,UAAU,SAAS;EAEhD,OAAO;GAAE;GAAW,iBAAiB;EAAK;CAC5C;;;;;CAMA,aACE,UACA,WACA,OACM;EACN,IAAI,KAAK,OAAO,IAAI,QAAQ,GAAG;EAC/B,MAAM,MAAM,YAAY,OAAO,SAAS;EACxC,IAAI,KACF,KAAK,OAAO,IAAI,UAAU,GAAG;CAEjC;;;;CAKA,gBAAgB,MAAc,KAAmB;EAC/C,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,GAC9B,KAAK,cAAc,IAAI,MAAM,GAAG;CAEpC;;;;CAKA,iBAAiB,MAAc,KAAmB;EAChD,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,GAC9B,KAAK,cAAc,IAAI,MAAM,GAAG;CAEpC;;;;CAKA,qBAAqB,cAA+B;EAClD,OACE,gBACA,iBAAiB,KAAK,YAAY,OAAO,KAAK,kBAAkB,CAAC;CAErE;;;;CAKA,gBAAgB,KAAa,KAAmB;EAC9C,IAAI,CAAC,KAAK,cAAc,IAAI,GAAG,GAC7B,KAAK,cAAc,IAAI,KAAK,GAAG;CAEnC;;;;CAKA,oBAAoB,MAAc,KAAmB;EACnD,IAAI,CAAC,KAAK,kBAAkB,IAAI,IAAI,GAClC,KAAK,kBAAkB,IAAI,MAAM,GAAG;CAExC;;;;CAKA,yBAAyB,cAA+B;EACtD,OACE,gBACA,qBAAqB,KAAK,YAAY,OAAO,KAAK,qBAAqB,CAAC;CAE5E;;;;;;;CAQA,oBAAoB,KAAa,KAAa,SAAyB;EACrE,IAAI,WAAW,CAAC,KAAK,aAAa,IAAI,GAAG,GACvC,KAAK,aAAa,IAAI,KAAK,GAAG;CAElC;;;;;;;CAQA,cAAc,KAAa,KAAa,SAAyB;EAC/D,IAAI,WAAW,CAAC,KAAK,OAAO,IAAI,GAAG,GACjC,KAAK,OAAO,IAAI,KAAK,GAAG;CAE5B;;;;;;CAOA,SAAiB;EACf,MAAM,QAAkB,CAAC;EAEzB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,kBAAkB,OAAO,GAC9C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,OAAO,OAAO,GACnC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,aAAa,OAAO,GACzC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,OAAO,OAAO,GACnC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,OAAO,MAAM,KAAK,IAAI;CACxB;;;;;CAMA,WAAmB;EACjB,MAAM,QAAkB,CAAC;EAEzB,KAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,eAC7B,IAAI,CAAC,KAAK,oBAAoB,IAAI,IAAI,GAAG;GACvC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,IAAI;EACnC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,eAC5B,IAAI,CAAC,KAAK,oBAAoB,IAAI,GAAG,GAAG;GACtC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,GAAG;EAClC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,mBAC5B,IAAI,CAAC,KAAK,wBAAwB,IAAI,GAAG,GAAG;GAC1C,MAAM,KAAK,GAAG;GACd,KAAK,wBAAwB,IAAI,GAAG;EACtC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,QAC5B,IAAI,CAAC,KAAK,eAAe,IAAI,GAAG,GAAG;GACjC,MAAM,KAAK,GAAG;GACd,KAAK,eAAe,IAAI,GAAG;EAC7B;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,cAC5B,IAAI,CAAC,KAAK,kBAAkB,IAAI,GAAG,GAAG;GACpC,MAAM,KAAK,GAAG;GACd,KAAK,kBAAkB,IAAI,GAAG;EAChC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,QAC5B,IAAI,CAAC,KAAK,YAAY,IAAI,GAAG,GAAG;GAC9B,MAAM,KAAK,GAAG;GACd,KAAK,YAAY,IAAI,GAAG;EAC1B;EAGF,KAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,eAC7B,IAAI,CAAC,KAAK,oBAAoB,IAAI,IAAI,GAAG;GACvC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,IAAI;EACnC;EAGF,OAAO,MAAM,KAAK,IAAI;CACxB;CAEA,oCAA4B,IAAI,IAAY;;;;;CAM5C,wBAAkC;EAChC,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,aAAa,KAAK,oBAAoB,OAAO,GACtD,IAAI,CAAC,KAAK,kBAAkB,IAAI,SAAS,GAAG;GAC1C,KAAK,kBAAkB,IAAI,SAAS;GACpC,MAAM,KAAK,SAAS;EACtB;EAEF,OAAO;CACT;AACF"}
|