@uncinq/component-tokens 1.9.2 → 1.10.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/docs/_index.md ADDED
@@ -0,0 +1,102 @@
1
+ ---
2
+ isIndex: false
3
+ title: component-tokens
4
+ description: Component-scoped CSS design tokens, layer 3 of the architecture, mapping semantic values onto the parts of a component.
5
+ weight: 3
6
+ icon: puzzle
7
+ ---
8
+
9
+ Component tokens are CSS custom properties scoped to a single UI component. They sit at the top of the [DTCG](dtcg/) three-layer model.
10
+
11
+ ```
12
+ primitive → semantic → component
13
+ (raw values) (purpose) (component-scoped)
14
+ ```
15
+
16
+ Where primitive and semantic tokens come from [@uncinq/design-tokens](../design-tokens/), component tokens map those semantic values onto specific parts of a component.
17
+
18
+ ```css
19
+ /* semantic token, from @uncinq/design-tokens */
20
+ --color-brand: var(--color-sienna-600);
21
+
22
+ /* component token, from this package */
23
+ --btn-color-background: var(--color-brand);
24
+ ```
25
+
26
+ A component token answers **"which semantic value does this part of this component use?"**.
27
+
28
+ ## Why the indirection is worth it
29
+
30
+ A component could read `--color-brand` directly. The extra hop buys two things.
31
+
32
+ **A seam to override.** A project can restyle buttons alone by setting `--btn-color-background`, without touching the brand color and therefore without moving every other branded element.
33
+
34
+ **A place to record intent.** `--btn-color-text: var(--color-text-on-brand)` documents that button text has to contrast against the brand color, which is an accessibility decision. Read directly, that decision would be invisible.
35
+
36
+ The rule that keeps the indirection honest: a component token **always references a semantic token**, never a raw value and never a primitive. When you find yourself wanting a raw value, the semantic layer is usually missing a token.
37
+
38
+ ## What is covered
39
+
40
+ 26 components, one JSON source and one generated CSS file each, 390 tokens in total.
41
+
42
+ | | | |
43
+ | --- | --- | --- |
44
+ | `alert` | `figure` | `map` |
45
+ | `badge` | `heading` | `media` |
46
+ | `breadcrumb` | `hero` | `modal` |
47
+ | `button` | `item` | `nav` |
48
+ | `card` | `items` | `pagination` |
49
+ | `carousel` | `link` | `surtitle` |
50
+ | `container` | `list` | `table` |
51
+ | `details` | `logo` | |
52
+ | `drawer` | | |
53
+ | `dropdown` | | |
54
+ | `embed` | | |
55
+
56
+ `card` is an alias layer over `item`, which is the canonical card-like unit. See the [Reference](reference/) for what each one actually declares.
57
+
58
+ ## Installation
59
+
60
+ This package resolves its references against `@uncinq/design-tokens`, which must be imported first.
61
+
62
+ ```bash
63
+ npm install @uncinq/design-tokens @uncinq/component-tokens
64
+ ```
65
+
66
+ ```css
67
+ @import '@uncinq/design-tokens';
68
+ @import '@uncinq/component-tokens';
69
+ ```
70
+
71
+ Per component, when you only need a few:
72
+
73
+ ```css
74
+ @import '@uncinq/design-tokens';
75
+ @import '@uncinq/component-tokens/css/components/button.css';
76
+ @import '@uncinq/component-tokens/css/components/badge.css';
77
+ ```
78
+
79
+ Without a build step:
80
+
81
+ ```html
82
+ <link rel="stylesheet" href="https://unpkg.com/@uncinq/design-tokens">
83
+ <link rel="stylesheet" href="https://unpkg.com/@uncinq/component-tokens">
84
+ ```
85
+
86
+ Import order matters here in a way it does not for most packages. These tokens are `var()` references, resolved by the browser at use time rather than at import time, so a missing design-tokens import does not error: it silently yields invalid values and unstyled components.
87
+
88
+ ## Where to go next
89
+
90
+ | Page | Covers |
91
+ | --- | --- |
92
+ | [Naming](naming/) | The naming grammar and the rules that keep it consistent |
93
+ | [Customizing](customizing/) | Overriding a component token, and when to add one |
94
+ | [Reference](reference/) | Every token for all 26 components, generated from the sources |
95
+ | [DTCG format](dtcg/) | The authoring format, including group-level types |
96
+ | [Style Dictionary](style-dictionary/) | The build, and how cross-package references resolve |
97
+
98
+ ## References
99
+
100
+ - [@uncinq/design-tokens](https://github.com/uncinq/design-tokens), the primitive and semantic layers
101
+ - [@uncinq/css-components](https://github.com/uncinq/css-components), the CSS that consumes these tokens
102
+ - [DTCG specification](https://tr.designtokens.org/format/)
@@ -0,0 +1,75 @@
1
+ ---
2
+ isIndex: false
3
+ title: Customizing
4
+ description: How to override a component token, which layer to reach for, and when a new token is warranted.
5
+ weight: 2
6
+ ---
7
+
8
+ ## CSS override
9
+
10
+ Every token is declared in `@layer tokens`, the lowest-priority layer in the recommended order. Re-declare any of them in your own `@layer tokens` block after the import. Same layer, later source order wins, and no specificity escalation is needed.
11
+
12
+ ```css
13
+ @import '@uncinq/design-tokens';
14
+ @import '@uncinq/component-tokens';
15
+
16
+ @layer tokens {
17
+ :root {
18
+ --btn-color-background: var(--color-light);
19
+ --btn-border-radius: 0;
20
+ --hero-height: 80svh;
21
+ }
22
+ }
23
+ ```
24
+
25
+ ## Choosing the right layer to override
26
+
27
+ This is the decision that matters, and it is easy to get wrong in a way that only shows up later.
28
+
29
+ | You want to change | Override | Effect |
30
+ | --- | --- | --- |
31
+ | The brand color everywhere | `--color-brand` (semantic) | Every component reading brand follows |
32
+ | Buttons only | `--btn-color-background` (component) | Buttons alone, brand untouched |
33
+ | One button variant | The variant's own token, or a local scope | Narrower still |
34
+
35
+ Reach for the **semantic** layer by default. Overriding a component token is the right call only when you genuinely mean "buttons differ from everything else here". Doing it because it was the first token you found produces a design system that drifts component by component, which is the exact failure mode the three-layer split exists to prevent.
36
+
37
+ ## Scoped overrides
38
+
39
+ Because these are custom properties, they inherit. Setting one on a container rather than on `:root` restyles a region without a new class or a new token.
40
+
41
+ ```css
42
+ .promo-section {
43
+ --btn-color-background: var(--color-light);
44
+ --btn-color-text: var(--color-text-on-light);
45
+ }
46
+ ```
47
+
48
+ Every button inside `.promo-section` picks it up. This is usually better than inventing `--btn-promo-color-background`, because the variation is contextual rather than a new permanent concept.
49
+
50
+ Note that this works outside `@layer tokens` too. A scoped override is a normal declaration on a normal selector, so it competes on specificity like any other rule, not on layer order.
51
+
52
+ ## Adding a token
53
+
54
+ Only add a component token when a component genuinely needs a knob that does not exist. Before doing so, check three things:
55
+
56
+ 1. **Does a semantic token already express it?** If so, reference it rather than creating a new name.
57
+ 2. **Does the semantic layer need it instead?** If two components would want the same value for the same reason, it belongs in [@uncinq/design-tokens](../../design-tokens/), not here.
58
+ 3. **Does the name follow the grammar?** See [Naming](../naming/). A token that does not sort with its siblings will be missed by whoever looks for it next.
59
+
60
+ To add one, edit the JSON source and rebuild:
61
+
62
+ ```bash
63
+ npm install
64
+ npm run build
65
+ ```
66
+
67
+ Nothing else needs updating. Both the per-component CSS and `dist/css/index.css` are generated from files discovered on disk, so a new `tokens/components/*.json` is picked up automatically. See [Style Dictionary](../style-dictionary/).
68
+
69
+ ## What not to do
70
+
71
+ **Do not edit `dist/`.** Every file there carries a generated header and is overwritten on the next build.
72
+
73
+ **Do not override a token to a raw value when a semantic one exists.** `--btn-color-background: #3f51b5` works, but it leaves dark mode, theming and contrast pairing behind. `var(--color-indigo-600)` keeps the value inside the system.
74
+
75
+ **Do not fork the package to change values.** The CSS override above exists so that you do not have to. A fork means inheriting the maintenance of 26 components for what is usually a handful of lines.
package/docs/dtcg.md ADDED
@@ -0,0 +1,249 @@
1
+ ---
2
+ isIndex: false
3
+ title: DTCG format
4
+ description: The Design Tokens Community Group JSON format as used for component tokens, including group-level types.
5
+ weight: 4
6
+ ---
7
+
8
+
9
+ The [W3C Design Token Community Group (DTCG)](https://www.w3.org/community/design-tokens/) defines a standard interchange format for design tokens, so they can travel between tools (Figma, code, documentation) without loss of meaning.
10
+
11
+ `@uncinq/design-tokens` uses DTCG JSON as its source format. [Style Dictionary v5](https://styledictionary.com/) transforms those JSON files into CSS custom properties — see [STYLE-DICTIONARY.md](STYLE-DICTIONARY.md) for the build pipeline. The DTCG spec informs the architecture (primitive → semantic → component, naming conventions, token types).
12
+
13
+ ---
14
+
15
+ ## The DTCG format
16
+
17
+ The [DTCG spec](https://tr.designtokens.org/format/) defines tokens as JSON objects with reserved `$`-prefixed keys:
18
+
19
+ ```json
20
+ {
21
+ "color": {
22
+ "brand": {
23
+ "$value": "oklch(0.530 0.195 22.0)",
24
+ "$type": "color",
25
+ "$description": "Primary brand color — used for CTAs and highlights."
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ > **Note on OKLCH:** The DTCG `color` type accepts any valid CSS color value, including `oklch(…)`. `@uncinq/design-tokens` uses OKLCH throughout — perceptually uniform, wide-gamut, and natively supported in modern browsers.
32
+
33
+ | Key | Required | Description |
34
+ | --- | --- | --- |
35
+ | `$value` | ✅ | The token's value |
36
+ | `$type` | recommended | The token type (see below) |
37
+ | `$description` | optional | Human-readable documentation |
38
+
39
+ ---
40
+
41
+ ## DTCG token types
42
+
43
+ ### Scalar types
44
+
45
+ | Type | Example value | CSS usage |
46
+ | --- | --- | --- |
47
+ | `color` | `oklch(0.530 0.195 22.0)` | `color`, `background-color` |
48
+ | `dimension` | `1rem`, `4px` | `width`, `padding`, `font-size` |
49
+ | `fontFamily` | `"system-ui, sans-serif"` | `font-family` |
50
+ | `fontWeight` | `700` | `font-weight` |
51
+ | `duration` | `300ms` | `transition-duration` |
52
+ | `cubicBezier` | `[0.165, 0.84, 0.44, 1]` | `animation-timing-function` |
53
+ | `number` | `1.5` | `line-height`, `opacity` |
54
+ | `string` | `"uppercase"` | free-form text values |
55
+ | `strokeStyle` | `"solid"`, `"dashed"` | `border-style` |
56
+
57
+ ### Composite types
58
+
59
+ | Type | Shape | CSS usage |
60
+ | --- | --- | --- |
61
+ | `shadow` | `{offsetX, offsetY, blur, spread, color}` | `box-shadow` |
62
+ | `border` | `{width, style, color}` | `border` shorthand |
63
+ | `transition` | `{duration, delay, timingFunction}` | `transition` shorthand |
64
+ | `typography` | `{fontFamily, fontSize, fontWeight, letterSpacing, lineHeight}` | typography rules |
65
+ | `gradient` | `{gradientType, stops[]}` | `background: linear-gradient(…)` |
66
+
67
+ → Full type list: [tr.designtokens.org/format/#types](https://tr.designtokens.org/format/#types)
68
+
69
+ > **Note on `clamp()` values:** DTCG has no native `fluid` type. Fluid tokens (`--font-size-fluid-sm`, `--font-size-fluid-md`, `--spacing-fluid-*`) use `$type: "dimension"` as the closest match — a documented gap in the spec.
70
+
71
+ ---
72
+
73
+ ## Token groups
74
+
75
+ Tokens are organized in nested objects. Groups share a `$type` by inheritance:
76
+
77
+ ```json
78
+ {
79
+ "color": {
80
+ "$type": "color",
81
+ "gray": {
82
+ "100": { "$value": "oklch(0.967 0.003 264.542)" },
83
+ "900": { "$value": "oklch(0.208 0.006 264.542)" }
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ → [tr.designtokens.org/format/#groups](https://tr.designtokens.org/format/#groups)
90
+
91
+ ---
92
+
93
+ ## Naming conventions
94
+
95
+ ### CSS compound properties → camelCase
96
+
97
+ CSS property names that are two words (kebab-case in CSS) are written as a single **camelCase key** — not as a nested group. The `pathToKebab` transform converts them back to kebab-case for the CSS output, so the result is identical either way.
98
+
99
+ | JSON key | CSS custom property |
100
+ | --- | --- |
101
+ | `"fontFamily"` | `--btn-font-family` |
102
+ | `"fontSize"` | `--btn-font-size` |
103
+ | `"fontStyle"` | `--btn-font-style` |
104
+ | `"fontWeight"` | `--btn-font-weight` |
105
+ | `"lineHeight"` | `--btn-line-height` |
106
+ | `"maxHeight"` | `--btn-max-height` |
107
+ | `"maxWidth"` | `--btn-max-width` |
108
+ | `"textDecoration"` | `--btn-text-decoration` |
109
+ | `"textTransform"` | `--btn-text-transform` |
110
+
111
+ ```json
112
+ // ✅ correct
113
+ "btn": {
114
+ "fontSize": { "$value": "{fontSize.sm}", "$type": "dimension" },
115
+ "fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
116
+ }
117
+
118
+ // ❌ wrong
119
+ "btn": {
120
+ "font": {
121
+ "size": { "$value": "{fontSize.sm}", "$type": "dimension" },
122
+ "weight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
123
+ }
124
+ }
125
+ ```
126
+
127
+ **Exception — semantic namespaces:** `border`, `color`, `padding`, `margin`, `shadow` used to group multiple sub-properties stay nested, because the group key itself is not a CSS property compound word.
128
+
129
+ ```json
130
+ // ✅ border as a namespace grouping multiple properties
131
+ "border": {
132
+ "radius": { "$value": "{radius.control}", "$type": "dimension" },
133
+ "width": { "$value": "{border.width.sm}", "$type": "dimension" }
134
+ }
135
+
136
+ // ✅ color as a semantic grouping
137
+ "color": {
138
+ "background": { "$value": "{color.background.default}", "$type": "color" },
139
+ "text": { "$value": "{color.text.default}", "$type": "color" }
140
+ }
141
+ ```
142
+
143
+ ### Logical properties → sub-keys of `padding` / `margin`
144
+
145
+ Sub-axes of `padding` and `margin` use **CSS logical property names** as sub-keys — not physical directions (`x`, `y`, `top`, `bottom`, `left`, `right`).
146
+
147
+ | Sub-key | CSS logical property | Physical equivalent |
148
+ | --- | --- | --- |
149
+ | `"inline"` | `padding-inline` / `margin-inline` | left + right |
150
+ | `"block"` | `padding-block` / `margin-block` | top + bottom |
151
+ | `"inlineStart"` | `padding-inline-start` / `margin-inline-start` | left (LTR) |
152
+ | `"inlineEnd"` | `padding-inline-end` / `margin-inline-end` | right (LTR) |
153
+ | `"blockStart"` | `padding-block-start` / `margin-block-start` | top |
154
+ | `"blockEnd"` | `padding-block-end` / `margin-block-end` | bottom |
155
+
156
+ ```json
157
+ // ✅ correct
158
+ "padding": {
159
+ "inline": { "$value": "{spacing.sm}", "$type": "dimension" },
160
+ "block": { "$value": "{spacing.xs}", "$type": "dimension" }
161
+ }
162
+
163
+ // ❌ wrong
164
+ "padding": {
165
+ "x": { "$value": "{spacing.sm}", "$type": "dimension" },
166
+ "y": { "$value": "{spacing.xs}", "$type": "dimension" }
167
+ }
168
+ ```
169
+
170
+ **Exception — CSS `top`/`bottom`/`left`/`right` as positioning values** (not margin/padding sub-keys) keep their physical names, since they map to CSS position properties, not logical shorthands.
171
+
172
+ ```json
173
+ // ✅ positioning — physical names are correct here
174
+ "sticky": {
175
+ "top": { "$value": "4rem", "$type": "dimension" }
176
+ }
177
+ ```
178
+
179
+ ### States → nested sub-keys
180
+
181
+ Interactive states (`default`, `hover`, `active`, `disabled`…) are expressed as **nested keys** under the property they modify. The `default` key is automatically stripped by the build transform.
182
+
183
+ ```json
184
+ "color": {
185
+ "background": {
186
+ "default": { "$value": "{color.brand.default}", "$type": "color" },
187
+ "hover": { "$value": "{color.brand.hover}", "$type": "color" }
188
+ }
189
+ }
190
+ ```
191
+
192
+ ```css
193
+ /* output */
194
+ --btn-color-background: var(--color-brand);
195
+ --btn-color-background-hover: var(--color-brand-hover);
196
+ ```
197
+
198
+ States and camelCase properties compose naturally:
199
+
200
+ ```json
201
+ "color": {
202
+ "textDecoration": {
203
+ "default": { "$value": "transparent", "$type": "color" },
204
+ "hover": { "$value": "{color.link.default}", "$type": "color" }
205
+ }
206
+ }
207
+ ```
208
+
209
+ ```css
210
+ --btn-color-text-decoration: transparent;
211
+ --btn-color-text-decoration-hover: var(--color-link);
212
+ ```
213
+
214
+ ---
215
+
216
+ ## References (aliases)
217
+
218
+ Tokens can reference other tokens using `{dotted.path}` syntax:
219
+
220
+ ```json
221
+ {
222
+ "color": {
223
+ "link": {
224
+ "default": {
225
+ "$value": "{color.brand.default}",
226
+ "$type": "color"
227
+ }
228
+ }
229
+ }
230
+ }
231
+ ```
232
+
233
+ In CSS, this maps to `var()`:
234
+
235
+ ```css
236
+ --color-link: var(--color-brand);
237
+ ```
238
+
239
+ This is the key mechanism behind the **primitive → semantic → component** hierarchy.
240
+
241
+ → [tr.designtokens.org/format/#alias](https://tr.designtokens.org/format/#alias)
242
+
243
+ ---
244
+
245
+ ## References
246
+
247
+ - [DTCG specification](https://tr.designtokens.org/format/) — W3C Community Group draft
248
+ - [DTCG GitHub](https://github.com/design-tokens/community-group) — issues, discussion
249
+ - [Style Dictionary v5](https://styledictionary.com/) — token build pipeline, see [STYLE-DICTIONARY.md](STYLE-DICTIONARY.md)
package/docs/naming.md ADDED
@@ -0,0 +1,118 @@
1
+ ---
2
+ isIndex: false
3
+ title: Naming
4
+ description: The component token naming grammar, the rules behind it, and why colors invert the usual property order.
5
+ weight: 1
6
+ ---
7
+
8
+ Every component token follows one pattern:
9
+
10
+ ```
11
+ --{component}-{property}-{sub-property?}-{state?}
12
+ ```
13
+
14
+ | Pattern | Example |
15
+ | --- | --- |
16
+ | `--{component}` | `--btn` |
17
+ | `--{component}-{property}` | `--btn-padding-inline` |
18
+ | `--{component}-{property}-{sub-property}` | `--btn-color-text-decoration` |
19
+ | `--{component}-{property}-{state}` | `--btn-color-background-hover` |
20
+
21
+ The property mirrors the CSS property name, so a token reads the same way as the declaration it controls. `--btn-padding-inline` drives `padding-inline`. Colors are the one exception, explained below.
22
+
23
+ ## Rules
24
+
25
+ **Lowercase kebab-case**, always.
26
+
27
+ **Component name first**: `--btn-*`, `--badge-*`, `--hero-*`. This is what makes the tokens greppable and what keeps them sorted together in the generated CSS.
28
+
29
+ **Reference a semantic token whenever the value is a shared design decision.** Colors, spacing, radii, typography and motion should all be `var(--some-semantic-token)`, so that overriding the semantic layer moves every component at once.
30
+
31
+ About 80% of the tokens in this package do exactly that. The remaining fifth carry raw values, and legitimately so. They fall into four groups:
32
+
33
+ | Group | Examples |
34
+ | --- | --- |
35
+ | CSS keywords with no semantic equivalent | `transparent`, `none`, `solid`, `start`, `auto`, `underline` |
36
+ | Identity values | `--badge-border-width: 0`, `--container-max-width-mobile: 100%` |
37
+ | Geometry specific to one component | `--drawer-width: 320px`, `--dropdown-min-width: 12rem`, `--drawer-translate: translateX(100%)` |
38
+ | Content and computed values | `--breadcrumb-separator: "/"`, `--hero-height: clamp(...)`, `--hero-media-brightness: 0.5` |
39
+
40
+ The test to apply is whether another component would ever want the same value for the same reason. If yes, it belongs in the semantic layer and should be referenced from there. If no, a raw value here is correct, and inventing a semantic token for it would only add a hop that means nothing.
41
+
42
+ **States go last**: `-hover`, `-focus`, `-active`, `-disabled`.
43
+
44
+ **Alphabetical order within each group**, with a comment introducing each group once a component has many properties.
45
+
46
+ ```css
47
+ /* Border */
48
+ --btn-border-radius: var(--radius-control);
49
+ --btn-border-width: var(--border-width-sm);
50
+
51
+ /* Color */
52
+ --btn-color-background: var(--color-brand);
53
+ --btn-color-border: var(--color-brand);
54
+ --btn-color-text: var(--color-text-on-brand);
55
+ --btn-color-text-decoration: transparent;
56
+
57
+ /* Spacing */
58
+ --btn-gap: var(--spacing-xs);
59
+ --btn-padding-block: var(--spacing-control);
60
+ --btn-padding-inline: var(--spacing-control);
61
+ ```
62
+
63
+ ## Why colors invert the order
64
+
65
+ For every other property the token mirrors the CSS property name. For colors it does not: `color` leads and the UI role follows.
66
+
67
+ | Token | Role | CSS property it drives |
68
+ | --- | --- | --- |
69
+ | `--btn-color-background` | background | `background-color` |
70
+ | `--btn-color-border` | border | `border-color` |
71
+ | `--btn-color-text` | text | `color` |
72
+ | `--btn-color-text-decoration` | text-decoration | `text-decoration-color` |
73
+ | `--form-color-accent` | accent | `color` |
74
+ | `--input-color-placeholder` | placeholder | `color` |
75
+
76
+ Writing `--btn-background-color` would have been more faithful to CSS, but it scatters a component's colors across the alphabet, between `--btn-border-radius` and `--btn-padding-block`. Leading with `color` groups them into one contiguous block in the generated file and in an editor's autocomplete.
77
+
78
+ It also makes the component token mirror the global one. `--color-background` becomes `--btn-color-background`, so the relationship between the two layers is visible in the name.
79
+
80
+ `background` is never abbreviated. It is `color-background`, never `color-bg`.
81
+
82
+ ## The `default` convention
83
+
84
+ In the JSON source, a state lives in a nested key, and `default` is the unstated one. The build strips it from the generated name.
85
+
86
+ ```json
87
+ {
88
+ "btn": {
89
+ "color": {
90
+ "background": {
91
+ "default": { "$value": "{color.brand.default}", "$type": "color" },
92
+ "hover": { "$value": "{color.brand.hover}", "$type": "color" }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ produces:
100
+
101
+ ```css
102
+ --btn-color-background: var(--color-brand);
103
+ --btn-color-background-hover: var(--color-brand-hover);
104
+ ```
105
+
106
+ Note that the stripping happens on both sides. `{color.brand.default}` becomes `var(--color-brand)`, matching what `@uncinq/design-tokens` actually emits.
107
+
108
+ ## Compound CSS properties
109
+
110
+ A CSS property with a hyphen is written in camelCase in JSON, and the build converts it back.
111
+
112
+ | JSON path | CSS custom property |
113
+ | --- | --- |
114
+ | `btn.paddingInline` | `--btn-padding-inline` |
115
+ | `btn.color.textDecoration` | `--btn-color-text-decoration` |
116
+ | `item.borderRadius` | `--item-border-radius` |
117
+
118
+ Use logical properties (`inline`, `block`, `inlineStart`, `blockEnd`) rather than physical ones (`left`, `right`, `top`, `bottom`), so that a component works in a right-to-left context without a second set of tokens. See [DTCG format](../dtcg/) for the full list of conventions.