@ponchia/ui 0.7.0 → 0.8.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/CHANGELOG.md +133 -0
- package/README.md +3 -3
- package/classes/classes.json +79 -7
- package/classes/index.d.ts +53 -1
- package/classes/index.js +60 -0
- package/classes/vscode.css-custom-data.json +24 -0
- package/css/app.css +14 -3
- package/css/disclosure.css +7 -7
- package/css/feedback.css +11 -8
- package/css/forms.css +3 -3
- package/css/navigation.css +1 -1
- package/css/overlay.css +19 -5
- package/css/primitives.css +101 -6
- package/css/site.css +11 -5
- package/css/skins.css +97 -3
- package/css/state.css +161 -0
- package/css/table.css +1 -1
- package/css/tokens.css +6 -0
- package/css/workbench.css +151 -0
- package/dist/bronto.css +1 -1
- package/dist/css/app.css +1 -1
- package/dist/css/disclosure.css +1 -1
- package/dist/css/feedback.css +1 -1
- package/dist/css/forms.css +1 -1
- package/dist/css/navigation.css +1 -1
- package/dist/css/overlay.css +1 -1
- package/dist/css/primitives.css +1 -1
- package/dist/css/report-kit.css +1 -1
- package/dist/css/site.css +1 -1
- package/dist/css/skins.css +1 -1
- package/dist/css/state.css +1 -1
- package/dist/css/table.css +1 -1
- package/dist/css/tokens.css +1 -1
- package/dist/css/workbench.css +1 -1
- package/docs/adr/0001-color-system.md +32 -3
- package/docs/contrast.md +102 -18
- package/docs/reference.md +52 -1
- package/docs/reporting.md +8 -8
- package/docs/stability.md +31 -2
- package/docs/state.md +51 -1
- package/docs/theming.md +18 -0
- package/docs/usage.md +62 -2
- package/docs/workbench.md +83 -4
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/tokens/figma.variables.json +84 -0
- package/tokens/index.d.ts +2 -2
- package/tokens/index.js +23 -0
- package/tokens/index.json +12 -0
- package/tokens/resolved.json +6 -0
- package/tokens/skins.js +117 -7
- package/tokens/tokens.dtcg.json +7 -1
package/docs/usage.md
CHANGED
|
@@ -167,15 +167,50 @@ a `.ui-legend` key, and fallback data. Full LLM/static report cookbook:
|
|
|
167
167
|
|
|
168
168
|
## Buttons: variant and size
|
|
169
169
|
|
|
170
|
-
- **primary
|
|
170
|
+
- **primary is the bare `ui-button`.** There is no `--primary` and no
|
|
171
|
+
`--accent`: the unmodified class already paints the accent fill, and the
|
|
172
|
+
variants below all step *down* from it. Aim for one per view. Consumers reach
|
|
173
|
+
for a `--primary` or `--accent` modifier often enough that it is worth
|
|
174
|
+
stating plainly: neither exists. Writing one is harmless *and invisible* —
|
|
175
|
+
the unknown class does nothing and the button still looks right, which is why
|
|
176
|
+
the mistake survives review. `bronto-ui-check` is what catches it.
|
|
171
177
|
- **ghost** — secondary actions; the default for "another button here".
|
|
172
178
|
- **subtle** — tertiary / low-stakes (toolbar, inline).
|
|
179
|
+
- **danger** — destructive confirmation.
|
|
173
180
|
- Size: default everywhere; `--sm` for dense tooling (toolbars,
|
|
174
|
-
pagination, table row actions), `--lg` for a hero CTA only
|
|
181
|
+
pagination, table row actions), `--lg` for a hero CTA only, `--dense` when a
|
|
182
|
+
bar's *height* is the constraint (a pane title bar). `--dense` lowers only the
|
|
183
|
+
visual floor — coarse pointers still get the full `--tap-target`, so a control
|
|
184
|
+
you shrink for a mouse is never shrunk for a finger.
|
|
175
185
|
- Loading is **not** a class: set `aria-busy="true"` (+ `disabled`); the
|
|
176
186
|
spinner is CSS. This is the ARIA-driven contract — see reference.md
|
|
177
187
|
→ "Composition & state".
|
|
178
188
|
|
|
189
|
+
## Empty state vs invite
|
|
190
|
+
|
|
191
|
+
Both use `ui-empty-state`, and the slots are the same three parts — a quiet
|
|
192
|
+
`__glyph`, one sentence of full ink in `__lead`, a quieter `__hint`. What
|
|
193
|
+
differs is the job:
|
|
194
|
+
|
|
195
|
+
- **Plain `ui-empty-state`** *reports absence*: a dashed card saying this region
|
|
196
|
+
has no rows today. Use it for a list, a table, a results pane.
|
|
197
|
+
- **`--invite`** *offers the next action*: no dashed box (there is nothing to
|
|
198
|
+
outline — the surface itself is what you are being invited into) and it
|
|
199
|
+
centres in whatever block space it is given. Use it for a surface the user is
|
|
200
|
+
meant to fill.
|
|
201
|
+
|
|
202
|
+
```html
|
|
203
|
+
<div class="ui-empty-state ui-empty-state--invite">
|
|
204
|
+
<span class="ui-empty-state__glyph" aria-hidden="true">+</span>
|
|
205
|
+
<p class="ui-empty-state__lead">Nothing pinned yet</p>
|
|
206
|
+
<p class="ui-empty-state__hint">Drop a file here, or press ⌘K</p>
|
|
207
|
+
</div>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Without the slots, every empty surface in an app re-invents these three parts
|
|
211
|
+
under a different name and they drift — one has a glyph, the next has two
|
|
212
|
+
sentences at the same weight, a third is a bare `<p>`.
|
|
213
|
+
|
|
179
214
|
## Link vs link--cta
|
|
180
215
|
|
|
181
216
|
Plain `ui-link` for in-flow links. `ui-link--cta` is the eyebrow-faced
|
|
@@ -278,6 +313,31 @@ without it these widgets are unlabelled or unannounced:
|
|
|
278
313
|
- **Icon-only buttons** (`ui-button--icon` and any glyph-only control) carry no
|
|
279
314
|
text node, so they're nameless to AT — give them an `aria-label`
|
|
280
315
|
(`<button class="ui-button ui-button--icon" aria-label="Delete">`).
|
|
316
|
+
Prefer `ui-button__label` when the same control also appears with its word
|
|
317
|
+
visible, or when a test reads the button by its text. Wrap the text in the
|
|
318
|
+
slot and let `--icon` decide whether it is painted — the markup does not
|
|
319
|
+
change, the accessible name survives, and no `aria-label` can drift out of
|
|
320
|
+
sync with the visible wording:
|
|
321
|
+
|
|
322
|
+
```js
|
|
323
|
+
// The mask comes from renderGlyph(..., { render: 'mask' }) — there is no
|
|
324
|
+
// --glyph-* token.
|
|
325
|
+
const mask = renderGlyph('trash', { render: 'mask' });
|
|
326
|
+
el.innerHTML =
|
|
327
|
+
`<button class="ui-button ui-button--icon">` +
|
|
328
|
+
`<span class="ui-icon" style="--icon-mask: ${mask}"></span>` +
|
|
329
|
+
`<span class="ui-button__label">Delete</span>` +
|
|
330
|
+
`</button>`;
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Drop `--icon` and the same markup renders glyph + word. The slot also
|
|
334
|
+
ellipsises rather than wrapping, so a labelled button in a width-constrained
|
|
335
|
+
bar shrinks instead of pushing its neighbours out.
|
|
336
|
+
- **`ui-button--dense`** is for bars whose height is the constraint — a pane
|
|
337
|
+
title bar, a packed toolbar, a table row's actions. It lowers only the
|
|
338
|
+
*visual* floor, to the WCAG 2.5.8 24px minimum. The coarse-pointer block
|
|
339
|
+
still floats it to the full `--tap-target`, so a control you shrink for a
|
|
340
|
+
mouse is never shrunk for a finger.
|
|
281
341
|
- **`ui-sitenav` / `ui-app-nav`** — signal the current link with
|
|
282
342
|
`aria-current="page"` (both honour it; `ui-app-nav` also accepts the
|
|
283
343
|
visual-only `.is-active`, but prefer `aria-current`).
|
package/docs/workbench.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Workbench — split panes, toolstrips, inspector, properties, selection bar
|
|
1
|
+
# Workbench — panes, split panes, toolstrips, inspector, properties, selection bar
|
|
2
2
|
|
|
3
3
|
`@ponchia/ui/css/workbench.css` is an opt-in set of primitives for **real
|
|
4
4
|
tools**: resizable split panes, compact toolstrips, button-mode segmented
|
|
@@ -52,6 +52,29 @@ hiding, and placement.
|
|
|
52
52
|
</header>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
### Pane-scale — `.ui-toolstrip--pane`
|
|
56
|
+
|
|
57
|
+
The app has one toolstrip; a workbench full of panes has one *per pane*, and
|
|
58
|
+
those are a different thing. The difference is framing, not density: a pane bar
|
|
59
|
+
is a row inside a surface that already has a border, so it drops its own frame
|
|
60
|
+
and corners and rules off from the content below.
|
|
61
|
+
|
|
62
|
+
It also refuses to wrap. A pane bar usually sits directly above content that may
|
|
63
|
+
be a live terminal, an editor, or a video — and a second row would resize that
|
|
64
|
+
content every time a control appears. The row scrolls instead, and
|
|
65
|
+
`.ui-toolstrip__fill` marks the one element that absorbs slack and gives it back
|
|
66
|
+
first (a title, a path, a filter input), so nothing else is pushed out of reach.
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<div class="ui-toolstrip ui-toolstrip--pane">
|
|
70
|
+
<button class="ui-button ui-button--subtle ui-button--dense" type="button">Run</button>
|
|
71
|
+
<span class="ui-toolstrip__fill ui-mono">src/server/routes/reports.ts</span>
|
|
72
|
+
<button class="ui-button ui-button--ghost ui-button--icon ui-button--dense" type="button">
|
|
73
|
+
<span class="ui-button__label">Close</span>
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
```
|
|
77
|
+
|
|
55
78
|
## Button segmented control — `.ui-segmented-buttons`
|
|
56
79
|
|
|
57
80
|
Use `.ui-segmented-buttons` when each option is a real command button and the
|
|
@@ -170,11 +193,67 @@ A raised bar of actions on the current selection: a `__count` on one side,
|
|
|
170
193
|
</div>
|
|
171
194
|
```
|
|
172
195
|
|
|
196
|
+
### Anchoring a floating bar
|
|
197
|
+
|
|
198
|
+
Both `--floating` bars are raised but position-less, so every consumer
|
|
199
|
+
re-derives the same thing — including the `max(offset, inset)` shape, which is
|
|
200
|
+
the part people get wrong by writing a bare offset that a phone then swallows
|
|
201
|
+
under the home indicator. `--anchored` centres the bar against its positioned
|
|
202
|
+
ancestor and clears the safe area:
|
|
203
|
+
|
|
204
|
+
```html
|
|
205
|
+
<div class="ui-selectionbar ui-selectionbar--anchored">…</div>
|
|
206
|
+
|
|
207
|
+
<!-- The bar that must NOT sit under the thumb: recovery, destructive actions. -->
|
|
208
|
+
<div class="ui-selectionbar ui-selectionbar--anchor-block-start">…</div>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`--anchored` alone means bottom. Override the gap with `--anchor-offset`. The
|
|
212
|
+
host still owns `z-index`, because only it knows what else is on the canvas.
|
|
213
|
+
|
|
214
|
+
## Pane — `.ui-pane`
|
|
215
|
+
|
|
216
|
+
`.ui-panel` is a padded card and `.ui-inspector` is head-plus-body; neither is a
|
|
217
|
+
*window*. A pane is what a canvas node, a floating tool window, or a dockable
|
|
218
|
+
panel needs: a header you can drag, a title that renames in place, an actions
|
|
219
|
+
slot that survives a narrow pane, and a body that owns the rest.
|
|
220
|
+
|
|
221
|
+
```html
|
|
222
|
+
<article class="ui-pane">
|
|
223
|
+
<header class="ui-pane__head">
|
|
224
|
+
<strong class="ui-pane__title">deploy.log</strong>
|
|
225
|
+
<span class="ui-pane__actions">
|
|
226
|
+
<button class="ui-button ui-button--subtle ui-button--icon ui-button--dense" type="button">
|
|
227
|
+
<span class="ui-button__label">Focus</span>
|
|
228
|
+
</button>
|
|
229
|
+
</span>
|
|
230
|
+
</header>
|
|
231
|
+
<div class="ui-pane__body">…</div>
|
|
232
|
+
</article>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Two behaviours are worth knowing, because both come from a real failure:
|
|
236
|
+
|
|
237
|
+
- **The title gives up space first.** It is the only thing in the header that
|
|
238
|
+
can be truncated without losing a function.
|
|
239
|
+
- **`__actions` scrolls rather than pushing.** Sized `flex: 0 1 auto` with
|
|
240
|
+
`overflow-x: auto`, so a pane narrow enough to run out of room scrolls its
|
|
241
|
+
controls instead of pushing the last one past the clipped edge — which is how
|
|
242
|
+
an app ends up with a Focus or Disconnect button that exists, is in the a11y
|
|
243
|
+
tree, and cannot be reached.
|
|
244
|
+
|
|
245
|
+
Swap the title for `.ui-pane__title-input` to rename in place. It inherits the
|
|
246
|
+
type it replaces, so the swap moves no layout; only the accent border says you
|
|
247
|
+
are typing a name now. The host owns dragging, z-order, focus policy and
|
|
248
|
+
persistence — this leaf has no behavior.
|
|
249
|
+
|
|
173
250
|
## Scope
|
|
174
251
|
|
|
175
|
-
No recipes
|
|
176
|
-
|
|
177
|
-
`cls.property`, …).
|
|
252
|
+
No recipes for the structural containers and rows; apply the classes directly
|
|
253
|
+
(or read them from `cls.toolstrip`, `cls.pane`, `cls.splitter`, `cls.inspector`,
|
|
254
|
+
`cls.property`, …). `ui.toolstrip()` and `ui.selectionbar()` exist only to
|
|
255
|
+
compose the variant/anchor modifiers. Pair the selection bar with the
|
|
256
|
+
cross-cutting
|
|
178
257
|
[`ui-sel`](./selection.md) states on the selected items themselves. Bronto styles
|
|
179
258
|
the chrome and wires the splitter affordance; the host owns hit-testing,
|
|
180
259
|
persistence, pane contents, viewport semantics, and commands.
|
package/llms.txt
CHANGED
|
@@ -45,7 +45,7 @@ the path changes from source `css/` to built `dist/css/`:
|
|
|
45
45
|
<!-- installed locally -->
|
|
46
46
|
<link rel="stylesheet" href="./node_modules/@ponchia/ui/dist/css/<leaf>.css" />
|
|
47
47
|
<!-- or from a CDN; pin the version (pre-1.0, breaking changes ship in the minor) -->
|
|
48
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.
|
|
48
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ponchia/ui@0.8.0/dist/css/<leaf>.css" />
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
The flattened default bundle is `dist/bronto.css` (bundler shorthand
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ponchia/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CSS-first identity and UI layer for services, tools, sites, and reports — works in HTML, every framework, and PDF, no component runtime. Shared app shell, forms, tables, workflow chrome, plus opt-in analytical/report primitives. Monochrome with one rationed accent. Zero runtime dependencies.",
|
|
6
6
|
"keywords": [
|
|
@@ -1906,6 +1906,62 @@
|
|
|
1906
1906
|
},
|
|
1907
1907
|
"unit": "px"
|
|
1908
1908
|
},
|
|
1909
|
+
{
|
|
1910
|
+
"name": "safe/area/bottom",
|
|
1911
|
+
"type": "STRING",
|
|
1912
|
+
"sourceCssVariable": "--safe-area-bottom",
|
|
1913
|
+
"valuesByMode": {
|
|
1914
|
+
"global": "env(safe-area-inset-bottom, 0px)"
|
|
1915
|
+
},
|
|
1916
|
+
"$extensions": {
|
|
1917
|
+
"com.ponchia.css": {
|
|
1918
|
+
"variable": "--safe-area-bottom",
|
|
1919
|
+
"value": "env(safe-area-inset-bottom, 0px)"
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
"name": "safe/area/left",
|
|
1925
|
+
"type": "STRING",
|
|
1926
|
+
"sourceCssVariable": "--safe-area-left",
|
|
1927
|
+
"valuesByMode": {
|
|
1928
|
+
"global": "env(safe-area-inset-left, 0px)"
|
|
1929
|
+
},
|
|
1930
|
+
"$extensions": {
|
|
1931
|
+
"com.ponchia.css": {
|
|
1932
|
+
"variable": "--safe-area-left",
|
|
1933
|
+
"value": "env(safe-area-inset-left, 0px)"
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
},
|
|
1937
|
+
{
|
|
1938
|
+
"name": "safe/area/right",
|
|
1939
|
+
"type": "STRING",
|
|
1940
|
+
"sourceCssVariable": "--safe-area-right",
|
|
1941
|
+
"valuesByMode": {
|
|
1942
|
+
"global": "env(safe-area-inset-right, 0px)"
|
|
1943
|
+
},
|
|
1944
|
+
"$extensions": {
|
|
1945
|
+
"com.ponchia.css": {
|
|
1946
|
+
"variable": "--safe-area-right",
|
|
1947
|
+
"value": "env(safe-area-inset-right, 0px)"
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
},
|
|
1951
|
+
{
|
|
1952
|
+
"name": "safe/area/top",
|
|
1953
|
+
"type": "STRING",
|
|
1954
|
+
"sourceCssVariable": "--safe-area-top",
|
|
1955
|
+
"valuesByMode": {
|
|
1956
|
+
"global": "env(safe-area-inset-top, 0px)"
|
|
1957
|
+
},
|
|
1958
|
+
"$extensions": {
|
|
1959
|
+
"com.ponchia.css": {
|
|
1960
|
+
"variable": "--safe-area-top",
|
|
1961
|
+
"value": "env(safe-area-inset-top, 0px)"
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1909
1965
|
{
|
|
1910
1966
|
"name": "sans",
|
|
1911
1967
|
"type": "STRING",
|
|
@@ -2025,6 +2081,34 @@
|
|
|
2025
2081
|
},
|
|
2026
2082
|
"unit": "rem"
|
|
2027
2083
|
},
|
|
2084
|
+
{
|
|
2085
|
+
"name": "tap/target",
|
|
2086
|
+
"type": "STRING",
|
|
2087
|
+
"sourceCssVariable": "--tap-target",
|
|
2088
|
+
"valuesByMode": {
|
|
2089
|
+
"global": "max(44px, 2.9rem)"
|
|
2090
|
+
},
|
|
2091
|
+
"$extensions": {
|
|
2092
|
+
"com.ponchia.css": {
|
|
2093
|
+
"variable": "--tap-target",
|
|
2094
|
+
"value": "max(44px, 2.9rem)"
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
"name": "tap/target/min",
|
|
2100
|
+
"type": "STRING",
|
|
2101
|
+
"sourceCssVariable": "--tap-target-min",
|
|
2102
|
+
"valuesByMode": {
|
|
2103
|
+
"global": "max(24px, 1.6rem)"
|
|
2104
|
+
},
|
|
2105
|
+
"$extensions": {
|
|
2106
|
+
"com.ponchia.css": {
|
|
2107
|
+
"variable": "--tap-target-min",
|
|
2108
|
+
"value": "max(24px, 1.6rem)"
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
},
|
|
2028
2112
|
{
|
|
2029
2113
|
"name": "text/2xs",
|
|
2030
2114
|
"type": "FLOAT",
|
package/tokens/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
export type ThemeName = 'light' | 'dark';
|
|
5
5
|
|
|
6
|
-
export type GlobalTokenName = '--radius-xl' | '--radius-lg' | '--radius-md' | '--radius-sm' | '--radius-pill' | '--space-2xs' | '--space-xs' | '--space-sm' | '--space-md' | '--space-lg' | '--space-xl' | '--space-2xl' | '--mono' | '--sans' | '--dot-font' | '--display' | '--display-weight' | '--display-weight-strong' | '--text-2xs' | '--text-xs' | '--text-sm' | '--text-base' | '--text-lg' | '--text-xl' | '--tracking-wide' | '--tracking-wider' | '--ease-standard' | '--ease-spring' | '--ease-out' | '--duration-fast' | '--duration-base' | '--duration-slow' | '--dot-size' | '--dot-gap' | '--z-base' | '--z-raised' | '--z-sticky' | '--z-overlay' | '--z-popover' | '--z-toast' | '--accent-1' | '--accent-2' | '--accent-3' | '--accent-4' | '--accent-5' | '--accent-6' | '--surface-1' | '--surface-2' | '--surface-3' | '--surface-4' | '--surface-5' | '--surface-6' | '--bronto-color-bg' | '--bronto-color-surface' | '--bronto-color-surface-raised' | '--bronto-color-border' | '--bronto-color-border-strong' | '--bronto-color-text' | '--bronto-color-text-muted' | '--bronto-color-action' | '--bronto-color-on-action' | '--bronto-color-focus' | '--bronto-color-success' | '--bronto-color-warning' | '--bronto-color-danger' | '--bronto-color-info' | '--surface' | '--surface-raised' | '--surface-muted' | '--border' | '--border-strong';
|
|
6
|
+
export type GlobalTokenName = '--radius-xl' | '--radius-lg' | '--radius-md' | '--radius-sm' | '--radius-pill' | '--space-2xs' | '--space-xs' | '--space-sm' | '--space-md' | '--space-lg' | '--space-xl' | '--space-2xl' | '--tap-target' | '--tap-target-min' | '--safe-area-top' | '--safe-area-right' | '--safe-area-bottom' | '--safe-area-left' | '--mono' | '--sans' | '--dot-font' | '--display' | '--display-weight' | '--display-weight-strong' | '--text-2xs' | '--text-xs' | '--text-sm' | '--text-base' | '--text-lg' | '--text-xl' | '--tracking-wide' | '--tracking-wider' | '--ease-standard' | '--ease-spring' | '--ease-out' | '--duration-fast' | '--duration-base' | '--duration-slow' | '--dot-size' | '--dot-gap' | '--z-base' | '--z-raised' | '--z-sticky' | '--z-overlay' | '--z-popover' | '--z-toast' | '--accent-1' | '--accent-2' | '--accent-3' | '--accent-4' | '--accent-5' | '--accent-6' | '--surface-1' | '--surface-2' | '--surface-3' | '--surface-4' | '--surface-5' | '--surface-6' | '--bronto-color-bg' | '--bronto-color-surface' | '--bronto-color-surface-raised' | '--bronto-color-border' | '--bronto-color-border-strong' | '--bronto-color-text' | '--bronto-color-text-muted' | '--bronto-color-action' | '--bronto-color-on-action' | '--bronto-color-focus' | '--bronto-color-success' | '--bronto-color-warning' | '--bronto-color-danger' | '--bronto-color-info' | '--surface' | '--surface-raised' | '--surface-muted' | '--border' | '--border-strong';
|
|
7
7
|
export type LightTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-ramp-end' | '--accent-strong' | '--accent-text' | '--on-accent' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
|
|
8
8
|
export type DarkTokenName = '--bg' | '--bg-elevated' | '--bg-accent' | '--panel' | '--panel-strong' | '--panel-soft' | '--line' | '--line-strong' | '--text' | '--text-soft' | '--text-dim' | '--accent' | '--accent-ramp-end' | '--accent-strong' | '--accent-text' | '--on-accent' | '--accent-soft' | '--success' | '--success-soft' | '--warning' | '--warning-soft' | '--danger' | '--danger-soft' | '--info' | '--info-soft' | '--code-bg' | '--button-text' | '--field-dot' | '--field-dot-hot' | '--field-dot-accent' | '--focus-ring' | '--shadow' | '--shadow-raised';
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ export declare const cssVars: {
|
|
|
14
14
|
dark: Record<DarkTokenName, string>;
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export type ScaleKey = 'radius-xl' | 'radius-lg' | 'radius-md' | 'radius-sm' | 'radius-pill' | 'space-2xs' | 'space-xs' | 'space-sm' | 'space-md' | 'space-lg' | 'space-xl' | 'space-2xl' | 'mono' | 'sans' | 'dot-font' | 'display' | 'display-weight' | 'display-weight-strong' | 'text-2xs' | 'text-xs' | 'text-sm' | 'text-base' | 'text-lg' | 'text-xl' | 'tracking-wide' | 'tracking-wider' | 'ease-standard' | 'ease-spring' | 'ease-out' | 'duration-fast' | 'duration-base' | 'duration-slow' | 'dot-size' | 'dot-gap' | 'z-base' | 'z-raised' | 'z-sticky' | 'z-overlay' | 'z-popover' | 'z-toast' | 'accent-1' | 'accent-2' | 'accent-3' | 'accent-4' | 'accent-5' | 'accent-6' | 'surface-1' | 'surface-2' | 'surface-3' | 'surface-4' | 'surface-5' | 'surface-6' | 'bronto-color-bg' | 'bronto-color-surface' | 'bronto-color-surface-raised' | 'bronto-color-border' | 'bronto-color-border-strong' | 'bronto-color-text' | 'bronto-color-text-muted' | 'bronto-color-action' | 'bronto-color-on-action' | 'bronto-color-focus' | 'bronto-color-success' | 'bronto-color-warning' | 'bronto-color-danger' | 'bronto-color-info' | 'surface' | 'surface-raised' | 'surface-muted' | 'border' | 'border-strong';
|
|
17
|
+
export type ScaleKey = 'radius-xl' | 'radius-lg' | 'radius-md' | 'radius-sm' | 'radius-pill' | 'space-2xs' | 'space-xs' | 'space-sm' | 'space-md' | 'space-lg' | 'space-xl' | 'space-2xl' | 'tap-target' | 'tap-target-min' | 'safe-area-top' | 'safe-area-right' | 'safe-area-bottom' | 'safe-area-left' | 'mono' | 'sans' | 'dot-font' | 'display' | 'display-weight' | 'display-weight-strong' | 'text-2xs' | 'text-xs' | 'text-sm' | 'text-base' | 'text-lg' | 'text-xl' | 'tracking-wide' | 'tracking-wider' | 'ease-standard' | 'ease-spring' | 'ease-out' | 'duration-fast' | 'duration-base' | 'duration-slow' | 'dot-size' | 'dot-gap' | 'z-base' | 'z-raised' | 'z-sticky' | 'z-overlay' | 'z-popover' | 'z-toast' | 'accent-1' | 'accent-2' | 'accent-3' | 'accent-4' | 'accent-5' | 'accent-6' | 'surface-1' | 'surface-2' | 'surface-3' | 'surface-4' | 'surface-5' | 'surface-6' | 'bronto-color-bg' | 'bronto-color-surface' | 'bronto-color-surface-raised' | 'bronto-color-border' | 'bronto-color-border-strong' | 'bronto-color-text' | 'bronto-color-text-muted' | 'bronto-color-action' | 'bronto-color-on-action' | 'bronto-color-focus' | 'bronto-color-success' | 'bronto-color-warning' | 'bronto-color-danger' | 'bronto-color-info' | 'surface' | 'surface-raised' | 'surface-muted' | 'border' | 'border-strong';
|
|
18
18
|
export type ColorKey = 'bg' | 'bg-elevated' | 'bg-accent' | 'panel' | 'panel-strong' | 'panel-soft' | 'line' | 'line-strong' | 'text' | 'text-soft' | 'text-dim' | 'accent' | 'accent-ramp-end' | 'accent-strong' | 'accent-text' | 'on-accent' | 'accent-soft' | 'success' | 'success-soft' | 'warning' | 'warning-soft' | 'danger' | 'danger-soft' | 'info' | 'info-soft' | 'code-bg' | 'button-text' | 'field-dot' | 'field-dot-hot' | 'field-dot-accent' | 'focus-ring' | 'shadow' | 'shadow-raised';
|
|
19
19
|
|
|
20
20
|
/** Ergonomic view derived from {@link cssVars} (`--` prefix stripped). */
|
package/tokens/index.js
CHANGED
|
@@ -33,6 +33,29 @@ export const cssVars = {
|
|
|
33
33
|
'--space-lg': '1.35rem',
|
|
34
34
|
'--space-xl': '1.75rem',
|
|
35
35
|
'--space-2xl': '2.5rem',
|
|
36
|
+
// Tap targets. Both floors are clamped in px against the rem so they cannot
|
|
37
|
+
// shrink below the standard when a host re-points the root font size —
|
|
38
|
+
// Bronto's own base sets `html { font-size: 0.9375rem }`, under which a bare
|
|
39
|
+
// 2.9rem is 43.5px, half a pixel short of the target floor.
|
|
40
|
+
// `--tap-target` is the WCAG 2.5.5 (AAA) / iOS-HIG / Material 44px target
|
|
41
|
+
// every coarse-pointer control floats to. `--tap-target-min` is the WCAG
|
|
42
|
+
// 2.5.8 (AA) 24px minimum, for controls that only have to clear the smaller
|
|
43
|
+
// bar (standalone CTA links, disclosure carets).
|
|
44
|
+
'--tap-target': 'max(44px, 2.9rem)',
|
|
45
|
+
'--tap-target-min': 'max(24px, 1.6rem)',
|
|
46
|
+
// Display cutouts and system gesture areas. Every viewport-anchored surface
|
|
47
|
+
// Bronto ships — the app rail and topbar, a sticky site header, the skip
|
|
48
|
+
// link, the toast stacks, the drawer and the lightbox — reads these instead
|
|
49
|
+
// of calling env() at the point of use. The indirection is the point: env()
|
|
50
|
+
// cannot be emulated by a desktop browser runner, so routing every inset
|
|
51
|
+
// through an overrideable custom property is what makes full-bleed framing
|
|
52
|
+
// testable, and what lets a host running inside its own chrome (an embedded
|
|
53
|
+
// webview, a kiosk frame) declare the real insets. They resolve to 0px off
|
|
54
|
+
// a notched device, so every consuming rule is a no-op on desktop.
|
|
55
|
+
'--safe-area-top': 'env(safe-area-inset-top, 0px)',
|
|
56
|
+
'--safe-area-right': 'env(safe-area-inset-right, 0px)',
|
|
57
|
+
'--safe-area-bottom': 'env(safe-area-inset-bottom, 0px)',
|
|
58
|
+
'--safe-area-left': 'env(safe-area-inset-left, 0px)',
|
|
36
59
|
'--mono': "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
|
37
60
|
'--sans':
|
|
38
61
|
"'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
package/tokens/index.json
CHANGED
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
"--space-lg": "1.35rem",
|
|
15
15
|
"--space-xl": "1.75rem",
|
|
16
16
|
"--space-2xl": "2.5rem",
|
|
17
|
+
"--tap-target": "max(44px, 2.9rem)",
|
|
18
|
+
"--tap-target-min": "max(24px, 1.6rem)",
|
|
19
|
+
"--safe-area-top": "env(safe-area-inset-top, 0px)",
|
|
20
|
+
"--safe-area-right": "env(safe-area-inset-right, 0px)",
|
|
21
|
+
"--safe-area-bottom": "env(safe-area-inset-bottom, 0px)",
|
|
22
|
+
"--safe-area-left": "env(safe-area-inset-left, 0px)",
|
|
17
23
|
"--mono": "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
|
18
24
|
"--sans": "'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
19
25
|
"--dot-font": "'Doto', var(--mono)",
|
|
@@ -159,6 +165,12 @@
|
|
|
159
165
|
"space-lg": "1.35rem",
|
|
160
166
|
"space-xl": "1.75rem",
|
|
161
167
|
"space-2xl": "2.5rem",
|
|
168
|
+
"tap-target": "max(44px, 2.9rem)",
|
|
169
|
+
"tap-target-min": "max(24px, 1.6rem)",
|
|
170
|
+
"safe-area-top": "env(safe-area-inset-top, 0px)",
|
|
171
|
+
"safe-area-right": "env(safe-area-inset-right, 0px)",
|
|
172
|
+
"safe-area-bottom": "env(safe-area-inset-bottom, 0px)",
|
|
173
|
+
"safe-area-left": "env(safe-area-inset-left, 0px)",
|
|
162
174
|
"mono": "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
|
163
175
|
"sans": "'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
164
176
|
"dot-font": "'Doto', var(--mono)",
|
package/tokens/resolved.json
CHANGED
|
@@ -141,6 +141,12 @@
|
|
|
141
141
|
"--space-lg": "1.35rem",
|
|
142
142
|
"--space-xl": "1.75rem",
|
|
143
143
|
"--space-2xl": "2.5rem",
|
|
144
|
+
"--tap-target": "max(44px, 2.9rem)",
|
|
145
|
+
"--tap-target-min": "max(24px, 1.6rem)",
|
|
146
|
+
"--safe-area-top": "env(safe-area-inset-top, 0px)",
|
|
147
|
+
"--safe-area-right": "env(safe-area-inset-right, 0px)",
|
|
148
|
+
"--safe-area-bottom": "env(safe-area-inset-bottom, 0px)",
|
|
149
|
+
"--safe-area-left": "env(safe-area-inset-left, 0px)",
|
|
144
150
|
"--mono": "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
|
145
151
|
"--sans": "'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
146
152
|
"--dot-font": "'Doto', 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
package/tokens/skins.js
CHANGED
|
@@ -5,8 +5,26 @@
|
|
|
5
5
|
* A skin is NOT a second brand colour — it *re-points the one accent* (and the
|
|
6
6
|
* Tier-3 dot-matrix display knobs) to a different single hue, so the
|
|
7
7
|
* one-accent-per-scope discipline holds while the palette gains creative range
|
|
8
|
-
* *across* skins. The
|
|
9
|
-
*
|
|
8
|
+
* *across* skins. The status palette and every component stay exactly as they
|
|
9
|
+
* are.
|
|
10
|
+
*
|
|
11
|
+
* Since 0.8.0 a skin ALSO re-points the neutral canvas (ADR-0001 step 4,
|
|
12
|
+
* amended). Accent-only colorways were the original rule, and a downstream
|
|
13
|
+
* consumer proved it surprising in the worst way: a workspace offering these
|
|
14
|
+
* three as pickable looks found that "Amber CRT" left the surface grey, so it
|
|
15
|
+
* hand-wrote a full amber canvas in raw hex — dark theme only, outside OKLCH,
|
|
16
|
+
* outside the contrast gate, and with e-ink left un-tinted because nobody
|
|
17
|
+
* noticed it was missing. Shipping the canvas here makes it governed instead.
|
|
18
|
+
*
|
|
19
|
+
* THE NEUTRALS ARE DERIVED, NOT PICKED. Each one keeps the core token's OKLCH
|
|
20
|
+
* *lightness* exactly, adopts the skin accent's *hue*, and takes a small
|
|
21
|
+
* role-scaled chroma — surfaces least, lines most, text near-neutral so it
|
|
22
|
+
* never competes with the accent. Because WCAG contrast is a function of
|
|
23
|
+
* relative luminance, which OKLCH L tracks closely, holding L fixed means every
|
|
24
|
+
* gated pairing keeps essentially its core ratio: the colorway gains a canvas,
|
|
25
|
+
* not a contrast problem. `check-contrast.mjs` audits the FULL pairing table
|
|
26
|
+
* for any skin that moves the canvas — not just the accent subset — so that
|
|
27
|
+
* claim is proven on every run rather than asserted here.
|
|
10
28
|
*
|
|
11
29
|
* Accents are authored in **OKLCH** (ADR-0001 step 5 — "OKLCH for new work
|
|
12
30
|
* first"): perceptually-uniform lightness makes the light/dark pair easy to
|
|
@@ -41,22 +59,68 @@ export const skins = {
|
|
|
41
59
|
// bright with a warm bloom in dark theme (the classic CRT glow). The glow
|
|
42
60
|
// and a deeper --pulse breath (`--dotmatrix-pulse-min`) are the Tier-3
|
|
43
61
|
// "display expression" knobs the colorway is allowed to re-point.
|
|
44
|
-
light: {
|
|
62
|
+
light: {
|
|
63
|
+
'--accent': 'oklch(52% 0.11 67deg)',
|
|
64
|
+
'--dotmatrix-pulse-min': '0.35',
|
|
65
|
+
'--bg': 'oklch(96.66% 0.02 67deg)',
|
|
66
|
+
'--bg-elevated': 'oklch(98.781% 0.022 67deg)',
|
|
67
|
+
'--panel': 'oklch(100% 0.024 67deg)',
|
|
68
|
+
'--panel-strong': 'oklch(100% 0.026 67deg)',
|
|
69
|
+
'--panel-soft': 'oklch(94.253% 0.026 67deg)',
|
|
70
|
+
'--line': 'oklch(88.11% 0.035 67deg)',
|
|
71
|
+
'--line-strong': 'oklch(72.983% 0.04 67deg)',
|
|
72
|
+
'--text': 'oklch(14.479% 0.03 67deg)',
|
|
73
|
+
'--text-soft': 'oklch(32.825% 0.03 67deg)',
|
|
74
|
+
'--text-dim': 'oklch(51.571% 0.028 67deg)',
|
|
75
|
+
},
|
|
45
76
|
dark: {
|
|
46
77
|
'--accent': 'oklch(82% 0.15 82deg)',
|
|
47
78
|
'--dotmatrix-glow': '0.4em',
|
|
48
79
|
'--dotmatrix-pulse-min': '0.3',
|
|
80
|
+
'--bg': 'oklch(18.22% 0.02 82deg)',
|
|
81
|
+
'--bg-elevated': 'oklch(20.904% 0.022 82deg)',
|
|
82
|
+
'--panel': 'oklch(22.645% 0.024 82deg)',
|
|
83
|
+
'--panel-strong': 'oklch(25.196% 0.026 82deg)',
|
|
84
|
+
'--panel-soft': 'oklch(26.032% 0.026 82deg)',
|
|
85
|
+
'--line': 'oklch(34.07% 0.035 82deg)',
|
|
86
|
+
'--line-strong': 'oklch(44.953% 0.04 82deg)',
|
|
87
|
+
'--text': 'oklch(92.494% 0.03 82deg)',
|
|
88
|
+
'--text-soft': 'oklch(83.279% 0.03 82deg)',
|
|
89
|
+
'--text-dim': 'oklch(70.576% 0.028 82deg)',
|
|
49
90
|
},
|
|
50
91
|
},
|
|
51
92
|
'phosphor-green': {
|
|
52
93
|
label: 'Phosphor Green',
|
|
53
94
|
// P1-phosphor green. Same light=dark-ink / dark=bright-glow split, with the
|
|
54
95
|
// same deeper phosphor breath as Amber CRT.
|
|
55
|
-
light: {
|
|
96
|
+
light: {
|
|
97
|
+
'--accent': 'oklch(52% 0.13 150deg)',
|
|
98
|
+
'--dotmatrix-pulse-min': '0.35',
|
|
99
|
+
'--bg': 'oklch(96.66% 0.02 150deg)',
|
|
100
|
+
'--bg-elevated': 'oklch(98.781% 0.022 150deg)',
|
|
101
|
+
'--panel': 'oklch(100% 0.024 150deg)',
|
|
102
|
+
'--panel-strong': 'oklch(100% 0.026 150deg)',
|
|
103
|
+
'--panel-soft': 'oklch(94.253% 0.026 150deg)',
|
|
104
|
+
'--line': 'oklch(88.11% 0.035 150deg)',
|
|
105
|
+
'--line-strong': 'oklch(72.983% 0.04 150deg)',
|
|
106
|
+
'--text': 'oklch(14.479% 0.03 150deg)',
|
|
107
|
+
'--text-soft': 'oklch(32.825% 0.03 150deg)',
|
|
108
|
+
'--text-dim': 'oklch(51.571% 0.028 150deg)',
|
|
109
|
+
},
|
|
56
110
|
dark: {
|
|
57
111
|
'--accent': 'oklch(84% 0.19 150deg)',
|
|
58
112
|
'--dotmatrix-glow': '0.4em',
|
|
59
113
|
'--dotmatrix-pulse-min': '0.3',
|
|
114
|
+
'--bg': 'oklch(18.22% 0.02 150deg)',
|
|
115
|
+
'--bg-elevated': 'oklch(20.904% 0.022 150deg)',
|
|
116
|
+
'--panel': 'oklch(22.645% 0.024 150deg)',
|
|
117
|
+
'--panel-strong': 'oklch(25.196% 0.026 150deg)',
|
|
118
|
+
'--panel-soft': 'oklch(26.032% 0.026 150deg)',
|
|
119
|
+
'--line': 'oklch(34.07% 0.035 150deg)',
|
|
120
|
+
'--line-strong': 'oklch(44.953% 0.04 150deg)',
|
|
121
|
+
'--text': 'oklch(92.494% 0.03 150deg)',
|
|
122
|
+
'--text-soft': 'oklch(83.279% 0.03 150deg)',
|
|
123
|
+
'--text-dim': 'oklch(70.576% 0.028 150deg)',
|
|
60
124
|
},
|
|
61
125
|
},
|
|
62
126
|
'e-ink': {
|
|
@@ -64,12 +128,58 @@ export const skins = {
|
|
|
64
128
|
// The opposite move: drop the hue almost entirely → a near-monochrome
|
|
65
129
|
// ink/paper accent, no glow. The most restrained look in the set — and the
|
|
66
130
|
// --reveal scan snaps on instantly (`--dotmatrix-reveal-step: 0ms`), since
|
|
67
|
-
// e-ink panels don't sweep, they flip.
|
|
68
|
-
|
|
69
|
-
|
|
131
|
+
// e-ink panels don't sweep, they flip. Its canvas takes a QUARTER of the
|
|
132
|
+
// chroma the other two do, for the same reason: near-monochrome is the
|
|
133
|
+
// whole point, so the tint should be felt rather than seen.
|
|
134
|
+
light: {
|
|
135
|
+
'--accent': 'oklch(34% 0.012 250deg)',
|
|
136
|
+
'--dotmatrix-reveal-step': '0ms',
|
|
137
|
+
'--bg': 'oklch(96.66% 0.005 250deg)',
|
|
138
|
+
'--bg-elevated': 'oklch(98.781% 0.006 250deg)',
|
|
139
|
+
'--panel': 'oklch(100% 0.006 250deg)',
|
|
140
|
+
'--panel-strong': 'oklch(100% 0.007 250deg)',
|
|
141
|
+
'--panel-soft': 'oklch(94.253% 0.007 250deg)',
|
|
142
|
+
'--line': 'oklch(88.11% 0.009 250deg)',
|
|
143
|
+
'--line-strong': 'oklch(72.983% 0.01 250deg)',
|
|
144
|
+
'--text': 'oklch(14.479% 0.008 250deg)',
|
|
145
|
+
'--text-soft': 'oklch(32.825% 0.008 250deg)',
|
|
146
|
+
'--text-dim': 'oklch(51.571% 0.007 250deg)',
|
|
147
|
+
},
|
|
148
|
+
dark: {
|
|
149
|
+
'--accent': 'oklch(84% 0.008 250deg)',
|
|
150
|
+
'--dotmatrix-reveal-step': '0ms',
|
|
151
|
+
'--bg': 'oklch(18.22% 0.005 250deg)',
|
|
152
|
+
'--bg-elevated': 'oklch(20.904% 0.006 250deg)',
|
|
153
|
+
'--panel': 'oklch(22.645% 0.006 250deg)',
|
|
154
|
+
'--panel-strong': 'oklch(25.196% 0.007 250deg)',
|
|
155
|
+
'--panel-soft': 'oklch(26.032% 0.007 250deg)',
|
|
156
|
+
'--line': 'oklch(34.07% 0.009 250deg)',
|
|
157
|
+
'--line-strong': 'oklch(44.953% 0.01 250deg)',
|
|
158
|
+
'--text': 'oklch(92.494% 0.008 250deg)',
|
|
159
|
+
'--text-soft': 'oklch(83.279% 0.008 250deg)',
|
|
160
|
+
'--text-dim': 'oklch(70.576% 0.007 250deg)',
|
|
161
|
+
},
|
|
70
162
|
},
|
|
71
163
|
};
|
|
72
164
|
|
|
165
|
+
/** The canvas tokens a colorway may re-point (ADR-0001 step 4, amended). Status
|
|
166
|
+
* colours are deliberately NOT here: a warning must look like a warning in
|
|
167
|
+
* every skin. The gates read this — check-skins allows these keys, and
|
|
168
|
+
* gen-contrast widens a skin's audit to the full pairing table when any of
|
|
169
|
+
* them is set. */
|
|
170
|
+
export const SKIN_CANVAS_TOKENS = Object.freeze([
|
|
171
|
+
'--bg',
|
|
172
|
+
'--bg-elevated',
|
|
173
|
+
'--panel',
|
|
174
|
+
'--panel-strong',
|
|
175
|
+
'--panel-soft',
|
|
176
|
+
'--line',
|
|
177
|
+
'--line-strong',
|
|
178
|
+
'--text',
|
|
179
|
+
'--text-soft',
|
|
180
|
+
'--text-dim',
|
|
181
|
+
]);
|
|
182
|
+
|
|
73
183
|
/** Skin names, frozen + sorted. */
|
|
74
184
|
export const SKIN_NAMES = Object.freeze(Object.keys(skins).sort());
|
|
75
185
|
|
package/tokens/tokens.dtcg.json
CHANGED
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
"--tracking-wide",
|
|
11
11
|
"--tracking-wider",
|
|
12
12
|
"--shadow",
|
|
13
|
-
"--shadow-raised"
|
|
13
|
+
"--shadow-raised",
|
|
14
|
+
"--tap-target",
|
|
15
|
+
"--tap-target-min",
|
|
16
|
+
"--safe-area-top",
|
|
17
|
+
"--safe-area-right",
|
|
18
|
+
"--safe-area-bottom",
|
|
19
|
+
"--safe-area-left"
|
|
14
20
|
]
|
|
15
21
|
}
|
|
16
22
|
},
|