Skip to content

Commit 625b9cd

Browse files
authored
Merge pull request #95 from tenphi/feat-token-props
feat: token props
2 parents 1b8f7ca + a45edd7 commit 625b9cd

File tree

7 files changed

+637
-31
lines changed

7 files changed

+637
-31
lines changed

.changeset/swift-tokens-shine.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tenphi/tasty': minor
3+
---
4+
5+
Add `tokenProps` option to `tasty()` for exposing token keys as top-level component props. Supports array form (with `Color` suffix convention for color tokens) and object form (explicit `$`/`#` mapping).

docs/methodology.md

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,54 @@ The `tokens` prop sets `style="--progress: 75%"` on the DOM element. The `$progr
256256

257257
Design tokens (via `configure({ tokens })`) are injected as CSS custom properties on `:root`. Replace tokens (via `configure({ replaceTokens })`) are resolved at parse time and baked into the generated CSS. The `tokens` prop on components is resolved at render time via inline CSS custom properties. Use design tokens for design-system constants, replace tokens for value aliases, and the `tokens` prop for truly dynamic per-instance values.
258258

259+
### tokenProps
260+
261+
`tokenProps` expose token keys as top-level component props — the token equivalent of `styleProps` and `modProps`. Use them when a component has a fixed set of known dynamic token values.
262+
263+
#### Array form
264+
265+
Prop names are plain camelCase identifiers. Names ending in `Color` map to `#` color tokens; everything else maps to `$` custom property tokens:
266+
267+
```tsx
268+
const ProgressBar = tasty({
269+
tokenProps: ['progress', 'accentColor'] as const,
270+
styles: { width: '$progress', fill: '#accent' },
271+
});
272+
273+
// Clean prop API — no tokens object needed
274+
<ProgressBar progress="75%" accentColor="#purple" />
275+
276+
// Conversion:
277+
// 'progress' → $progress → --progress
278+
// 'accentColor' → #accent → --accent-color + --accent-color-oklch
279+
```
280+
281+
#### Object form
282+
283+
Keys are prop names; values are `$`/`#`-prefixed token keys. No suffix convention needed — the prefix in the value is explicit:
284+
285+
```tsx
286+
const Card = tasty({
287+
tokenProps: {
288+
size: '$card-size',
289+
color: '#card-accent',
290+
},
291+
styles: { padding: '$card-size', fill: '#card-accent' },
292+
});
293+
294+
<Card size="4x" color="#purple" />
295+
```
296+
297+
#### Merge order
298+
299+
When all three token sources are present, values merge with increasing priority:
300+
301+
1. `tokens` option in `tasty({...})` — default tokens (lowest)
302+
2. `tokens` prop on the component instance — runtime overrides
303+
3. `tokenProps`-derived values — highest priority (explicit named props win)
304+
305+
The `tokens` prop remains available for ad-hoc or dynamic tokens alongside `tokenProps`.
306+
259307
---
260308

261309
## styles prop vs style prop
@@ -458,7 +506,8 @@ See [Configuration](configuration.md) for the full `configure()` API.
458506
- **Use `elements` prop** to declare typed sub-components for compound components
459507
- **Use `styleProps`** to define what product engineers can customize
460508
- **Use `modProps`** to expose known modifier states as clean component props
461-
- **Use `tokens` prop** for per-instance dynamic values (progress, user color)
509+
- **Use `tokenProps`** to expose known token keys as clean component props
510+
- **Use `tokens` prop** for ad-hoc or dynamic per-instance token values (progress, user color)
462511
- **Use modifiers** (`mods` or `modProps`) for state-driven style changes instead of runtime `styles` prop changes
463512

464513
### Avoid

docs/runtime.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,75 @@ For architecture guidance on when to use modifiers vs `styleProps`, see [Methodo
154154

155155
---
156156

157+
## Token Props
158+
159+
Use `tokenProps` to expose token keys as direct component props instead of requiring the `tokens` object:
160+
161+
```jsx
162+
// Before: tokens object
163+
<ProgressBar tokens={{ $progress: '75%', '#accent': '#purple' }} />
164+
165+
// After: token props
166+
<ProgressBar progress="75%" accentColor="#purple" />
167+
```
168+
169+
### Array form
170+
171+
List prop names. Names ending in `Color` map to `#` color tokens; everything else maps to `$` custom property tokens:
172+
173+
```jsx
174+
const ProgressBar = tasty({
175+
tokenProps: ['progress', 'accentColor'] as const,
176+
styles: { width: '$progress', fill: '#accent' },
177+
});
178+
179+
<ProgressBar progress="75%" accentColor="#purple" />
180+
// 'progress' → $progress → --progress
181+
// 'accentColor' → #accent → --accent-color + --accent-color-oklch
182+
```
183+
184+
### Object form
185+
186+
Map prop names to explicit `$`/`#`-prefixed token keys:
187+
188+
```tsx
189+
const Card = tasty({
190+
tokenProps: {
191+
size: '$card-size',
192+
color: '#card-accent',
193+
},
194+
styles: { padding: '$card-size', fill: '#card-accent' },
195+
});
196+
197+
<Card size="4x" color="#purple" />
198+
```
199+
200+
### Merge with `tokens`
201+
202+
Token props and the `tokens` prop can be used together. Token props take precedence over `tokens`, which takes precedence over default `tokens` in `tasty({...})`:
203+
204+
```jsx
205+
const Bar = tasty({
206+
tokenProps: ['progress'] as const,
207+
tokens: { $progress: '0%' }, // default
208+
});
209+
210+
<Bar tokens={{ $progress: '50%' }} progress="90%" />
211+
// progress="90%" wins (from token prop)
212+
```
213+
214+
### When to use `tokenProps` vs `tokens`
215+
216+
| Use case | Recommendation |
217+
|---|---|
218+
| Component has a fixed set of known token keys | `tokenProps` — cleaner API, better TypeScript autocomplete |
219+
| Component needs arbitrary/dynamic token values | `tokens` — open-ended `Record<string, TokenValue>` |
220+
| Both fixed and dynamic | Combine: `tokenProps` for known keys, `tokens` for ad-hoc |
221+
222+
For architecture guidance, see [Methodology — tokenProps](methodology.md#tokenprops).
223+
224+
---
225+
157226
## Variants
158227

159228
Define named style variations. Only CSS for variants actually used at runtime is injected:

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export type {
4343
ModPropsInput,
4444
ResolveModProps,
4545
ResolveModPropDef,
46+
TokenPropsInput,
47+
ResolveTokenProps,
4648
} from './tasty';
4749
export type {
4850
AllBaseProps,

0 commit comments

Comments
 (0)