@tenphi/tasty 0.10.1 → 0.11.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.
- package/README.md +79 -5
- package/dist/config.d.ts +32 -9
- package/dist/config.js +51 -10
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/injector/injector.js +1 -7
- package/dist/injector/injector.js.map +1 -1
- package/dist/parser/classify.js.map +1 -1
- package/dist/plugins/types.d.ts +9 -2
- package/dist/ssr/collector.js +11 -1
- package/dist/ssr/collector.js.map +1 -1
- package/dist/styles/types.d.ts +14 -1
- package/dist/tasty.d.ts +6 -6
- package/dist/utils/typography.d.ts +24 -13
- package/dist/utils/typography.js +6 -16
- package/dist/utils/typography.js.map +1 -1
- package/dist/zero/babel.d.ts +10 -4
- package/dist/zero/babel.js +6 -1
- package/dist/zero/babel.js.map +1 -1
- package/docs/adoption.md +286 -0
- package/docs/comparison.md +413 -0
- package/docs/configuration.md +41 -10
- package/docs/debug.md +1 -1
- package/docs/design-system.md +401 -0
- package/docs/{usage.md → dsl.md} +254 -409
- package/docs/getting-started.md +201 -0
- package/docs/injector.md +2 -2
- package/docs/methodology.md +501 -0
- package/docs/runtime.md +291 -0
- package/docs/ssr.md +11 -1
- package/docs/styles.md +2 -2
- package/docs/tasty-static.md +25 -3
- package/package.json +7 -4
- package/dist/tokens/typography.d.ts +0 -19
- package/dist/tokens/typography.js +0 -237
- package/dist/tokens/typography.js.map +0 -1
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# Comparison
|
|
2
|
+
|
|
3
|
+
Tasty is best understood not as a general-purpose CSS framework, but as a **styling engine for design systems**.
|
|
4
|
+
|
|
5
|
+
Most styling tools focus on one of these layers:
|
|
6
|
+
|
|
7
|
+
- direct app styling
|
|
8
|
+
- component-level styling
|
|
9
|
+
- typed CSS authoring
|
|
10
|
+
- utility composition
|
|
11
|
+
- atomic CSS generation
|
|
12
|
+
|
|
13
|
+
Tasty targets a different layer: it helps design-system authors define a **house styling language** on top of CSS, including tokens, state semantics, style props, recipes, custom units, and sub-element rules.
|
|
14
|
+
|
|
15
|
+
That is why syntax-level comparisons are often shallow. The more meaningful comparison is about:
|
|
16
|
+
|
|
17
|
+
- **which layer** a tool is designed for
|
|
18
|
+
- **who owns the authoring language**
|
|
19
|
+
- **how state conflicts are resolved**
|
|
20
|
+
- **what kind of predictability** the tool actually guarantees
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## High-level positioning
|
|
25
|
+
|
|
26
|
+
| System | Best described as | Main authoring model | Conflict model | Best fit |
|
|
27
|
+
|---|---|---|---|---|
|
|
28
|
+
| **Tasty** | Design-system styling engine | Custom DSL with tokens, state maps, recipes, style props, sub-elements, custom units | **Mutually exclusive selector resolution** for stateful styles | DS/platform teams defining a house styling language |
|
|
29
|
+
| **Tailwind CSS** | Utility-first styling framework | Utility classes in markup | Utility composition, variants, and framework-controlled ordering | Product teams optimizing for speed and direct authoring |
|
|
30
|
+
| **Panda CSS** | Typed styling engine with atomic output | Typed style objects, recipes, generated primitives, style props | Atomic CSS with static analysis | Teams wanting a DS-friendly engine with typed primitives |
|
|
31
|
+
| **vanilla-extract** | Zero-runtime TS-native stylesheet system | `.css.ts` files, theme contracts, style composition | Standard CSS semantics | Teams wanting static CSS and low-level control |
|
|
32
|
+
| **StyleX** | Compiler-based atomic styling system | JS authoring with compiler-generated atomic CSS | Compiler-controlled atomic composition | Large app teams wanting optimized, predictable atomic styling |
|
|
33
|
+
| **Stitches** (deprecated) **/ Emotion** | Component-first CSS-in-JS | Styled components, `css()` APIs, object/string styles | Composition within CSS-in-JS rules | Teams optimizing for component DX and flexible styling |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## What makes Tasty different
|
|
38
|
+
|
|
39
|
+
Tasty is built around a stronger goal than generic "predictable styling."
|
|
40
|
+
|
|
41
|
+
In many systems, predictability means:
|
|
42
|
+
|
|
43
|
+
- the compiler controls ordering
|
|
44
|
+
- class names do not accidentally collide
|
|
45
|
+
- specificity is reduced or normalized
|
|
46
|
+
- atomic rules compose in a stable way
|
|
47
|
+
|
|
48
|
+
Those are useful guarantees, but they are not the same as Tasty's main idea.
|
|
49
|
+
|
|
50
|
+
Tasty focuses on **stateful style resolution**. Instead of relying on ordinary cascade competition between matching rules, it compiles style logic into **mutually exclusive selectors**. For a given property and state combination, the system ensures that exactly one branch is eligible to win.
|
|
51
|
+
|
|
52
|
+
This is especially relevant for components with intersecting states such as:
|
|
53
|
+
|
|
54
|
+
- hover
|
|
55
|
+
- focus
|
|
56
|
+
- pressed
|
|
57
|
+
- disabled
|
|
58
|
+
- selected
|
|
59
|
+
- theme variants
|
|
60
|
+
- responsive conditions
|
|
61
|
+
- parent or root-driven conditions
|
|
62
|
+
|
|
63
|
+
Here is a minimal example. Two CSS rules for a button's background — one for `:hover`, one for `[disabled]`:
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
.btn:hover { background: dodgerblue; }
|
|
67
|
+
.btn[disabled] { background: gray; }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
When the button is both hovered **and** disabled, both selectors match with equal specificity. The last rule in source order wins. Swap the two lines and the visual behavior silently reverses — a hovered disabled button turns blue instead of gray.
|
|
71
|
+
|
|
72
|
+
In Tasty, the same intent is declared as a state map:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
fill: {
|
|
76
|
+
'': '#primary',
|
|
77
|
+
':hover': '#primary-hover',
|
|
78
|
+
'disabled': '#surface',
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Tasty compiles this into selectors where `disabled` is guarded by `:not(:hover)` negations (and vice versa), so exactly one rule matches regardless of source order. The outcome is defined by the state map, not by which line comes last.
|
|
83
|
+
|
|
84
|
+
That makes Tasty less of a "better way to write CSS objects" and more of a **state-aware style compiler for design systems**.
|
|
85
|
+
|
|
86
|
+
Beyond state resolution, Tasty includes several structural capabilities that most other tools do not offer:
|
|
87
|
+
|
|
88
|
+
- **CSS properties as typed React props** — `styleProps` lets a component expose selected style properties as normal props (`<Button placeSelf="end">`), including state maps for responsive values. No other tool provides this as a first-class, typed, design-system-aware feature.
|
|
89
|
+
- **Sub-element styling** — Compound components declare inner parts via capitalized keys in `styles` and `data-element` attributes. States, tokens, and recipes apply across the entire element tree from a single definition. See [Runtime API — Sub-element Styling](runtime.md#sub-element-styling).
|
|
90
|
+
- **Auto-inferred `@property`** — When a custom property is assigned a concrete value, Tasty infers the CSS `@property` syntax and registers it automatically, enabling smooth transitions on custom properties without manual declarations.
|
|
91
|
+
- **AI-friendly style definitions** — Style definitions are declarative, self-contained, and structurally consistent. AI tools can read, refactor, and generate Tasty styles as confidently as a human — no hidden cascade logic or implicit ordering to second-guess.
|
|
92
|
+
- **Companion ecosystem** — An [ESLint plugin](https://github.com/tenphi/eslint-plugin-tasty) with 27 lint rules, a [VS Code extension](https://github.com/tenphi/tasty-vscode-extension) for syntax highlighting, and [Glaze](https://github.com/tenphi/glaze) for OKHSL color theme generation with automatic WCAG contrast solving.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Comparison by system
|
|
97
|
+
|
|
98
|
+
### Tasty vs Tailwind CSS
|
|
99
|
+
|
|
100
|
+
Tailwind is centered on **direct authoring in markup**.
|
|
101
|
+
|
|
102
|
+
Its strength is speed: developers compose utilities directly where they use them, with responsive and state modifiers layered on top. This works extremely well for app teams that want a shared utility vocabulary with minimal ceremony.
|
|
103
|
+
|
|
104
|
+
Tasty solves a different problem.
|
|
105
|
+
|
|
106
|
+
Tasty is more appropriate when styling should be exposed through a **design-system-owned API** rather than through raw utility composition. Instead of asking every product engineer to compose the styling vocabulary directly, Tasty makes more sense when a design-system team wants to define:
|
|
107
|
+
|
|
108
|
+
- approved style props
|
|
109
|
+
- semantic tokens
|
|
110
|
+
- custom units
|
|
111
|
+
- recipes
|
|
112
|
+
- state semantics
|
|
113
|
+
- sub-element rules
|
|
114
|
+
- constrained component-facing styling APIs
|
|
115
|
+
|
|
116
|
+
So this is not mainly a comparison of syntax. It is a comparison of **governance models**:
|
|
117
|
+
|
|
118
|
+
- Tailwind: developers author directly with framework vocabulary
|
|
119
|
+
- Tasty: design-system authors define the vocabulary product teams consume
|
|
120
|
+
|
|
121
|
+
Tailwind is usually a stronger fit for fast product styling. Tasty is usually a stronger fit for governed design-system architecture.
|
|
122
|
+
|
|
123
|
+
To make this concrete, consider a button with `hover`, `disabled`, and `theme=danger` states.
|
|
124
|
+
|
|
125
|
+
**Plain CSS** — you need a selector for every intersection, and equal-specificity rules depend on source order:
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
.btn { background: var(--primary); color: white; cursor: pointer; }
|
|
129
|
+
.btn:hover { background: var(--primary-hover); }
|
|
130
|
+
.btn:active { background: var(--primary-pressed); }
|
|
131
|
+
.btn[disabled] { background: var(--surface); color: var(--text-40); cursor: not-allowed; }
|
|
132
|
+
|
|
133
|
+
/* theme=danger overrides — must repeat disabled/hover/active */
|
|
134
|
+
.btn[data-theme="danger"] { background: var(--danger); }
|
|
135
|
+
.btn[data-theme="danger"]:hover { background: var(--danger-hover); }
|
|
136
|
+
.btn[data-theme="danger"]:active { background: var(--danger-pressed); }
|
|
137
|
+
.btn[data-theme="danger"][disabled] { background: var(--surface); }
|
|
138
|
+
|
|
139
|
+
/* Bug: .btn:hover and .btn[disabled] have the same specificity.
|
|
140
|
+
A hovered disabled button gets :hover styles — unless source order saves you. */
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Every new state doubles the selector count. Miss one intersection and you ship a visual bug.
|
|
144
|
+
|
|
145
|
+
**Tailwind** — state intersections move into conditional className logic:
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<button className={cn(
|
|
149
|
+
'bg-primary text-white cursor-pointer',
|
|
150
|
+
'hover:bg-primary-hover active:bg-primary-pressed',
|
|
151
|
+
'disabled:bg-surface disabled:text-text-40 disabled:cursor-not-allowed',
|
|
152
|
+
theme === 'danger' && 'bg-danger hover:bg-danger-hover active:bg-danger-pressed',
|
|
153
|
+
theme === 'danger' && disabled && '!bg-surface',
|
|
154
|
+
)}>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The `theme` branch is runtime JS, not CSS. Intersections like `disabled + hover` need manual `!important` or extra utilities to override correctly.
|
|
158
|
+
|
|
159
|
+
**Tasty** — each property declares all its states in one map. The engine generates mutually exclusive selectors:
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
const Button = tasty({
|
|
163
|
+
as: 'button',
|
|
164
|
+
styles: {
|
|
165
|
+
fill: {
|
|
166
|
+
'': '#primary',
|
|
167
|
+
':hover': '#primary-hover',
|
|
168
|
+
':active': '#primary-pressed',
|
|
169
|
+
'disabled': '#surface',
|
|
170
|
+
'theme=danger': '#danger',
|
|
171
|
+
'theme=danger & :hover': '#danger-hover',
|
|
172
|
+
'theme=danger & :active': '#danger-pressed',
|
|
173
|
+
},
|
|
174
|
+
color: {
|
|
175
|
+
'': '#on-primary',
|
|
176
|
+
'disabled': '#text.40',
|
|
177
|
+
},
|
|
178
|
+
cursor: {
|
|
179
|
+
'': 'pointer',
|
|
180
|
+
'disabled': 'not-allowed',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`disabled` always wins over `:hover` because Tasty emits negation selectors — no source-order dependence, no manual intersection management, no `!important`.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### Tasty vs Panda CSS
|
|
191
|
+
|
|
192
|
+
Panda is one of the closest comparisons.
|
|
193
|
+
|
|
194
|
+
Like Tasty, Panda sits closer to the design-system layer than many other tools. It supports typed style authoring, recipes, generated primitives, and a DS-friendly workflow. It is much more than a basic styling helper.
|
|
195
|
+
|
|
196
|
+
The difference is where each system puts its core idea.
|
|
197
|
+
|
|
198
|
+
Panda is centered on **typed atomic generation** and static analysis. It gives teams a structured, modern, design-system-friendly engine with a strong build-time story.
|
|
199
|
+
|
|
200
|
+
Tasty is more centered on:
|
|
201
|
+
|
|
202
|
+
- a custom DSL
|
|
203
|
+
- state mapping
|
|
204
|
+
- mutually exclusive resolution
|
|
205
|
+
- defining a team-specific styling language
|
|
206
|
+
|
|
207
|
+
So while both can support serious design-system work, they do not optimize for exactly the same thing:
|
|
208
|
+
|
|
209
|
+
- **Panda** is closer to a typed styling engine with strong DS ergonomics
|
|
210
|
+
- **Tasty** is closer to a design-system style compiler with explicit state semantics
|
|
211
|
+
|
|
212
|
+
If a team mostly wants typed primitives, recipes, and extracted CSS, Panda may feel more straightforward.
|
|
213
|
+
|
|
214
|
+
If a team wants to define a more opinionated styling language with stronger control over state logic and rule exclusivity, Tasty has a more specialized angle.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### Tasty vs vanilla-extract
|
|
219
|
+
|
|
220
|
+
vanilla-extract is a lower-level foundation.
|
|
221
|
+
|
|
222
|
+
It gives teams a zero-runtime TypeScript-native way to generate CSS, plus strong theming primitives and the ability to build architecture on top. It is excellent when a team wants maximum control over structure while staying close to normal CSS semantics.
|
|
223
|
+
|
|
224
|
+
That last point matters.
|
|
225
|
+
|
|
226
|
+
With vanilla-extract, styles are still fundamentally governed by **standard CSS behavior**. Ordering, layering, and media-query structure still matter in the usual CSS sense. That is not a flaw; it is simply a different abstraction level.
|
|
227
|
+
|
|
228
|
+
Tasty is more opinionated.
|
|
229
|
+
|
|
230
|
+
It behaves less like "TypeScript that outputs CSS" and more like a **state-aware style compiler**. It is designed to encode higher-level styling semantics rather than only expose CSS primitives in typed form.
|
|
231
|
+
|
|
232
|
+
This also makes Tasty's static mode notable:
|
|
233
|
+
|
|
234
|
+
- Runtime `tasty()` creates React components with dynamic injection
|
|
235
|
+
- `tastyStatic()` with the Babel plugin produces static class name strings with zero runtime overhead
|
|
236
|
+
- In static mode, the output is plain CSS + class names, so it can be used with any JavaScript framework — not only React
|
|
237
|
+
|
|
238
|
+
Runtime features like `styleProps`, sub-element components, and dynamic variants are React-specific. The static path is framework-agnostic.
|
|
239
|
+
|
|
240
|
+
So the tradeoff is roughly:
|
|
241
|
+
|
|
242
|
+
- **vanilla-extract**: lower-level, static, explicit, architecture left to the team
|
|
243
|
+
- **Tasty**: more opinionated, more state-aware, more language-defining
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### Tasty vs StyleX
|
|
248
|
+
|
|
249
|
+
This comparison needs extra precision, because both systems care about predictability, but not in the same way.
|
|
250
|
+
|
|
251
|
+
StyleX is a compiler-based atomic system with strong guarantees around consistency and composition. Its model is designed to avoid many classic CSS pitfalls such as accidental rule collisions and specificity-driven unpredictability.
|
|
252
|
+
|
|
253
|
+
That is real value.
|
|
254
|
+
|
|
255
|
+
But it is still a different kind of guarantee from Tasty's.
|
|
256
|
+
|
|
257
|
+
StyleX predictability comes from:
|
|
258
|
+
|
|
259
|
+
- atomic decomposition
|
|
260
|
+
- compiler control
|
|
261
|
+
- constrained composition
|
|
262
|
+
- normalized style behavior
|
|
263
|
+
|
|
264
|
+
Tasty's differentiator is stronger in a specific area:
|
|
265
|
+
|
|
266
|
+
- **stateful per-property resolution**
|
|
267
|
+
- **mutually exclusive selectors**
|
|
268
|
+
- **conflict avoidance by construction**, not only by atomic normalization
|
|
269
|
+
|
|
270
|
+
So "collision-free atomic CSS" should not be treated as equivalent to Tasty's approach.
|
|
271
|
+
|
|
272
|
+
A better framing is:
|
|
273
|
+
|
|
274
|
+
- **StyleX** provides compiler-controlled atomic predictability
|
|
275
|
+
- **Tasty** provides mutually exclusive selector resolution for stateful component styling
|
|
276
|
+
|
|
277
|
+
That makes Tasty especially interesting when the hardest problem is not just style composition, but **complex intersecting component states**.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
### Tasty vs Stitches (deprecated) / Emotion
|
|
282
|
+
|
|
283
|
+
Stitches and Emotion are component-first styling systems. (Note: Stitches has been archived and is no longer maintained. It is included here because it remains widely referenced in comparisons.)
|
|
284
|
+
|
|
285
|
+
They optimize for developer experience, flexible composition, reusable styled primitives, and ergonomic component authoring. For many teams, that is exactly the right abstraction level.
|
|
286
|
+
|
|
287
|
+
Tasty targets a different question.
|
|
288
|
+
|
|
289
|
+
It is less focused on "how do I style this component ergonomically right now?" and more focused on:
|
|
290
|
+
|
|
291
|
+
- what styling language should this design system expose?
|
|
292
|
+
- how should states be modeled?
|
|
293
|
+
- what should be allowed or constrained?
|
|
294
|
+
- how do we keep style behavior deterministic as the system grows?
|
|
295
|
+
|
|
296
|
+
So while Stitches and Emotion are strong tools for building components, Tasty is more naturally positioned as a **styling substrate for the design system itself**.
|
|
297
|
+
|
|
298
|
+
That makes it narrower in audience, but deeper in architectural ambition.
|
|
299
|
+
|
|
300
|
+
Tasty's runtime performance is also validated in enterprise-scale applications where styling overhead is not noticeable in normal UI flows — an important consideration for teams evaluating runtime CSS-in-JS at scale.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Build-time vs runtime
|
|
305
|
+
|
|
306
|
+
Tasty is not limited to one execution model.
|
|
307
|
+
|
|
308
|
+
It can be used as a styling system with runtime behavior, but it can also be used as a **fully build-time style compiler** when that is the right fit.
|
|
309
|
+
|
|
310
|
+
That distinction matters.
|
|
311
|
+
|
|
312
|
+
In runtime mode, `tasty()` creates React components with dynamic style injection, `styleProps`, sub-element components, and variants. This path is React-specific.
|
|
313
|
+
|
|
314
|
+
In build-time mode, `tastyStatic()` with the Babel plugin generates plain static class names and CSS files. The output is framework-agnostic — any JavaScript framework can consume the resulting class names and CSS. This makes Tasty usable as the compiler layer underneath a design-system implementation, even outside the React ecosystem.
|
|
315
|
+
|
|
316
|
+
The tradeoff is that some capabilities — `styleProps`, sub-element components (`<Card.Title>`), dynamic variants — are tied to the runtime path. The static path is best understood as extraction and compilation of the DSL, tokens, and state logic.
|
|
317
|
+
|
|
318
|
+
This flexibility is one of Tasty's more unusual strengths:
|
|
319
|
+
|
|
320
|
+
- it can be used as a full authoring/runtime system for React
|
|
321
|
+
- or as a static compiler whose output works with any framework
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Comparison by abstraction level
|
|
326
|
+
|
|
327
|
+
Another useful way to think about the ecosystem is by abstraction level.
|
|
328
|
+
|
|
329
|
+
### Direct styling tools
|
|
330
|
+
These are optimized for styling product code directly.
|
|
331
|
+
|
|
332
|
+
Examples:
|
|
333
|
+
- Tailwind CSS
|
|
334
|
+
- Emotion
|
|
335
|
+
- Stitches (deprecated)
|
|
336
|
+
|
|
337
|
+
### Typed styling engines
|
|
338
|
+
These are optimized for generating CSS with stronger structure and tooling.
|
|
339
|
+
|
|
340
|
+
Examples:
|
|
341
|
+
- Panda CSS
|
|
342
|
+
- vanilla-extract
|
|
343
|
+
- StyleX
|
|
344
|
+
|
|
345
|
+
### Design-system language engines
|
|
346
|
+
These are optimized for helping a team define its own styling grammar and semantics.
|
|
347
|
+
|
|
348
|
+
Tasty belongs most naturally here.
|
|
349
|
+
|
|
350
|
+
That is why generic "feature matrix" comparisons often miss the point. Tasty is not only trying to style elements. It is trying to help define **how a design system talks about styling**.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## When Tasty is a strong fit
|
|
355
|
+
|
|
356
|
+
Tasty makes the most sense when:
|
|
357
|
+
|
|
358
|
+
- a real design system exists or is being built
|
|
359
|
+
- styling should be governed through a central platform team
|
|
360
|
+
- component state logic is complex
|
|
361
|
+
- the team wants a house styling language instead of raw CSS-shaped authoring
|
|
362
|
+
- tokens, recipes, and sub-elements should be first-class
|
|
363
|
+
- deterministic state resolution matters more than minimum abstraction overhead
|
|
364
|
+
- the styling engine may need to work as either a runtime tool or a build-time compiler
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## When another tool may be a better fit
|
|
369
|
+
|
|
370
|
+
A different tool may be more appropriate when:
|
|
371
|
+
|
|
372
|
+
- the main goal is styling app code directly with minimal setup
|
|
373
|
+
- the team prefers a shared framework vocabulary over a custom design-system language
|
|
374
|
+
- the complexity of intersecting states is low
|
|
375
|
+
- low ceremony matters more than central governance
|
|
376
|
+
- the team wants static CSS primitives without a more opinionated state model
|
|
377
|
+
- component-level DX is the primary optimization target
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Summary
|
|
382
|
+
|
|
383
|
+
Tasty is not best compared as "another CSS framework."
|
|
384
|
+
|
|
385
|
+
Its more meaningful comparison point is this:
|
|
386
|
+
|
|
387
|
+
> Tasty is a styling engine for building a design-system-defined authoring language, with a particular focus on explicit state semantics and mutually exclusive selector resolution.
|
|
388
|
+
|
|
389
|
+
That puts it in a different category from:
|
|
390
|
+
|
|
391
|
+
- utility-first tools that optimize for direct authoring
|
|
392
|
+
- component-first CSS-in-JS libraries that optimize for DX
|
|
393
|
+
- typed static CSS systems that expose lower-level primitives
|
|
394
|
+
- atomic compilers that focus on normalized composition
|
|
395
|
+
|
|
396
|
+
Those systems are all useful, but they optimize for different layers.
|
|
397
|
+
|
|
398
|
+
Tasty is most compelling when the problem is not just "how do we write styles," but:
|
|
399
|
+
|
|
400
|
+
> "How do we define a scalable, deterministic styling model for the design system itself?"
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
## Learn more
|
|
405
|
+
|
|
406
|
+
- [README](../README.md) — overview, quick start, and feature highlights
|
|
407
|
+
- [Style DSL](dsl.md) — state maps, tokens, units, extending semantics, keyframes, @property
|
|
408
|
+
- [Runtime API](runtime.md) — `tasty()` factory, component props, variants, sub-elements, hooks
|
|
409
|
+
- [Style Properties](styles.md) — complete reference for all enhanced style properties
|
|
410
|
+
- [Configuration](configuration.md) — tokens, recipes, custom units, style handlers, and TypeScript extensions
|
|
411
|
+
- [Zero Runtime (tastyStatic)](tasty-static.md) — build-time static styling with Babel plugin
|
|
412
|
+
- [Adoption Guide](adoption.md) — where Tasty sits in the stack, incremental adoption, and what changes for product engineers
|
|
413
|
+
- [Server-Side Rendering](ssr.md) — SSR setup for Next.js, Astro, and generic frameworks
|
package/docs/configuration.md
CHANGED
|
@@ -45,10 +45,11 @@ configure({
|
|
|
45
45
|
| `nonce` | `string` | - | CSP nonce for style elements |
|
|
46
46
|
| `states` | `Record<string, string>` | - | Global state aliases for advanced state mapping |
|
|
47
47
|
| `parserCacheSize` | `number` | `1000` | Parser LRU cache size |
|
|
48
|
-
| `units` | `Record<string, string \| Function>` | Built-in | Custom units (merged with built-in). See [built-in units](
|
|
48
|
+
| `units` | `Record<string, string \| Function>` | Built-in | Custom units (merged with built-in). See [built-in units](dsl.md#built-in-units) |
|
|
49
49
|
| `funcs` | `Record<string, Function>` | - | Custom parser functions (merged with existing) |
|
|
50
50
|
| `handlers` | `Record<string, StyleHandlerDefinition>` | Built-in | Custom style handlers (replace built-in) |
|
|
51
|
-
| `tokens` | `Record<string,
|
|
51
|
+
| `tokens` | `Record<string, value \| stateMap>` | - | Design tokens injected as `:root` CSS custom properties |
|
|
52
|
+
| `replaceTokens` | `Record<string, string \| number>` | - | Parse-time token substitution (inline replacement) |
|
|
52
53
|
| `keyframes` | `Record<string, KeyframesSteps>` | - | Global keyframes for animations |
|
|
53
54
|
| `properties` | `Record<string, PropertyDefinition>` | - | Global CSS @property definitions |
|
|
54
55
|
| `autoPropertyTypes` | `boolean` | `true` | Auto-infer and register `@property` types from values |
|
|
@@ -56,26 +57,56 @@ configure({
|
|
|
56
57
|
|
|
57
58
|
---
|
|
58
59
|
|
|
59
|
-
##
|
|
60
|
+
## Design Tokens
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
Design tokens define CSS custom properties on `:root`. They are injected automatically when the first style is rendered. Values are parsed through the Tasty DSL, so you can use units, color syntax, and other DSL features.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
Tokens support state maps for responsive or theme-aware values:
|
|
64
65
|
|
|
65
66
|
```jsx
|
|
66
67
|
configure({
|
|
67
68
|
tokens: {
|
|
69
|
+
'$gap': '4px',
|
|
70
|
+
'$radius': '6px',
|
|
71
|
+
'#primary': {
|
|
72
|
+
'': '#purple',
|
|
73
|
+
'@dark': '#light-purple',
|
|
74
|
+
},
|
|
75
|
+
'$font-size': {
|
|
76
|
+
'': '14px',
|
|
77
|
+
'@mobile': '12px',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `$name` keys become `--name` CSS custom properties
|
|
84
|
+
- `#name` keys become `--name-color` and `--name-color-rgb` properties
|
|
85
|
+
|
|
86
|
+
Tokens are automatically emitted in all rendering modes: runtime (client), SSR, and zero-runtime (Babel plugin).
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Replace Tokens (Parse-Time Substitution)
|
|
91
|
+
|
|
92
|
+
Replace tokens are **substituted inline at parse time** — they are baked into the generated CSS, not resolved via CSS custom properties at runtime. This makes them ideal for value aliases and shorthand references.
|
|
93
|
+
|
|
94
|
+
Use `$name` for value tokens and `#name` for color token aliases:
|
|
95
|
+
|
|
96
|
+
```jsx
|
|
97
|
+
configure({
|
|
98
|
+
replaceTokens: {
|
|
68
99
|
$spacing: '2x',
|
|
69
100
|
'$card-padding': '4x',
|
|
70
|
-
'$button-height': '40px',
|
|
71
101
|
'#accent': '#purple',
|
|
72
|
-
'#surface': '#white',
|
|
73
102
|
'#surface-hover': '#gray.05',
|
|
74
103
|
},
|
|
75
104
|
});
|
|
76
105
|
```
|
|
77
106
|
|
|
78
|
-
|
|
107
|
+
When a component uses `padding: '$card-padding'`, the parser replaces it with `'4x'` before generating CSS. When a component uses `fill: '#accent'`, it is replaced with `'#purple'`, which in turn resolves to `var(--purple-color)`.
|
|
108
|
+
|
|
109
|
+
See [Replace Tokens](dsl.md#replace-tokens) in the Style DSL reference.
|
|
79
110
|
|
|
80
111
|
---
|
|
81
112
|
|
|
@@ -101,7 +132,7 @@ configure({
|
|
|
101
132
|
|
|
102
133
|
Recipe values are flat tasty styles (no sub-element keys). They may contain base styles, tokens, local states, `@keyframes`, and `@properties`. Recipes cannot reference other recipes.
|
|
103
134
|
|
|
104
|
-
For how to apply, compose, and override recipes in components, see [
|
|
135
|
+
For how to apply, compose, and override recipes in components, see [Recipes](dsl.md#recipes) in the Style DSL reference.
|
|
105
136
|
|
|
106
137
|
---
|
|
107
138
|
|
|
@@ -208,4 +239,4 @@ declare module '@tenphi/tasty' {
|
|
|
208
239
|
}
|
|
209
240
|
```
|
|
210
241
|
|
|
211
|
-
See [
|
|
242
|
+
See [Style DSL](dsl.md) for state maps, tokens, units, and extending semantics, and [Runtime API](runtime.md) for `tasty()`, hooks, and component props.
|
package/docs/debug.md
CHANGED
|
@@ -502,4 +502,4 @@ tastyDebug.chunks({ root: shadowRoot, log: true });
|
|
|
502
502
|
|
|
503
503
|
`tastyDebug` reads directly from the [Style Injector](./injector.md)'s internal registries. It does not inject, modify, or intercept any styles. The `cleanup()` method is the only method with side effects — it triggers the injector's garbage collection for unused styles.
|
|
504
504
|
|
|
505
|
-
For most development, you'll use the [
|
|
505
|
+
For most development, you'll use the [Runtime API](./runtime.md) to create components and the debug utilities to inspect the resulting CSS at runtime.
|