@motion-proto/live-tokens 0.18.3 → 0.19.1
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 +6 -4
- package/package.json +2 -4
- package/src/editor/component-editor/SegmentedControlEditor.svelte +2 -2
- package/src/editor/component-editor/TabBarEditor.svelte +1 -1
- package/src/editor/component-editor/ToggleEditor.svelte +6 -7
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +1 -1
- package/src/editor/core/themes/migrations/2026-05-29-segmentedcontrol-small-divider-rename.ts +36 -0
- package/src/editor/core/themes/migrations/2026-05-29-tabbar-indicator-thickness-to-per-state-width.ts +43 -0
- package/src/editor/core/themes/migrations/2026-05-29-toggle-derive-track-from-thumb.ts +41 -0
- package/src/editor/core/themes/migrations/index.ts +6 -0
- package/src/live-tokens/data/tokens.generated.css +19 -0
- package/src/system/components/SegmentedControl.svelte +4 -4
- package/src/system/components/TabBar.svelte +12 -4
- package/src/system/components/Toggle.svelte +11 -8
package/README.md
CHANGED
|
@@ -26,12 +26,14 @@ npm install @motion-proto/live-tokens
|
|
|
26
26
|
```ts
|
|
27
27
|
// vite.config.ts
|
|
28
28
|
import { defineConfig } from 'vite';
|
|
29
|
-
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
29
|
+
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
30
30
|
import { themeFileApi } from '@motion-proto/live-tokens/vite-plugin';
|
|
31
31
|
|
|
32
32
|
export default defineConfig({
|
|
33
33
|
plugins: [
|
|
34
|
-
|
|
34
|
+
// vitePreprocess compiles the shipped components' `<style lang="scss">`
|
|
35
|
+
// blocks — install `sass` alongside it.
|
|
36
|
+
svelte({ preprocess: vitePreprocess() }),
|
|
35
37
|
themeFileApi({
|
|
36
38
|
tokensCssPath: 'src/system/styles/tokens.css',
|
|
37
39
|
}),
|
|
@@ -205,10 +207,10 @@ mount(App, { target: document.getElementById('app')! });
|
|
|
205
207
|
```ts
|
|
206
208
|
// vite.config.ts
|
|
207
209
|
import { defineConfig } from 'vite';
|
|
208
|
-
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
210
|
+
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
|
209
211
|
|
|
210
212
|
export default defineConfig({
|
|
211
|
-
plugins: [svelte()],
|
|
213
|
+
plugins: [svelte({ preprocess: vitePreprocess() })],
|
|
212
214
|
});
|
|
213
215
|
```
|
|
214
216
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion-proto/live-tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
|
|
6
6
|
"keywords": [
|
|
@@ -92,14 +92,13 @@
|
|
|
92
92
|
"prepublishOnly": "npm run check:no-style-imports && npm run check:editor-font-isolation && npm run build:lib && npm run check:smoke-install"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
+
"@sveltejs/vite-plugin-svelte": "^7.0",
|
|
95
96
|
"sass": "^1.0",
|
|
96
97
|
"svelte": "^5",
|
|
97
|
-
"svelte-preprocess": "^6.0",
|
|
98
98
|
"vite": "^8"
|
|
99
99
|
},
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
102
|
-
"@tsconfig/svelte": "^5.0.8",
|
|
103
102
|
"@types/node": "^25.9.1",
|
|
104
103
|
"happy-dom": "^20.9.0",
|
|
105
104
|
"highlight.js": "^11.11.1",
|
|
@@ -108,7 +107,6 @@
|
|
|
108
107
|
"sass": "^1.98.0",
|
|
109
108
|
"svelte": "^5.55.5",
|
|
110
109
|
"svelte-check": "^4.4.8",
|
|
111
|
-
"svelte-preprocess": "^6.0.3",
|
|
112
110
|
"tsup": "^8.5.1",
|
|
113
111
|
"typescript": "~6.0.3",
|
|
114
112
|
"vite": "^8.0.14",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
// since family/weight/color don't differ.
|
|
53
53
|
const smallStates: Record<string, Token[]> = {
|
|
54
54
|
'control bar': [
|
|
55
|
-
{ label: 'divider inset', groupKey: 'small-divider-inset', variable: '--segmentedcontrol-divider-
|
|
56
|
-
{ label: 'divider width', groupKey: 'small-thickness', variable: '--segmentedcontrol-divider-
|
|
55
|
+
{ label: 'divider inset', groupKey: 'small-divider-inset', variable: '--segmentedcontrol-small-divider-inset' },
|
|
56
|
+
{ label: 'divider width', groupKey: 'small-divider-thickness', variable: '--segmentedcontrol-small-divider-thickness' },
|
|
57
57
|
{ label: 'corner radius', groupKey: 'small-radius', variable: '--segmentedcontrol-bar-small-radius' },
|
|
58
58
|
{ label: 'padding', variable: '--segmentedcontrol-bar-small-padding', groupKey: 'bar-small-padding' },
|
|
59
59
|
],
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
{ label: 'bottom radius', canBeLinked: true, groupKey: 'tab-bottom-radius', variable: `--tabbar-${s}-tab-bottom-radius` },
|
|
17
17
|
{ label: 'border color', canBeLinked: true, groupKey: 'tab-border-color', variable: `--tabbar-${s}-tab-border-color` },
|
|
18
18
|
{ label: 'border width', canBeLinked: true, groupKey: 'tab-border-width', variable: `--tabbar-${s}-tab-border-width` },
|
|
19
|
+
{ label: 'indicator width', canBeLinked: true, groupKey: 'indicator-border-width', variable: `--tabbar-${s}-indicator-border-width` },
|
|
19
20
|
];
|
|
20
21
|
}
|
|
21
22
|
function tabStateTypeGroups(s: TabState): TypeGroupConfig[] {
|
|
@@ -35,7 +36,6 @@
|
|
|
35
36
|
bar: [
|
|
36
37
|
{ label: 'divider color', groupKey: 'bar-divider', variable: '--tabbar-bar-divider' },
|
|
37
38
|
{ label: 'divider thickness', groupKey: 'bar-divider-thickness', variable: '--tabbar-bar-divider-thickness' },
|
|
38
|
-
{ label: 'indicator thickness', groupKey: 'bar-indicator-thickness', variable: '--tabbar-bar-indicator-thickness' },
|
|
39
39
|
{ label: 'space above', groupKey: 'bar-top-margin', variable: '--tabbar-bar-top-margin' },
|
|
40
40
|
// Consumed via `padding-bottom: var(--tabbar-bar-bottom-padding)` — a
|
|
41
41
|
// one-axis read. Splitting would produce top/left/right values that have
|
|
@@ -8,15 +8,14 @@
|
|
|
8
8
|
// on top of that baseline.
|
|
9
9
|
const states: Record<string, Token[]> = {
|
|
10
10
|
default: [
|
|
11
|
-
{ label: '
|
|
12
|
-
{ label: 'track
|
|
13
|
-
{ label: 'track border width',variable: '--toggle-track-border-width' },
|
|
11
|
+
{ label: 'thumb size', variable: '--toggle-thumb-size' },
|
|
12
|
+
{ label: 'track padding', variable: '--toggle-track-padding' },
|
|
14
13
|
{ label: 'track radius', variable: '--toggle-track-radius' },
|
|
15
|
-
{ label: 'track width',
|
|
16
|
-
{ label: 'track
|
|
17
|
-
{ label: '
|
|
14
|
+
{ label: 'track border width',variable: '--toggle-track-border-width' },
|
|
15
|
+
{ label: 'track border', variable: '--toggle-track-border' },
|
|
16
|
+
{ label: 'track surface', variable: '--toggle-track-surface' },
|
|
18
17
|
{ label: 'thumb border', variable: '--toggle-thumb-border' },
|
|
19
|
-
{ label: 'thumb
|
|
18
|
+
{ label: 'thumb surface', variable: '--toggle-thumb-surface' },
|
|
20
19
|
{ label: 'label text', variable: '--toggle-label-text' },
|
|
21
20
|
{ label: 'label font family', variable: '--toggle-label-font-family' },
|
|
22
21
|
{ label: 'label font size', variable: '--toggle-label-font-size' },
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
const KIND_PATTERNS: Array<{ kind: Kind; matches: (v: string) => boolean }> = [
|
|
90
90
|
{ kind: 'font-family', matches: (v) => v.endsWith('-font-family') },
|
|
91
91
|
{ kind: 'font-weight', matches: (v) => v.endsWith('-font-weight') },
|
|
92
|
-
{ kind: 'font-size', matches: (v) => v.endsWith('-font-size') || v.endsWith('-icon-size') },
|
|
92
|
+
{ kind: 'font-size', matches: (v) => v.endsWith('-font-size') || v.endsWith('-icon-size') || v.endsWith('-thumb-size') },
|
|
93
93
|
{ kind: 'line-height', matches: (v) => v.endsWith('-line-height') },
|
|
94
94
|
{ kind: 'letter-spacing', matches: (v) => v.endsWith('-letter-spacing') },
|
|
95
95
|
{ kind: 'text-color', matches: (v) => v.endsWith('-text') || v.startsWith('--text-') },
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-29, segmentedcontrol):
|
|
5
|
+
*
|
|
6
|
+
* Moves `small` ahead of `divider` in the small-size divider tokens so the
|
|
7
|
+
* picker's suffix matcher recognises them. With `-small-` as an infix, the
|
|
8
|
+
* variable's tail is `-small-thickness` / `-small-inset` — neither of which
|
|
9
|
+
* is in `KIND_PATTERNS`, so the editor falls back to rendering them as
|
|
10
|
+
* colour pickers. Reordering to `--segmentedcontrol-small-divider-*` puts
|
|
11
|
+
* `-divider-thickness` / `-divider-inset` at the suffix, where the picker
|
|
12
|
+
* classifies them as a stroke width and a divider inset respectively.
|
|
13
|
+
*
|
|
14
|
+
* --segmentedcontrol-divider-small-thickness → --segmentedcontrol-small-divider-thickness
|
|
15
|
+
* --segmentedcontrol-divider-small-inset → --segmentedcontrol-small-divider-inset
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const RENAMES: Record<string, string> = {
|
|
19
|
+
'--segmentedcontrol-divider-small-thickness': '--segmentedcontrol-small-divider-thickness',
|
|
20
|
+
'--segmentedcontrol-divider-small-inset': '--segmentedcontrol-small-divider-inset',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const componentMigration_2026_05_29_segmentedcontrolSmallDividerRename: Migration = {
|
|
24
|
+
id: '2026-05-29-segmentedcontrol-small-divider-rename',
|
|
25
|
+
fromVersion: 18,
|
|
26
|
+
toVersion: 19,
|
|
27
|
+
appliesTo: 'component-config',
|
|
28
|
+
apply(rawVars, meta) {
|
|
29
|
+
if (meta.component !== 'segmentedcontrol') return { ...rawVars };
|
|
30
|
+
const out: Record<string, string> = {};
|
|
31
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
32
|
+
out[RENAMES[key] ?? key] = value;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-29, tabbar):
|
|
5
|
+
*
|
|
6
|
+
* Moves the indicator stroke width from a bar-level token to a per-state
|
|
7
|
+
* token, mirroring how indicator color already rebinds per state. Also
|
|
8
|
+
* renames the suffix from `-thickness` to `-border-width` so the editor's
|
|
9
|
+
* suffix-based picker classifies it as a width input instead of a color.
|
|
10
|
+
*
|
|
11
|
+
* --tabbar-bar-indicator-thickness → --tabbar-{state}-indicator-border-width
|
|
12
|
+
* for state in default/hover/active/disabled.
|
|
13
|
+
*
|
|
14
|
+
* The bar-level value seeds every state, preserving the visual default
|
|
15
|
+
* (all four states had the same effective indicator width since only
|
|
16
|
+
* color rebinds in the old model). Unset → falls back to `--border-width-2`
|
|
17
|
+
* to match the new component default.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const TABBAR_STATES = ['default', 'hover', 'active', 'disabled'] as const;
|
|
21
|
+
const OLD_KEY = '--tabbar-bar-indicator-thickness';
|
|
22
|
+
const FALLBACK = '--border-width-2';
|
|
23
|
+
|
|
24
|
+
export const componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth: Migration = {
|
|
25
|
+
id: '2026-05-29-tabbar-indicator-thickness-to-per-state-width',
|
|
26
|
+
fromVersion: 17,
|
|
27
|
+
toVersion: 18,
|
|
28
|
+
appliesTo: 'component-config',
|
|
29
|
+
apply(rawVars, meta) {
|
|
30
|
+
if (meta.component !== 'tabbar') return { ...rawVars };
|
|
31
|
+
const seed = rawVars[OLD_KEY] ?? FALLBACK;
|
|
32
|
+
const out: Record<string, string> = {};
|
|
33
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
34
|
+
if (key === OLD_KEY) continue;
|
|
35
|
+
out[key] = value;
|
|
36
|
+
}
|
|
37
|
+
for (const state of TABBAR_STATES) {
|
|
38
|
+
const newKey = `--tabbar-${state}-indicator-border-width`;
|
|
39
|
+
if (!(newKey in out)) out[newKey] = seed;
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Migration } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Component-config migration (2026-05-29, toggle):
|
|
5
|
+
*
|
|
6
|
+
* Drops the explicit track dimensions and replaces them with a single
|
|
7
|
+
* `track-padding` knob. The runtime CSS now derives:
|
|
8
|
+
*
|
|
9
|
+
* track-width = thumb-size * 2 + track-padding * 2
|
|
10
|
+
* track-height = thumb-size + track-padding * 2
|
|
11
|
+
*
|
|
12
|
+
* so width and thickness are no longer authorable — they're a function of
|
|
13
|
+
* thumb-size (picked from the font-size scale) and the new padding token.
|
|
14
|
+
*
|
|
15
|
+
* --toggle-track-width → dropped (derived)
|
|
16
|
+
* --toggle-track-thickness → dropped (derived)
|
|
17
|
+
* --toggle-track-padding → seeded with --space-2 if absent
|
|
18
|
+
*
|
|
19
|
+
* `--toggle-thumb-size` is left untouched. Pre-existing `--space-*` values
|
|
20
|
+
* still render as valid lengths; the editor's font-size picker just won't
|
|
21
|
+
* highlight them as a known entry until the user re-picks.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const componentMigration_2026_05_29_toggleDeriveTrackFromThumb: Migration = {
|
|
25
|
+
id: '2026-05-29-toggle-derive-track-from-thumb',
|
|
26
|
+
fromVersion: 19,
|
|
27
|
+
toVersion: 20,
|
|
28
|
+
appliesTo: 'component-config',
|
|
29
|
+
apply(rawVars, meta) {
|
|
30
|
+
if (meta.component !== 'toggle') return { ...rawVars };
|
|
31
|
+
const out: Record<string, string> = {};
|
|
32
|
+
for (const [key, value] of Object.entries(rawVars)) {
|
|
33
|
+
if (key === '--toggle-track-width' || key === '--toggle-track-thickness') continue;
|
|
34
|
+
out[key] = value;
|
|
35
|
+
}
|
|
36
|
+
if (!('--toggle-track-padding' in out)) {
|
|
37
|
+
out['--toggle-track-padding'] = '--space-2';
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
@@ -54,6 +54,9 @@ import {
|
|
|
54
54
|
themeMigration_2026_05_26_dropOverlayExtraStops,
|
|
55
55
|
componentMigration_2026_05_26_dropOverlayExtraStops,
|
|
56
56
|
} from './2026-05-26-drop-overlay-extra-stops';
|
|
57
|
+
import { componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth } from './2026-05-29-tabbar-indicator-thickness-to-per-state-width';
|
|
58
|
+
import { componentMigration_2026_05_29_segmentedcontrolSmallDividerRename } from './2026-05-29-segmentedcontrol-small-divider-rename';
|
|
59
|
+
import { componentMigration_2026_05_29_toggleDeriveTrackFromThumb } from './2026-05-29-toggle-derive-track-from-thumb';
|
|
57
60
|
|
|
58
61
|
/**
|
|
59
62
|
* Registered migrations. Order in this array does not matter — the runner
|
|
@@ -80,6 +83,9 @@ export const MIGRATIONS: Migration[] = [
|
|
|
80
83
|
componentMigration_2026_05_25_cornerbadgeFlattenVariants,
|
|
81
84
|
themeMigration_2026_05_26_dropOverlayExtraStops,
|
|
82
85
|
componentMigration_2026_05_26_dropOverlayExtraStops,
|
|
86
|
+
componentMigration_2026_05_29_tabbarIndicatorThicknessToPerStateWidth,
|
|
87
|
+
componentMigration_2026_05_29_segmentedcontrolSmallDividerRename,
|
|
88
|
+
componentMigration_2026_05_29_toggleDeriveTrackFromThumb,
|
|
83
89
|
];
|
|
84
90
|
|
|
85
91
|
function countFor(kind: 'theme' | 'component-config'): number {
|
|
@@ -383,6 +383,25 @@
|
|
|
383
383
|
--button-warning-radius: var(--radius-xl);
|
|
384
384
|
--button-small-text-font-size: var(--font-size-sm);
|
|
385
385
|
|
|
386
|
+
/* callout (my-callout) */
|
|
387
|
+
--callout-info-border: var(--border-info-medium);
|
|
388
|
+
--callout-info-label-font-family: var(--font-sans);
|
|
389
|
+
--callout-info-label-font-size: var(--font-size-lg);
|
|
390
|
+
--callout-info-text-font-family: var(--font-sans);
|
|
391
|
+
--callout-info-text-font-size: var(--font-size-lg);
|
|
392
|
+
--callout-success-label-font-family: var(--font-sans);
|
|
393
|
+
--callout-success-label-font-size: var(--font-size-lg);
|
|
394
|
+
--callout-success-text-font-family: var(--font-sans);
|
|
395
|
+
--callout-success-text-font-size: var(--font-size-lg);
|
|
396
|
+
--callout-warning-label-font-family: var(--font-sans);
|
|
397
|
+
--callout-warning-label-font-size: var(--font-size-lg);
|
|
398
|
+
--callout-warning-text-font-family: var(--font-sans);
|
|
399
|
+
--callout-warning-text-font-size: var(--font-size-lg);
|
|
400
|
+
--callout-danger-label-font-family: var(--font-sans);
|
|
401
|
+
--callout-danger-label-font-size: var(--font-size-lg);
|
|
402
|
+
--callout-danger-text-font-family: var(--font-sans);
|
|
403
|
+
--callout-danger-text-font-size: var(--font-size-lg);
|
|
404
|
+
|
|
386
405
|
/* card (my-card) */
|
|
387
406
|
--card-default-surface: color-mix(in srgb, var(--surface-neutral-lower) 70%, transparent);
|
|
388
407
|
--card-default-header-surface: color-mix(in srgb, var(--surface-neutral-lowest) 80%, transparent);
|
|
@@ -127,8 +127,8 @@
|
|
|
127
127
|
values so existing state-specific cascades flow through unchanged. */
|
|
128
128
|
--segmentedcontrol-bar-small-padding: var(--space-2);
|
|
129
129
|
--segmentedcontrol-bar-small-radius: var(--radius-md);
|
|
130
|
-
--segmentedcontrol-divider-
|
|
131
|
-
--segmentedcontrol-divider-
|
|
130
|
+
--segmentedcontrol-small-divider-inset: var(--space-4);
|
|
131
|
+
--segmentedcontrol-small-divider-thickness: var(--border-width-1);
|
|
132
132
|
--segmentedcontrol-option-small-padding: var(--space-6);
|
|
133
133
|
--segmentedcontrol-option-small-gap: var(--space-6);
|
|
134
134
|
--segmentedcontrol-option-small-icon-size: var(--icon-size-sm);
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
--segmentedcontrol-bar-padding-left: var(--segmentedcontrol-bar-small-padding-left);
|
|
164
164
|
--segmentedcontrol-bar-radius: var(--segmentedcontrol-bar-small-radius);
|
|
165
165
|
|
|
166
|
-
--segmentedcontrol-divider-inset: var(--segmentedcontrol-divider-
|
|
167
|
-
--segmentedcontrol-divider-thickness: var(--segmentedcontrol-divider-
|
|
166
|
+
--segmentedcontrol-divider-inset: var(--segmentedcontrol-small-divider-inset);
|
|
167
|
+
--segmentedcontrol-divider-thickness: var(--segmentedcontrol-small-divider-thickness);
|
|
168
168
|
|
|
169
169
|
--segmentedcontrol-option-padding: var(--segmentedcontrol-option-small-padding);
|
|
170
170
|
--segmentedcontrol-option-padding-top: var(--segmentedcontrol-option-small-padding-top);
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
/* Bar */
|
|
65
65
|
--tabbar-bar-divider: var(--border-neutral-subtle);
|
|
66
66
|
--tabbar-bar-divider-thickness: var(--border-width-1);
|
|
67
|
-
--tabbar-bar-indicator-thickness: var(--border-width-2);
|
|
68
67
|
--tabbar-bar-top-margin: var(--space-0);
|
|
69
68
|
--tabbar-bar-bottom-padding: var(--space-0);
|
|
70
69
|
--tabbar-bar-bottom-margin: var(--space-0);
|
|
@@ -84,6 +83,7 @@
|
|
|
84
83
|
--tabbar-default-tab-border-width: var(--border-width-0);
|
|
85
84
|
--tabbar-default-tab-top-radius: var(--radius-none);
|
|
86
85
|
--tabbar-default-tab-bottom-radius: var(--radius-none);
|
|
86
|
+
--tabbar-default-indicator-border-width: var(--border-width-2);
|
|
87
87
|
|
|
88
88
|
/* Hover tab */
|
|
89
89
|
--tabbar-hover-text: var(--text-secondary);
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
--tabbar-hover-tab-border-width: var(--border-width-0);
|
|
100
100
|
--tabbar-hover-tab-top-radius: var(--radius-none);
|
|
101
101
|
--tabbar-hover-tab-bottom-radius: var(--radius-none);
|
|
102
|
+
--tabbar-hover-indicator-border-width: var(--border-width-2);
|
|
102
103
|
|
|
103
104
|
/* Active tab */
|
|
104
105
|
--tabbar-active-text: var(--text-primary);
|
|
@@ -114,6 +115,7 @@
|
|
|
114
115
|
--tabbar-active-tab-border-width: var(--border-width-0);
|
|
115
116
|
--tabbar-active-tab-top-radius: var(--radius-none);
|
|
116
117
|
--tabbar-active-tab-bottom-radius: var(--radius-none);
|
|
118
|
+
--tabbar-active-indicator-border-width: var(--border-width-2);
|
|
117
119
|
|
|
118
120
|
/* Disabled tab */
|
|
119
121
|
--tabbar-disabled-text: var(--text-disabled);
|
|
@@ -129,6 +131,7 @@
|
|
|
129
131
|
--tabbar-disabled-tab-border-width: var(--border-width-0);
|
|
130
132
|
--tabbar-disabled-tab-top-radius: var(--radius-none);
|
|
131
133
|
--tabbar-disabled-tab-bottom-radius: var(--radius-none);
|
|
134
|
+
--tabbar-disabled-indicator-border-width: var(--border-width-2);
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
.tab-bar {
|
|
@@ -157,6 +160,7 @@
|
|
|
157
160
|
--_icon-size: var(--tabbar-default-icon-size);
|
|
158
161
|
--_surface: var(--tabbar-default-surface);
|
|
159
162
|
--_indicator-color: var(--tabbar-default-border);
|
|
163
|
+
--_indicator-width: var(--tabbar-default-indicator-border-width);
|
|
160
164
|
--_padding: var(--tabbar-default-padding);
|
|
161
165
|
--_border-color: var(--tabbar-default-tab-border-color);
|
|
162
166
|
--_border-width: var(--tabbar-default-tab-border-width);
|
|
@@ -169,9 +173,10 @@
|
|
|
169
173
|
padding: var(--_padding) calc(var(--_padding) * 2);
|
|
170
174
|
background: var(--_surface);
|
|
171
175
|
border: var(--_border-width) solid var(--_border-color);
|
|
172
|
-
/* Indicator accent owns the bottom edge.
|
|
173
|
-
|
|
174
|
-
|
|
176
|
+
/* Indicator accent owns the bottom edge. Both width and color rebind
|
|
177
|
+
per state — `--tabbar-{state}-indicator-border-width` and
|
|
178
|
+
`--tabbar-{state}-border` (the indicator color slot). */
|
|
179
|
+
border-bottom: var(--_indicator-width) solid var(--_indicator-color);
|
|
175
180
|
border-radius: var(--_top-radius) var(--_top-radius) var(--_bottom-radius) var(--_bottom-radius);
|
|
176
181
|
color: var(--_text-color);
|
|
177
182
|
font-family: var(--_text-family);
|
|
@@ -200,6 +205,7 @@
|
|
|
200
205
|
--_icon-size: var(--tabbar-hover-icon-size);
|
|
201
206
|
--_surface: var(--tabbar-hover-surface);
|
|
202
207
|
--_indicator-color: var(--tabbar-hover-border);
|
|
208
|
+
--_indicator-width: var(--tabbar-hover-indicator-border-width);
|
|
203
209
|
--_padding: var(--tabbar-hover-padding);
|
|
204
210
|
--_border-color: var(--tabbar-hover-tab-border-color);
|
|
205
211
|
--_border-width: var(--tabbar-hover-tab-border-width);
|
|
@@ -216,6 +222,7 @@
|
|
|
216
222
|
--_icon-size: var(--tabbar-active-icon-size);
|
|
217
223
|
--_surface: var(--tabbar-active-surface);
|
|
218
224
|
--_indicator-color: var(--tabbar-active-border);
|
|
225
|
+
--_indicator-width: var(--tabbar-active-indicator-border-width);
|
|
219
226
|
--_padding: var(--tabbar-active-padding);
|
|
220
227
|
--_border-color: var(--tabbar-active-tab-border-color);
|
|
221
228
|
--_border-width: var(--tabbar-active-tab-border-width);
|
|
@@ -232,6 +239,7 @@
|
|
|
232
239
|
--_icon-size: var(--tabbar-disabled-icon-size);
|
|
233
240
|
--_surface: var(--tabbar-disabled-surface);
|
|
234
241
|
--_indicator-color: var(--tabbar-disabled-border);
|
|
242
|
+
--_indicator-width: var(--tabbar-disabled-indicator-border-width);
|
|
235
243
|
--_padding: var(--tabbar-disabled-padding);
|
|
236
244
|
--_border-color: var(--tabbar-disabled-tab-border-color);
|
|
237
245
|
--_border-width: var(--tabbar-disabled-tab-border-width);
|
|
@@ -55,11 +55,10 @@
|
|
|
55
55
|
--toggle-track-border: var(--border-neutral);
|
|
56
56
|
--toggle-track-border-width: var(--border-width-1);
|
|
57
57
|
--toggle-track-radius: var(--radius-full);
|
|
58
|
-
--toggle-track-
|
|
59
|
-
--toggle-track-thickness: var(--space-16);
|
|
58
|
+
--toggle-track-padding: var(--space-2);
|
|
60
59
|
--toggle-thumb-surface: var(--surface-neutral-highest);
|
|
61
60
|
--toggle-thumb-border: var(--border-neutral-strong);
|
|
62
|
-
--toggle-thumb-size: var(--
|
|
61
|
+
--toggle-thumb-size: var(--font-size-md);
|
|
63
62
|
--toggle-label-text: var(--text-primary);
|
|
64
63
|
--toggle-label-font-family: var(--font-sans);
|
|
65
64
|
--toggle-label-font-size: var(--font-size-sm);
|
|
@@ -97,12 +96,16 @@
|
|
|
97
96
|
}
|
|
98
97
|
.toggle:disabled { cursor: not-allowed; }
|
|
99
98
|
|
|
99
|
+
/* Track geometry derives from the thumb. Width fits two thumb-widths plus
|
|
100
|
+
padding on each side; height fits one thumb plus the same padding. The
|
|
101
|
+
thumb's "on" travel is then exactly one thumb-width, regardless of
|
|
102
|
+
thumb-size or padding. Border sits outside (content-box default). */
|
|
100
103
|
.track {
|
|
101
104
|
position: relative;
|
|
102
105
|
flex: none;
|
|
103
106
|
display: inline-block;
|
|
104
|
-
width: var(--toggle-track-
|
|
105
|
-
height: var(--toggle-track-
|
|
107
|
+
width: calc(var(--toggle-thumb-size) * 2 + var(--toggle-track-padding) * 2);
|
|
108
|
+
height: calc(var(--toggle-thumb-size) + var(--toggle-track-padding) * 2);
|
|
106
109
|
background: var(--toggle-track-surface);
|
|
107
110
|
border: var(--toggle-track-border-width) solid var(--toggle-track-border);
|
|
108
111
|
border-radius: var(--toggle-track-radius);
|
|
@@ -112,7 +115,7 @@
|
|
|
112
115
|
.thumb {
|
|
113
116
|
position: absolute;
|
|
114
117
|
top: 50%;
|
|
115
|
-
left: var(--
|
|
118
|
+
left: var(--toggle-track-padding);
|
|
116
119
|
width: var(--toggle-thumb-size);
|
|
117
120
|
height: var(--toggle-thumb-size);
|
|
118
121
|
transform: translateY(-50%);
|
|
@@ -145,8 +148,8 @@
|
|
|
145
148
|
border-color: var(--toggle-on-track-border);
|
|
146
149
|
}
|
|
147
150
|
.toggle.on .thumb {
|
|
148
|
-
/*
|
|
149
|
-
left: calc(var(--toggle-
|
|
151
|
+
/* Mirror of the off-position calc: travel is exactly one thumb-width. */
|
|
152
|
+
left: calc(var(--toggle-thumb-size) + var(--toggle-track-padding));
|
|
150
153
|
background: var(--toggle-on-thumb-surface);
|
|
151
154
|
border-color: var(--toggle-on-thumb-border);
|
|
152
155
|
}
|