@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/ssr.md
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# Server-Side Rendering (SSR)
|
|
2
2
|
|
|
3
|
-
Tasty supports server-side rendering with zero-cost client hydration. This does **not** introduce a separate styling engine:
|
|
3
|
+
Tasty supports server-side rendering with zero-cost client hydration. This does **not** introduce a separate styling engine: `tasty()` uses the same rendering pipeline on the server and in the browser, while the SSR integrations add server-side CSS collection and client-side cache hydration. Your existing `tasty()` components work unchanged, and SSR remains opt-in with no per-component modifications. For the broader docs map, see the [Docs Hub](README.md).
|
|
4
|
+
|
|
5
|
+
## Zero-runtime terminology
|
|
6
|
+
|
|
7
|
+
Zero-runtime delivery is an outcome, not an alias for `tastyStatic()`. When `tasty()` components render only on the server, their CSS is delivered with the HTML and no Tasty styling runtime is shipped to the browser. Astro's `tastyIntegration({ islands: false })` is the explicit integration for this setup. Server-only Next.js React Server Components follow the same architecture, although you should verify the generated output for your deployment.
|
|
8
|
+
|
|
9
|
+
`tastyStatic()` reaches the same client-side outcome by extracting CSS during the build instead of during React rendering. Use it when extraction must happen before rendering or when the consumer is not React; see [Build-Time Extraction](tasty-static.md).
|
|
4
10
|
|
|
5
11
|
---
|
|
6
12
|
|
|
7
13
|
## Requirements
|
|
8
14
|
|
|
9
|
-
| Dependency | Version | Required for
|
|
10
|
-
|
|
11
|
-
| `react`
|
|
12
|
-
| `next`
|
|
13
|
-
| Node.js
|
|
15
|
+
| Dependency | Version | Required for |
|
|
16
|
+
| ---------- | ------- | ----------------------------------------------------------------------------------------------- |
|
|
17
|
+
| `react` | >= 18 | All SSR entry points (matches the current peer dependency of `@tenphi/tasty`) |
|
|
18
|
+
| `next` | >= 13 | Next.js integration (`@tenphi/tasty/ssr/next`) — App Router with `useServerInsertedHTML` |
|
|
19
|
+
| Node.js | >= 20 | Generic / streaming SSR (`@tenphi/tasty/ssr`) — uses `node:async_hooks` for `AsyncLocalStorage` |
|
|
14
20
|
|
|
15
21
|
The Astro integration (`@tenphi/tasty/ssr/astro`) has no additional dependencies beyond `react`.
|
|
16
22
|
|
|
@@ -18,18 +24,18 @@ The Astro integration (`@tenphi/tasty/ssr/astro`) has no additional dependencies
|
|
|
18
24
|
|
|
19
25
|
## How It Works
|
|
20
26
|
|
|
21
|
-
`tasty()` components are hook-free and use `computeStyles()` internally — a synchronous, framework-agnostic function. On the server, `computeStyles()` discovers a `ServerStyleCollector` via a registered getter (module-level for Next.js, `globalThis` for Astro/generic frameworks using `AsyncLocalStorage`) and collects CSS into it instead of trying to access the DOM. On the client, CSS is injected synchronously into the DOM during render; the injector's content-based cache makes this idempotent. The collector accumulates all styles
|
|
27
|
+
`tasty()` components are hook-free and use `computeStyles()` internally — a synchronous, framework-agnostic function. On the server, `computeStyles()` discovers a `ServerStyleCollector` via a registered getter (module-level for Next.js, `globalThis` for Astro/generic frameworks using `AsyncLocalStorage`) and collects CSS into it instead of trying to access the DOM. On the client, CSS is injected synchronously into the DOM during render; the injector's content-based cache makes this idempotent. The collector accumulates all styles and serializes them as `<style>` tags plus a class-list script in the HTML. On the client, `hydrateTastyClasses()` pre-populates the injector's rules map with the rendered class names so that `computeStyles()` skips the rendering pipeline entirely during hydration.
|
|
22
28
|
|
|
23
29
|
```
|
|
24
30
|
Server Client
|
|
25
31
|
────── ──────
|
|
26
|
-
tasty() renders
|
|
27
|
-
└─ computeStyles() └─
|
|
32
|
+
tasty() renders hydrateTastyClasses() reads window.__TASTY__
|
|
33
|
+
└─ computeStyles() └─ marks rendered class names as already-in-DOM
|
|
28
34
|
└─ collector.collect()
|
|
29
35
|
tasty() renders
|
|
30
36
|
After render: └─ computeStyles()
|
|
31
|
-
<style data-tasty-ssr>
|
|
32
|
-
<script
|
|
37
|
+
<style data-tasty-ssr> └─ class name known → skip pipeline
|
|
38
|
+
<script> (pushes to __TASTY__) └─ no CSS re-injection
|
|
33
39
|
```
|
|
34
40
|
|
|
35
41
|
---
|
|
@@ -85,8 +91,8 @@ That's it. All `tasty()` components inside the tree automatically get SSR suppor
|
|
|
85
91
|
- `TastyRegistry` is a `'use client'` component, but Next.js still server-renders it on initial page load. The `'use client'` boundary is required solely to access `useServerInsertedHTML` — **not** because `tasty()` components need the client.
|
|
86
92
|
- During SSR, `TastyRegistry` creates a `ServerStyleCollector` and registers it via a module-level getter (not `globalThis` — this avoids leaking between Next.js's separate RSC and SSR module graphs). It also wraps children in a React context provider so that hooks inside the SSR tree can discover the collector. All style functions — `tasty()` components, `computeStyles()`, `useStyles()`, `useGlobalStyles()`, `useRawCSS()`, `useKeyframes()`, `useProperty()`, `useFontFace()`, and `useCounterStyle()` — discover the collector through the module-level getter or context provider.
|
|
87
93
|
- `TastyRegistry` uses `useServerInsertedHTML` to flush collected CSS into the HTML stream as `<style data-tasty-ssr>` tags. This is fully streaming-compatible — styles are injected alongside each Suspense boundary as it resolves.
|
|
88
|
-
- A companion inline `<script>` tag
|
|
89
|
-
- When the `@tenphi/tasty/ssr/next` module loads on the client, `
|
|
94
|
+
- A companion inline `<script>` tag pushes the rendered class names into `window.__TASTY__` for each flush. This streaming-friendly approach accumulates the class list incrementally as Suspense boundaries resolve.
|
|
95
|
+
- When the `@tenphi/tasty/ssr/next` module loads on the client, `hydrateTastyClasses()` runs automatically from `window.__TASTY__` and pre-populates the injector's rules map. During hydration, `computeStyles()` sees the class name is already registered and skips the entire pipeline.
|
|
90
96
|
|
|
91
97
|
### Using Tasty in Server Components
|
|
92
98
|
|
|
@@ -124,11 +130,11 @@ The nonce is automatically applied to all `<style>` and `<script>` tags injected
|
|
|
124
130
|
|
|
125
131
|
Tasty offers three levels of Astro integration. Choose the one that matches your needs:
|
|
126
132
|
|
|
127
|
-
| Setup
|
|
128
|
-
|
|
129
|
-
| Zero setup
|
|
130
|
-
| `tastyIntegration({ islands: false })` | One line
|
|
131
|
-
| `tastyIntegration()`
|
|
133
|
+
| Setup | Config needed | Deduplication | Hooks work | Client JS |
|
|
134
|
+
| -------------------------------------- | ------------- | --------------- | ---------------------- | -------------- |
|
|
135
|
+
| Zero setup | None | Per render tree | Yes (within each tree) | None |
|
|
136
|
+
| `tastyIntegration({ islands: false })` | One line | Cross-tree | Yes | None |
|
|
137
|
+
| `tastyIntegration()` | One line | Cross-tree | Yes | Auto-hydration |
|
|
132
138
|
|
|
133
139
|
### Zero setup (static pages)
|
|
134
140
|
|
|
@@ -188,7 +194,7 @@ This gives you:
|
|
|
188
194
|
|
|
189
195
|
- A `ServerStyleCollector` per request via `AsyncLocalStorage`, deduplicating CSS across all React trees on the page
|
|
190
196
|
- A single consolidated `<style data-tasty-ssr>` injected into `</head>`
|
|
191
|
-
- A `<script
|
|
197
|
+
- A `<script>` tag pushing the rendered class names into `window.__TASTY__` for client hydration
|
|
192
198
|
- Auto-injected client hydration script (via `injectScript('before-hydration')`) so islands skip the style pipeline during hydration -- no need to import anything manually in each island component
|
|
193
199
|
|
|
194
200
|
All style functions (`useGlobalStyles`, `useRawCSS`, `useKeyframes`, `useProperty`, `useFontFace`, `useCounterStyle`) work on the server.
|
|
@@ -223,7 +229,7 @@ export default defineConfig({
|
|
|
223
229
|
});
|
|
224
230
|
```
|
|
225
231
|
|
|
226
|
-
This gives the same middleware deduplication and hook support, but ships zero client-side JavaScript. No `<script
|
|
232
|
+
This gives the same middleware deduplication and hook support, but ships zero client-side JavaScript. No class-list `<script>` is emitted.
|
|
227
233
|
|
|
228
234
|
### Manual middleware (advanced)
|
|
229
235
|
|
|
@@ -234,10 +240,7 @@ If you need to compose Tasty's middleware with other middleware (e.g., via `sequ
|
|
|
234
240
|
import { sequence } from 'astro:middleware';
|
|
235
241
|
import { tastyMiddleware } from '@tenphi/tasty/ssr/astro';
|
|
236
242
|
|
|
237
|
-
export const onRequest = sequence(
|
|
238
|
-
tastyMiddleware(),
|
|
239
|
-
myOtherMiddleware,
|
|
240
|
-
);
|
|
243
|
+
export const onRequest = sequence(tastyMiddleware(), myOtherMiddleware);
|
|
241
244
|
```
|
|
242
245
|
|
|
243
246
|
For island hydration with manual middleware, import the client module in a shared entry point or in each island:
|
|
@@ -258,7 +261,7 @@ export const onRequest = tastyMiddleware({ transferCache: false });
|
|
|
258
261
|
Astro's `@astrojs/react` renderer calls `renderToString()` for each React component without wrapping the tree in a provider. The middleware creates a `ServerStyleCollector` and binds it via `AsyncLocalStorage`. All `computeStyles()` calls within the request discover this collector automatically.
|
|
259
262
|
|
|
260
263
|
- **Static components** (no `client:*`): Styles are collected during `renderToString` and injected into `</head>` as a single `<style>` tag. No JavaScript is shipped.
|
|
261
|
-
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, the hydration script (auto-injected by `tastyIntegration()` or manually via `@tenphi/tasty/ssr/astro-client`) reads the
|
|
264
|
+
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, the hydration script (auto-injected by `tastyIntegration()` or manually via `@tenphi/tasty/ssr/astro-client`) reads the class list from `window.__TASTY__` and pre-populates the injector's rules map. The island's `computeStyles()` calls see the class names as already registered and skip the pipeline during hydration.
|
|
262
265
|
- The middleware reads the full response body, then injects the collected CSS into `</head>` before sending the final HTML.
|
|
263
266
|
|
|
264
267
|
### CSP nonce
|
|
@@ -274,31 +277,28 @@ Any React-based framework can integrate using `runWithCollector`, which binds a
|
|
|
274
277
|
```tsx
|
|
275
278
|
import {
|
|
276
279
|
ServerStyleCollector,
|
|
280
|
+
createServerStyleCollector,
|
|
277
281
|
runWithCollector,
|
|
278
|
-
|
|
282
|
+
hydrateTastyClasses,
|
|
279
283
|
} from '@tenphi/tasty/ssr';
|
|
280
284
|
import { renderToString } from 'react-dom/server';
|
|
281
285
|
import { hydrateRoot } from 'react-dom/client';
|
|
282
286
|
|
|
283
287
|
// ── Server ──────────────────────────────────────────────
|
|
284
288
|
|
|
285
|
-
const collector =
|
|
289
|
+
const collector = createServerStyleCollector();
|
|
286
290
|
|
|
287
|
-
const html = await runWithCollector(collector, () =>
|
|
288
|
-
renderToString(<App />)
|
|
289
|
-
);
|
|
291
|
+
const html = await runWithCollector(collector, () => renderToString(<App />));
|
|
290
292
|
|
|
291
293
|
const css = collector.getCSS();
|
|
292
|
-
const
|
|
294
|
+
const classNames = collector.getRenderedClassNames();
|
|
293
295
|
|
|
294
296
|
// Embed in your HTML template:
|
|
295
297
|
const fullHtml = `
|
|
296
298
|
<html>
|
|
297
299
|
<head>
|
|
298
300
|
<style data-tasty-ssr>${css}</style>
|
|
299
|
-
<script
|
|
300
|
-
${JSON.stringify(cacheState)}
|
|
301
|
-
</script>
|
|
301
|
+
<script>(window.__TASTY__=window.__TASTY__||[]).push(${JSON.stringify(classNames)})</script>
|
|
302
302
|
</head>
|
|
303
303
|
<body>
|
|
304
304
|
<div id="root">${html}</div>
|
|
@@ -309,7 +309,7 @@ const fullHtml = `
|
|
|
309
309
|
// ── Client ──────────────────────────────────────────────
|
|
310
310
|
|
|
311
311
|
// Before hydration:
|
|
312
|
-
|
|
312
|
+
hydrateTastyClasses(); // reads from window.__TASTY__
|
|
313
313
|
|
|
314
314
|
hydrateRoot(document.getElementById('root'), <App />);
|
|
315
315
|
```
|
|
@@ -319,7 +319,7 @@ hydrateRoot(document.getElementById('root'), <App />);
|
|
|
319
319
|
For streaming with `renderToPipeableStream`, use `flushCSS()` instead of `getCSS()`:
|
|
320
320
|
|
|
321
321
|
```tsx
|
|
322
|
-
const collector =
|
|
322
|
+
const collector = createServerStyleCollector();
|
|
323
323
|
|
|
324
324
|
const stream = await runWithCollector(collector, () =>
|
|
325
325
|
renderToPipeableStream(<App />, {
|
|
@@ -330,14 +330,16 @@ const stream = await runWithCollector(collector, () =>
|
|
|
330
330
|
stream.pipe(res);
|
|
331
331
|
},
|
|
332
332
|
onAllReady() {
|
|
333
|
-
// Flush any remaining styles +
|
|
333
|
+
// Flush any remaining styles + class list
|
|
334
334
|
const css = collector.flushCSS();
|
|
335
335
|
if (css) res.write(`<style data-tasty-ssr>${css}</style>`);
|
|
336
336
|
|
|
337
|
-
const
|
|
338
|
-
res.write(
|
|
337
|
+
const classNames = collector.getRenderedClassNames();
|
|
338
|
+
res.write(
|
|
339
|
+
`<script>(window.__TASTY__=window.__TASTY__||[]).push(${JSON.stringify(classNames)})</script>`,
|
|
340
|
+
);
|
|
339
341
|
},
|
|
340
|
-
})
|
|
342
|
+
}),
|
|
341
343
|
);
|
|
342
344
|
```
|
|
343
345
|
|
|
@@ -347,62 +349,65 @@ const stream = await runWithCollector(collector, () =>
|
|
|
347
349
|
|
|
348
350
|
### Entry points
|
|
349
351
|
|
|
350
|
-
| Import path
|
|
351
|
-
|
|
352
|
-
| `@tenphi/tasty/ssr`
|
|
353
|
-
| `@tenphi/tasty/ssr/next`
|
|
354
|
-
| `@tenphi/tasty/ssr/astro`
|
|
355
|
-
| `@tenphi/tasty/ssr/astro-client`
|
|
352
|
+
| Import path | Description |
|
|
353
|
+
| ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
354
|
+
| `@tenphi/tasty/ssr` | Core SSR API: `ServerStyleCollector`, `createServerStyleCollector`, `runWithCollector`, `hydrateTastyClasses` |
|
|
355
|
+
| `@tenphi/tasty/ssr/next` | Next.js App Router: `TastyRegistry` component |
|
|
356
|
+
| `@tenphi/tasty/ssr/astro` | Astro: `tastyIntegration`, `tastyMiddleware` |
|
|
357
|
+
| `@tenphi/tasty/ssr/astro-client` | Astro: client-side cache hydration (auto-injected by integration, or import manually) |
|
|
358
|
+
| `@tenphi/tasty/ssr/astro-middleware`<br>`@tenphi/tasty/ssr/astro-middleware-static` | Astro: the middleware entrypoints `tastyIntegration()` registers via `addMiddleware()`. Exported so Astro can resolve them by specifier; you should not import them. For manual setups use `tastyMiddleware()`. |
|
|
356
359
|
|
|
357
360
|
### `ServerStyleCollector`
|
|
358
361
|
|
|
359
362
|
Server-safe style collector. One instance per request.
|
|
360
363
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
| `
|
|
366
|
-
| `
|
|
367
|
-
| `
|
|
368
|
-
| `
|
|
369
|
-
| `
|
|
370
|
-
| `
|
|
371
|
-
| `
|
|
372
|
-
| `
|
|
373
|
-
| `
|
|
374
|
-
| `
|
|
375
|
-
| `
|
|
376
|
-
| `
|
|
364
|
+
Constructor: `new ServerStyleCollector(namePrefix?)`, or use the `createServerStyleCollector(namePrefix?)` factory. The optional `namePrefix` overrides the value from `configure({ namePrefix })`; in normal usage you pass nothing and let the global config drive it. See [Configuration: Name prefix](configuration.md#name-prefix).
|
|
365
|
+
|
|
366
|
+
| Method | Description |
|
|
367
|
+
| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
368
|
+
| `allocateClassName(cacheKey)` | Allocate a deterministic, content-hashed class name for a cache key (e.g. `t1a2b3` with the default prefix). The same `cacheKey` always produces the same class name on server and client when both share the same `namePrefix`. Returns `{ className, isNewAllocation }`. |
|
|
369
|
+
| `collectChunk(cacheKey, className, rules)` | Record CSS rules for a chunk. Deduplicated by `cacheKey`. |
|
|
370
|
+
| `collectKeyframes(name, css)` | Record a `@keyframes` rule. Deduplicated by name. |
|
|
371
|
+
| `allocateKeyframeName(providedName?)` | Allocate a keyframe name. Returns `providedName` if given, otherwise generates one using `${namePrefix}k${counter}` (e.g. `tk0`, `tk1`, ...). |
|
|
372
|
+
| `collectProperty(name, css)` | Record a `@property` rule. Deduplicated by name. |
|
|
373
|
+
| `collectFontFace(key, css)` | Record a `@font-face` rule. Deduplicated by content hash. |
|
|
374
|
+
| `collectCounterStyle(name, css)` | Record a `@counter-style` rule. Deduplicated by name. |
|
|
375
|
+
| `allocateCounterStyleName(providedName?)` | Allocate a counter-style name. Returns `providedName` if given, otherwise generates one using `${namePrefix}c${counter}` (e.g. `tc0`, `tc1`, ...). |
|
|
376
|
+
| `collectGlobalStyles(key, css)` | Record global styles (from `useGlobalStyles`). Deduplicated by key. |
|
|
377
|
+
| `collectRawCSS(key, css)` | Record raw CSS text (from `useRawCSS`). Deduplicated by key. |
|
|
378
|
+
| `collectInternals()` | Collect internal `@property` rules, `:root` token defaults, `@font-face`, and `@counter-style` rules from the global config. Called automatically on first chunk collection; idempotent. |
|
|
379
|
+
| `getCSS()` | Get all collected CSS as a single string. For non-streaming SSR. |
|
|
380
|
+
| `flushCSS()` | Get only CSS collected since the last flush. For streaming SSR. |
|
|
381
|
+
| `getRenderedClassNames()` | Get the list of class names rendered so far. Serialized to `window.__TASTY__` for client hydration via `hydrateTastyClasses()`. |
|
|
377
382
|
|
|
378
383
|
### `TastyRegistry`
|
|
379
384
|
|
|
380
385
|
Next.js App Router component. Props:
|
|
381
386
|
|
|
382
|
-
| Prop
|
|
383
|
-
|
|
384
|
-
| `children`
|
|
385
|
-
| `transferCache` | `boolean`
|
|
387
|
+
| Prop | Type | Default | Description |
|
|
388
|
+
| --------------- | ----------- | -------- | ------------------------------------------------ |
|
|
389
|
+
| `children` | `ReactNode` | required | Application tree |
|
|
390
|
+
| `transferCache` | `boolean` | `true` | Embed cache state script for zero-cost hydration |
|
|
386
391
|
|
|
387
392
|
### `tastyIntegration(options?)`
|
|
388
393
|
|
|
389
394
|
Astro integration factory. Registers middleware and optionally injects client hydration.
|
|
390
395
|
|
|
391
|
-
| Option
|
|
392
|
-
|
|
393
|
-
| `islands` | `boolean` | `true`
|
|
396
|
+
| Option | Type | Default | Description |
|
|
397
|
+
| --------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
398
|
+
| `islands` | `boolean` | `true` | When `true`, injects client hydration script and enables `transferCache`. When `false`, no client JS is shipped. |
|
|
394
399
|
|
|
395
400
|
### `tastyMiddleware(options?)`
|
|
396
401
|
|
|
397
402
|
Astro middleware factory. Use for manual middleware composition.
|
|
398
403
|
|
|
399
|
-
| Option
|
|
400
|
-
|
|
401
|
-
| `transferCache` | `boolean` | `true`
|
|
404
|
+
| Option | Type | Default | Description |
|
|
405
|
+
| --------------- | --------- | ------- | --------------------------------------------- |
|
|
406
|
+
| `transferCache` | `boolean` | `true` | Embed cache state script for island hydration |
|
|
402
407
|
|
|
403
|
-
### `
|
|
408
|
+
### `hydrateTastyClasses(classes?)`
|
|
404
409
|
|
|
405
|
-
Pre-populate the client injector
|
|
410
|
+
Pre-populate the client injector's rules map with class names rendered on the server, marking them as already present in the DOM so `computeStyles()` skips re-injection during hydration. When called without arguments, reads the class list from `window.__TASTY__` (populated by the streaming `<script>` tags emitted during SSR).
|
|
406
411
|
|
|
407
412
|
### `runWithCollector(collector, fn)`
|
|
408
413
|
|
|
@@ -418,21 +423,27 @@ The `TastyRegistry` or `tastyIntegration` is missing. Ensure your layout wraps t
|
|
|
418
423
|
|
|
419
424
|
### Hydration mismatch warnings
|
|
420
425
|
|
|
421
|
-
Class names are deterministic for the same render order. If you see mismatches, ensure `
|
|
426
|
+
Class names are deterministic for the same render order. If you see mismatches, ensure `hydrateTastyClasses()` runs before React hydration. For Next.js, this is automatic. For Astro with `tastyIntegration()`, this is also automatic. For manual Astro middleware setups, import `@tenphi/tasty/ssr/astro-client` in your island components. For custom setups, call `hydrateTastyClasses()` before `hydrateRoot()`.
|
|
427
|
+
|
|
428
|
+
Class names are also derived from the _resolved_ styles, so the server and the client must configure Tasty identically. Anything that changes what a component's styles resolve to will produce a mismatch if it is registered on only one side — `namePrefix`, `recipes`, `handlers`, and the `propHandlers` / `baseStyleProps` extension points described in [Plugins](plugins.md). Call the same `configure()` on both; global CSS is deduplicated automatically, so no `typeof window` guard is needed.
|
|
422
429
|
|
|
423
430
|
### Styles duplicated after hydration
|
|
424
431
|
|
|
425
|
-
|
|
432
|
+
**Global CSS** (`:root` tokens, `@property`, `globalStyles`, `@font-face`, `@counter-style`) configured via `configure()` is automatically deduplicated. When Tasty detects `<style data-tasty-ssr>` in the document, it skips client-side injection of globals that were already rendered by the SSR collector. This means `configure()` can be called with the full config on both server and client — no `typeof window === 'undefined'` guard is needed.
|
|
433
|
+
|
|
434
|
+
**Component CSS**: SSR `<style data-tasty-ssr>` tags remain in the DOM. The client injector creates separate `<style>` elements for any new styles. SSR styles are never modified or removed by the client. If this is a concern for very large apps, you can remove the SSR style tags and hydration scripts manually after hydration:
|
|
426
435
|
|
|
427
436
|
```tsx
|
|
428
|
-
import {
|
|
437
|
+
import { hydrateTastyClasses } from '@tenphi/tasty/ssr';
|
|
429
438
|
|
|
430
|
-
|
|
439
|
+
hydrateTastyClasses();
|
|
431
440
|
hydrateRoot(root, <App />);
|
|
432
441
|
|
|
433
|
-
// Optional: remove SSR style tags after hydration
|
|
434
|
-
document.querySelectorAll('style[data-tasty-ssr]').forEach(el => el.remove());
|
|
435
|
-
document.querySelectorAll('script
|
|
442
|
+
// Optional: remove SSR style tags and class-list scripts after hydration
|
|
443
|
+
document.querySelectorAll('style[data-tasty-ssr]').forEach((el) => el.remove());
|
|
444
|
+
document.querySelectorAll('script').forEach((el) => {
|
|
445
|
+
if (el.textContent?.includes('__TASTY__')) el.remove();
|
|
446
|
+
});
|
|
436
447
|
```
|
|
437
448
|
|
|
438
449
|
### `AsyncLocalStorage` not available
|
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,10 +199,23 @@ 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
|
+
|
|
209
|
+
**`dock` modifier:** pins the named edge and spans its full length, by also applying the value
|
|
210
|
+
to the two perpendicular sides. `inset: 'bottom dock'` gives `inset: auto 0 0 0` — anchored to
|
|
211
|
+
the bottom, full width. Without a direction, `dock` fills every side.
|
|
212
|
+
|
|
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.
|
|
218
|
+
|
|
198
219
|
**Output modifier:** `longhand` — forces output as individual CSS properties (`top`, `right`, `bottom`, `left`) instead of the `inset` shorthand.
|
|
199
220
|
|
|
200
221
|
| Value | Effect |
|
|
@@ -205,6 +226,11 @@ Positioning offsets with directional modifiers and multi-group support. Same dir
|
|
|
205
226
|
| `"0, 2x top"` | All sides `0`, then top overridden to `2x` |
|
|
206
227
|
| `"0 longhand"` | All sides `0`, output as individual `top`/`right`/`bottom`/`left` |
|
|
207
228
|
| `true` | All sides `0` |
|
|
229
|
+
| `"bottom dock"` | Bottom/left/right `0`, top `auto` — bottom-anchored, full width |
|
|
230
|
+
| `"right dock"` | Right/top/bottom `0`, left `auto` — right-anchored, full height |
|
|
231
|
+
| `"2x bottom dock"` | Bottom/left/right `2x`, top `auto` |
|
|
232
|
+
| `"2x 4x bottom dock"` | Bottom `2x`, left/right `4x`, top `auto` |
|
|
233
|
+
| `"dock"` | All sides `0` |
|
|
208
234
|
|
|
209
235
|
Later comma-separated groups override earlier groups for conflicting directions.
|
|
210
236
|
|
|
@@ -228,6 +254,7 @@ Background color with design token support. Preferred over `backgroundColor` and
|
|
|
228
254
|
| `"#purple.10"` | Token color at 10% opacity |
|
|
229
255
|
| `"#surface #primary.10"` | Background `#surface` with `#primary.10` overlay (two colors enable smooth transitions between both) |
|
|
230
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) |
|
|
231
258
|
| `true` | Default fill color |
|
|
232
259
|
|
|
233
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.
|
|
@@ -260,9 +287,17 @@ Text color with design token support.
|
|
|
260
287
|
| `"#current"` | Current inherited color |
|
|
261
288
|
| `"#current.5"` | Current inherited color at 50% opacity |
|
|
262
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) |
|
|
263
291
|
| `true` | `currentColor` |
|
|
264
292
|
|
|
265
|
-
|
|
293
|
+
Also sets `$current-color` to the same color, for anything that needs the
|
|
294
|
+
inherited color as a color rather than as the `currentcolor` keyword. Every color
|
|
295
|
+
publishes it, not just a named token, so a reader below always takes the nearest
|
|
296
|
+
`color` rather than the nearest *token* color. A value that already reads the
|
|
297
|
+
inherited color — `#current` itself, a `#current` fade, a bare `currentColor` —
|
|
298
|
+
is not republished: resolving it a second time one level down would fade it
|
|
299
|
+
twice, and the variable into itself is a self-reference. `#current` does not go
|
|
300
|
+
through it; it is the keyword.
|
|
266
301
|
|
|
267
302
|
### `svgFill`
|
|
268
303
|
|
|
@@ -270,7 +305,7 @@ SVG fill color. Same color token syntax as `fill` and `color`. Outputs the nativ
|
|
|
270
305
|
|
|
271
306
|
```jsx
|
|
272
307
|
svgFill="#purple.10"
|
|
273
|
-
svgFill="
|
|
308
|
+
svgFill="#current"
|
|
274
309
|
```
|
|
275
310
|
|
|
276
311
|
---
|
|
@@ -319,7 +354,11 @@ Border radius with shape presets and directional modifiers.
|
|
|
319
354
|
| `"backleaf"` | Asymmetric: round, sharp, round, sharp |
|
|
320
355
|
| `"inherit"` | Inherit border-radius from parent |
|
|
321
356
|
|
|
322
|
-
**
|
|
357
|
+
**Edge modifiers:** `top`, `right`, `bottom`, `left` — rounds the *pair* of corners along that edge.
|
|
358
|
+
|
|
359
|
+
**Corner modifiers:** `top-left`, `top-right`, `bottom-right`, `bottom-left` — rounds a single corner.
|
|
360
|
+
Use these when an edge modifier would round one corner too many. Edge and corner modifiers combine
|
|
361
|
+
(`radius: 'top bottom-right'`).
|
|
323
362
|
|
|
324
363
|
**Output modifier:** `longhand` — forces output as individual CSS longhand properties (`border-top-left-radius`, `border-top-right-radius`, `border-bottom-right-radius`, `border-bottom-left-radius`) instead of the `border-radius` shorthand. Useful when children need to selectively inherit individual corners via `radius: 'inherit left'`.
|
|
325
364
|
|
|
@@ -334,6 +373,9 @@ Border radius with shape presets and directional modifiers.
|
|
|
334
373
|
| `"1r longhand"` | All corners `1r`, output as 4 individual `border-*-radius` properties |
|
|
335
374
|
| `"inherit"` | All corners inherit from parent (`border-radius: inherit`) |
|
|
336
375
|
| `"inherit right"` | Right corners inherit from parent (uses longhand properties) |
|
|
376
|
+
| `"top-right"` | Top-right corner `1r`, every other corner `0` |
|
|
377
|
+
| `"4px top-left"` | Top-left corner `4px`, every other corner `0` |
|
|
378
|
+
| `"top bottom-right"` | Both top corners and bottom-right `1r`, bottom-left `0` |
|
|
337
379
|
|
|
338
380
|
### `outline`
|
|
339
381
|
|
|
@@ -378,11 +420,11 @@ Multiple shadows: `shadow="1x 1x 2x #dark.20, inset 0 0 4x #dark.10"`
|
|
|
378
420
|
|
|
379
421
|
Typography preset that sets font-size, line-height, letter-spacing, font-weight, font-style, and text-transform from named design tokens.
|
|
380
422
|
|
|
381
|
-
**Syntax:** `name`, `name / modifier
|
|
423
|
+
**Syntax:** `name`, `name / modifier...`, or `modifier...` (shorthand)
|
|
382
424
|
|
|
383
425
|
Preset names are project-specific (e.g. `h1`–`h6`, `t1`–`t4`, `p1`–`p4`). Register them for autocomplete by augmenting `TastyPresetNames`.
|
|
384
426
|
|
|
385
|
-
Use `/` to separate the preset name from
|
|
427
|
+
Use `/` to separate the preset name from one or more space-separated modifiers. When modifiers are used alone (without a name), the preset name defaults to `inherit`. Modifiers can be combined freely because they target different properties.
|
|
386
428
|
|
|
387
429
|
**Modifiers:**
|
|
388
430
|
|
|
@@ -394,11 +436,13 @@ Use `/` to separate the preset name from a modifier. When a modifier is used alo
|
|
|
394
436
|
| `tight` | Sets line-height equal to font-size |
|
|
395
437
|
|
|
396
438
|
```jsx
|
|
397
|
-
preset="h1"
|
|
398
|
-
preset="h2 / strong"
|
|
399
|
-
preset="
|
|
400
|
-
preset="
|
|
401
|
-
preset="
|
|
439
|
+
preset="h1" // heading 1
|
|
440
|
+
preset="h2 / strong" // bold heading 2
|
|
441
|
+
preset="h2 / strong italic" // bold + italic heading 2
|
|
442
|
+
preset="t3 / italic" // italic text 3
|
|
443
|
+
preset="t2 / strong tight" // bold text 2 with tight line-height
|
|
444
|
+
preset="bold" // inherit preset with bold (shorthand)
|
|
445
|
+
preset="bold italic" // inherit preset with bold + italic (shorthand)
|
|
402
446
|
```
|
|
403
447
|
|
|
404
448
|
Individual typography props (`fontSize`, `lineHeight`, `letterSpacing`, `fontWeight`, `fontStyle`, `textTransform`) can be used alongside `preset` to override specific values, but using `preset` alone is recommended.
|
|
@@ -550,15 +594,20 @@ Scrollbar styling using CSS standard properties (`scrollbar-width`, `scrollbar-c
|
|
|
550
594
|
|
|
551
595
|
Gradient-based edge fading using CSS masks. Use **comma-separated groups** to set different widths and colors per direction.
|
|
552
596
|
|
|
553
|
-
**Syntax:** `[width] [
|
|
597
|
+
**Syntax:** `[width] [direction...] [#from-color] [#to-color]` — comma-separated for multiple groups
|
|
554
598
|
|
|
555
599
|
**Direction modifiers:** `top`, `right`, `bottom`, `left`
|
|
556
600
|
|
|
601
|
+
A group that names edges takes a **single** width, applied to every edge it names — different
|
|
602
|
+
widths per edge come from comma groups. A group that names no edge covers all four and keeps
|
|
603
|
+
plain CSS shorthand order, like `padding`. See the [`padding` rule](#padding).
|
|
604
|
+
|
|
557
605
|
| Value | Effect |
|
|
558
606
|
|-------|--------|
|
|
559
607
|
| `"top"` | Fade top edge, default width (`2x`), all other edges unfaded |
|
|
560
608
|
| `"2x left right"` | Fade left and right edges with `2x` width, top/bottom unfaded |
|
|
561
|
-
| `"3x 1x
|
|
609
|
+
| `"3x 1x"` | All edges faded — top/bottom `3x`, left/right `1x` (CSS shorthand order) |
|
|
610
|
+
| `"3x top, 1x bottom"` | Fade top with `3x` width, bottom with `1x` width |
|
|
562
611
|
| `"2x #transparent #dark"` | All edges faded with `2x` width, from `#transparent` to `#dark` |
|
|
563
612
|
| `"top #a #b, bottom #c #d"` | Top fades from `#a` to `#b`, bottom fades from `#c` to `#d` |
|
|
564
613
|
|