@motion-proto/live-tokens 0.96.0 → 0.98.2
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/.claude/skills/live-tokens-check-compliance/SKILL.md +5 -0
- package/.claude/skills/live-tokens-create-component/SKILL.md +4 -3
- package/.claude/skills/live-tokens-create-component/references/contract-tests.md +71 -11
- package/CHANGELOG.md +309 -0
- package/README.md +2 -2
- package/bin/check-component.mjs +8 -0
- package/bin/check-page.mjs +6 -0
- package/bin/cli.mjs +36 -6
- package/bin/contractRunner.mjs +142 -17
- package/bin/lib/findings.mjs +20 -4
- package/bin/rules/a11y.mjs +53 -0
- package/bin/set-colors.mjs +1 -0
- package/bin/setup-claude.mjs +2 -2
- package/dist-plugin/{chunk-A4TBP4MM.js → chunk-SLICH4IH.js} +2 -2
- package/dist-plugin/index.cjs +148 -3
- package/dist-plugin/index.js +250 -105
- package/dist-plugin/setColors/index.cjs +7 -1
- package/dist-plugin/setColors/index.d.cts +9 -4
- package/dist-plugin/setColors/index.d.ts +9 -4
- package/dist-plugin/setColors/index.js +8 -2
- package/dist-plugin/setGeometry/index.d.cts +1 -1
- package/dist-plugin/setGeometry/index.d.ts +1 -1
- package/dist-plugin/setType/index.d.cts +1 -1
- package/dist-plugin/setType/index.d.ts +1 -1
- package/dist-plugin/{themeTypes-B8_Idrp4.d.cts → themeTypes-BaTQUyac.d.cts} +10 -1
- package/dist-plugin/{themeTypes-B8_Idrp4.d.ts → themeTypes-BaTQUyac.d.ts} +10 -1
- package/package.json +49 -2
- package/src/demo/LabeledSelect.svelte +1 -1
- package/src/editor/bootstrap.ts +3 -1
- package/src/editor/component-editor/BadgeEditor.svelte +13 -0
- package/src/editor/component-editor/ButtonEditor.svelte +33 -2
- package/src/editor/component-editor/CalloutEditor.svelte +13 -0
- package/src/editor/component-editor/CardEditor.svelte +12 -2
- package/src/editor/component-editor/CodeSnippetEditor.svelte +11 -1
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +18 -1
- package/src/editor/component-editor/CornerBadgeEditor.svelte +13 -0
- package/src/editor/component-editor/DialogEditor.svelte +15 -0
- package/src/editor/component-editor/IconButtonEditor.svelte +29 -1
- package/src/editor/component-editor/ImageEditor.svelte +20 -9
- package/src/editor/component-editor/ImageLightboxEditor.svelte +44 -0
- package/src/editor/component-editor/InlineEditActionsEditor.svelte +13 -1
- package/src/editor/component-editor/InputEditor.svelte +23 -0
- package/src/editor/component-editor/MenuSelectEditor.svelte +27 -1
- package/src/editor/component-editor/NotificationEditor.svelte +15 -0
- package/src/editor/component-editor/PanelEditor.svelte +1 -1
- package/src/editor/component-editor/ProgressBarEditor.svelte +13 -0
- package/src/editor/component-editor/RadioButtonEditor.svelte +20 -1
- package/src/editor/component-editor/SectionDividerEditor.svelte +41 -13
- package/src/editor/component-editor/SegmentedControlEditor.svelte +29 -1
- package/src/editor/component-editor/SideNavigationEditor.svelte +40 -1
- package/src/editor/component-editor/SlidePagerEditor.svelte +20 -0
- package/src/editor/component-editor/SliderEditor.svelte +33 -0
- package/src/editor/component-editor/TabBarEditor.svelte +23 -2
- package/src/editor/component-editor/TableEditor.svelte +14 -0
- package/src/editor/component-editor/ToggleEditor.svelte +17 -0
- package/src/editor/component-editor/TooltipEditor.svelte +11 -2
- package/src/editor/component-editor/VideoFrameEditor.svelte +8 -0
- package/src/editor/component-editor/VideoLightboxEditor.svelte +10 -0
- package/src/editor/component-editor/registration.ts +2 -1
- package/src/editor/component-editor/registry.ts +69 -27
- package/src/editor/component-editor/scaffolding/DemoHeader.svelte +2 -0
- package/src/editor/component-editor/scaffolding/StateBlock.svelte +19 -8
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +3 -0
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +70 -10
- package/src/editor/component-editor/scaffolding/editorContext.ts +7 -0
- package/src/editor/core/a11y/a11yReport.ts +101 -0
- package/src/editor/core/a11y/a11yReportTypes.ts +69 -0
- package/src/editor/core/a11y/contrastFailures.ts +22 -0
- package/src/editor/core/components/contrastPairRegistry.ts +18 -0
- package/src/editor/core/palettes/contrast.ts +44 -0
- package/src/editor/core/palettes/contrastPairs.ts +79 -0
- package/src/editor/core/palettes/resolveColor.ts +77 -0
- package/src/editor/core/store/editorPersistence.ts +9 -1
- package/src/editor/core/store/editorRenderer.ts +2 -0
- package/src/editor/core/store/editorStore.ts +29 -0
- package/src/editor/core/store/editorTypes.ts +9 -0
- package/src/editor/core/store/editorViewStore.ts +2 -2
- package/src/editor/core/store/unsavedEdits.ts +10 -0
- package/src/editor/core/themes/buildColors.ts +16 -5
- package/src/editor/core/themes/liveStateStream.ts +7 -1
- package/src/editor/core/themes/parsers/gradient.ts +5 -2
- package/src/editor/core/themes/slices/customColors.ts +226 -0
- package/src/editor/core/themes/themeTypes.ts +10 -0
- package/src/editor/docs/chapters.ts +1 -0
- package/src/editor/docs/content/accessibility.md +362 -0
- package/src/editor/docs/content/editing-tokens.md +56 -1
- package/src/editor/docs/content.generated.ts +2 -1
- package/src/editor/pages/ComponentEditorPage.svelte +10 -1
- package/src/editor/pages/EditorShell.svelte +97 -10
- package/src/editor/skill-atlas/skillSources.generated.ts +3 -3
- package/src/editor/skill-atlas/trees/check-compliance.ts +3 -3
- package/src/editor/skill-atlas/trees/create-component.ts +12 -12
- package/src/editor/ui/CustomColorReplaceStep.svelte +118 -0
- package/src/editor/ui/EditorViewSwitcher.svelte +15 -2
- package/src/editor/ui/GradientEditor.svelte +9 -1
- package/src/editor/ui/ThemePanel.svelte +4 -4
- package/src/editor/ui/UIContrastReadout.svelte +186 -0
- package/src/editor/ui/UIInfoPopover.svelte +16 -2
- package/src/editor/ui/UIPaletteSelector.svelte +347 -15
- package/src/editor/ui/UITokenSelector.svelte +33 -14
- package/src/editor/ui/VariablesTab.svelte +3 -0
- package/src/editor/ui/a11y/A11yComponentIssues.svelte +103 -0
- package/src/editor/ui/a11y/A11yFindingRow.svelte +57 -0
- package/src/editor/ui/a11y/A11yIssueRow.svelte +121 -0
- package/src/editor/ui/a11y/A11yOverview.svelte +242 -0
- package/src/editor/ui/a11y/A11yPanel.svelte +128 -0
- package/src/editor/ui/a11y/A11yPropertyMark.svelte +84 -0
- package/src/editor/ui/a11y/A11yRailMark.svelte +34 -0
- package/src/editor/ui/a11y/AccessibilityTab.svelte +334 -0
- package/src/editor/ui/a11y/a11yView.ts +218 -0
- package/src/editor/ui/anchorToTrigger.ts +63 -0
- package/src/editor/ui/contrastReadout.ts +45 -0
- package/src/editor/ui/sections/CustomColorsSection.svelte +254 -0
- package/src/live-tokens/data/themes/autumn.json +20 -20
- package/src/live-tokens/data/themes/halloween.json +20 -20
- package/src/live-tokens/data/themes/midnight-study.json +20 -20
- package/src/live-tokens/data/themes/ocean.json +20 -20
- package/src/live-tokens/data/themes/royal-velvet.json +20 -20
- package/src/live-tokens/data/themes/sketchy.json +20 -20
- package/src/live-tokens/data/themes/spring-meadow.json +20 -20
- package/src/live-tokens/data/themes/sunset.json +20 -20
- package/src/system/components/Badge.svelte +3 -3
- package/src/system/components/Button.svelte +9 -3
- package/src/system/components/CodeSnippet.svelte +8 -1
- package/src/system/components/CornerBadge.svelte +3 -3
- package/src/system/components/Dialog.svelte +43 -14
- package/src/system/components/IconButton.svelte +1 -1
- package/src/system/components/Image.svelte +7 -0
- package/src/system/components/ImageLightbox.svelte +26 -26
- package/src/system/components/Input.svelte +8 -1
- package/src/system/components/MenuSelect.svelte +30 -2
- package/src/system/components/Notification.svelte +1 -1
- package/src/system/components/ProgressBar.svelte +6 -0
- package/src/system/components/RadioButton.svelte +36 -3
- package/src/system/components/SegmentedControl.svelte +36 -2
- package/src/system/components/SlidePager.svelte +2 -2
- package/src/system/components/Slider.svelte +13 -9
- package/src/system/components/TabBar.svelte +33 -3
- package/src/system/components/Toggle.svelte +2 -2
- package/src/system/components/VideoFrame.svelte +1 -1
- package/src/system/components/VideoLightbox.svelte +2 -2
- package/src/system/internal/focusTrap.ts +35 -0
- package/src/testing-js/__aria__/badge.yml +40 -0
- package/src/testing-js/__aria__/button.yml +88 -0
- package/src/testing-js/__aria__/callout.yml +12 -0
- package/src/testing-js/__aria__/card.yml +8 -0
- package/src/testing-js/__aria__/codesnippet.yml +21 -0
- package/src/testing-js/__aria__/collapsiblesection.yml +23 -0
- package/src/testing-js/__aria__/cornerbadge.yml +24 -0
- package/src/testing-js/__aria__/dialog.yml +42 -0
- package/src/testing-js/__aria__/iconbutton.yml +57 -0
- package/src/testing-js/__aria__/image.yml +10 -0
- package/src/testing-js/__aria__/imagelightbox.yml +50 -0
- package/src/testing-js/__aria__/inlineeditactions.yml +16 -0
- package/src/testing-js/__aria__/input.yml +61 -0
- package/src/testing-js/__aria__/menuselect.yml +30 -0
- package/src/testing-js/__aria__/notification.yml +30 -0
- package/src/testing-js/__aria__/panel.yml +2 -0
- package/src/testing-js/__aria__/progressbar.yml +2 -0
- package/src/testing-js/__aria__/radiobutton.yml +20 -0
- package/src/testing-js/__aria__/sectiondivider.yml +9 -0
- package/src/testing-js/__aria__/segmentedcontrol.yml +35 -0
- package/src/testing-js/__aria__/sidenavigation.yml +304 -0
- package/src/testing-js/__aria__/slidepager.yml +72 -0
- package/src/testing-js/__aria__/slider.yml +28 -0
- package/src/testing-js/__aria__/tabbar.yml +35 -0
- package/src/testing-js/__aria__/table.yml +144 -0
- package/src/testing-js/__aria__/toggle.yml +12 -0
- package/src/testing-js/__aria__/tooltip.yml +2 -0
- package/src/testing-js/__aria__/videoframe.yml +6 -0
- package/src/testing-js/__aria__/videolightbox.yml +12 -0
- package/src/testing-js/{chunk-WIZ6W7UT.js → chunk-3WCLMOM7.js} +2 -2
- package/src/testing-js/{chunk-SHBYZUPD.js → chunk-5HNZHIHG.js} +211 -14
- package/src/testing-js/chunk-5HNZHIHG.js.map +1 -0
- package/src/testing-js/{chunk-NB3NZRBM.js → chunk-7CM5D7PF.js} +5 -1
- package/src/testing-js/chunk-7CM5D7PF.js.map +1 -0
- package/src/testing-js/chunk-EWSGE27V.js +168 -0
- package/src/testing-js/chunk-EWSGE27V.js.map +1 -0
- package/src/testing-js/{chunk-GKO27NGN.js → chunk-R54I7YL6.js} +2 -2
- package/src/testing-js/{chunk-X6KHEVIG.js → chunk-RWH46IU5.js} +97 -29
- package/src/testing-js/chunk-RWH46IU5.js.map +1 -0
- package/src/testing-js/chunk-SHLPDNAQ.js +658 -0
- package/src/testing-js/chunk-SHLPDNAQ.js.map +1 -0
- package/src/testing-js/{chunk-3UKGXCDL.js → chunk-YVVR3GJZ.js} +1 -1
- package/src/testing-js/chunk-YVVR3GJZ.js.map +1 -0
- package/src/testing-js/component-a11y.contract.js +283 -0
- package/src/testing-js/component-a11y.contract.js.map +1 -0
- package/src/testing-js/component-alias.contract.js +2 -2
- package/src/testing-js/component-behavior.contract.js +2 -2
- package/src/testing-js/component-editor.contract.js +6 -5
- package/src/testing-js/component-editor.contract.js.map +1 -1
- package/src/testing-js/component-render.contract.js +10 -6
- package/src/testing-js/component-render.contract.js.map +1 -1
- package/src/testing-js/index.d.ts +44 -16
- package/src/testing-js/index.js +9 -9
- package/src/testing-js/page-compliance.contract.js +163 -18
- package/src/testing-js/page-compliance.contract.js.map +1 -1
- package/src/testing-js/vitest.js +3 -3
- package/template/package.json +9 -0
- package/src/editor/ui/keepInViewport.ts +0 -84
- package/src/testing-js/chunk-3UKGXCDL.js.map +0 -1
- package/src/testing-js/chunk-NB3NZRBM.js.map +0 -1
- package/src/testing-js/chunk-SHBYZUPD.js.map +0 -1
- package/src/testing-js/chunk-X6KHEVIG.js.map +0 -1
- /package/src/testing-js/{chunk-WIZ6W7UT.js.map → chunk-3WCLMOM7.js.map} +0 -0
- /package/src/testing-js/{chunk-GKO27NGN.js.map → chunk-R54I7YL6.js.map} +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svelte action: pin a `position: fixed` popover under its trigger so no
|
|
3
|
+
* scrolling or clipping ancestor can cut it off. It aligns to the trigger's
|
|
4
|
+
* left edge, flips above when the space below runs out, and clamps to the
|
|
5
|
+
* viewport. It re-places on scroll, resize, and content reflow.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const GAP = 4;
|
|
9
|
+
const MARGIN = 8;
|
|
10
|
+
|
|
11
|
+
export function anchorToTrigger(node: HTMLElement, trigger: HTMLElement) {
|
|
12
|
+
let anchor = trigger;
|
|
13
|
+
let pendingFrame: number | null = null;
|
|
14
|
+
|
|
15
|
+
function place(): void {
|
|
16
|
+
// A container-type or transformed ancestor moves the fixed containing
|
|
17
|
+
// block off the viewport origin. Measuring at 0,0 reads that offset.
|
|
18
|
+
node.style.left = '0px';
|
|
19
|
+
node.style.top = '0px';
|
|
20
|
+
const origin = node.getBoundingClientRect();
|
|
21
|
+
const a = anchor.getBoundingClientRect();
|
|
22
|
+
const vw = window.innerWidth;
|
|
23
|
+
const vh = window.innerHeight;
|
|
24
|
+
|
|
25
|
+
const left = Math.max(MARGIN, Math.min(a.left, vw - MARGIN - origin.width));
|
|
26
|
+
let top = a.bottom + GAP;
|
|
27
|
+
if (top + origin.height > vh - MARGIN) {
|
|
28
|
+
const above = a.top - GAP - origin.height;
|
|
29
|
+
top = above >= MARGIN ? above : Math.max(MARGIN, vh - MARGIN - origin.height);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
node.style.left = `${left - origin.left}px`;
|
|
33
|
+
node.style.top = `${top - origin.top}px`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function schedule(): void {
|
|
37
|
+
if (pendingFrame !== null) return;
|
|
38
|
+
pendingFrame = requestAnimationFrame(() => {
|
|
39
|
+
pendingFrame = null;
|
|
40
|
+
place();
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
place();
|
|
45
|
+
|
|
46
|
+
const ro = new ResizeObserver(schedule);
|
|
47
|
+
ro.observe(node);
|
|
48
|
+
window.addEventListener('resize', schedule);
|
|
49
|
+
window.addEventListener('scroll', schedule, true);
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
update(next: HTMLElement) {
|
|
53
|
+
anchor = next;
|
|
54
|
+
schedule();
|
|
55
|
+
},
|
|
56
|
+
destroy() {
|
|
57
|
+
if (pendingFrame !== null) cancelAnimationFrame(pendingFrame);
|
|
58
|
+
ro.disconnect();
|
|
59
|
+
window.removeEventListener('resize', schedule);
|
|
60
|
+
window.removeEventListener('scroll', schedule, true);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CONTRAST_RULES, LARGE_BOLD_PX, LARGE_TEXT_PX } from '../core/palettes/contrast';
|
|
2
|
+
import { closestToFailing, type PairMeasure } from '../core/palettes/contrastPairs';
|
|
3
|
+
|
|
4
|
+
export type ReadoutState = 'pass' | 'fail' | 'inactive';
|
|
5
|
+
|
|
6
|
+
export interface Readout {
|
|
7
|
+
label: string;
|
|
8
|
+
state: ReadoutState;
|
|
9
|
+
ariaLabel: string;
|
|
10
|
+
measure: PairMeasure;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Truncation keeps a failing value from displaying as its floor. */
|
|
14
|
+
export function formatRatio(ratio: number): string {
|
|
15
|
+
return `${(Math.floor(ratio * 100 + 1e-9) / 100).toFixed(2)}:1`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const formatFloor = (floor: number) => `${floor}:1`;
|
|
19
|
+
|
|
20
|
+
export function measureState(measure: PairMeasure): ReadoutState {
|
|
21
|
+
if (measure.pair.inactive) return 'inactive';
|
|
22
|
+
return measure.passes ? 'pass' : 'fail';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function readoutState(measures: PairMeasure[]): Readout {
|
|
26
|
+
const measure = closestToFailing(measures);
|
|
27
|
+
const state = measureState(measure);
|
|
28
|
+
const label = formatRatio(measure.ratio);
|
|
29
|
+
const verdict = state === 'inactive'
|
|
30
|
+
? 'exempt as a disabled control'
|
|
31
|
+
: `${state === 'pass' ? 'meets' : 'below'} ${formatFloor(measure.floor)}`;
|
|
32
|
+
return { label, state, ariaLabel: `Contrast ${label}, ${verdict}`, measure };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function ruleSentence(measure: PairMeasure): string {
|
|
36
|
+
const rule = CONTRAST_RULES[measure.pair.role];
|
|
37
|
+
let sentence = `WCAG 2.2 success criterion ${rule.criterion}, ${rule.name} (${rule.level}): `
|
|
38
|
+
+ `${formatFloor(rule.floor)} against the colors behind it`;
|
|
39
|
+
if (rule.largeFloor !== undefined) {
|
|
40
|
+
sentence += `, or ${formatFloor(rule.largeFloor)} for large text (${LARGE_TEXT_PX}px, or ${LARGE_BOLD_PX}px bold)`;
|
|
41
|
+
}
|
|
42
|
+
sentence += '.';
|
|
43
|
+
if (measure.pair.inactive) sentence += ' Disabled controls are exempt.';
|
|
44
|
+
return sentence;
|
|
45
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import { get } from 'svelte/store';
|
|
4
|
+
import {
|
|
5
|
+
editorState,
|
|
6
|
+
beginScope,
|
|
7
|
+
commitScope,
|
|
8
|
+
cancelScope,
|
|
9
|
+
beginSliderGesture,
|
|
10
|
+
setCustomColor,
|
|
11
|
+
removeCustomColor,
|
|
12
|
+
replaceAndRemoveCustomColor,
|
|
13
|
+
type Scope,
|
|
14
|
+
} from '../../core/store/editorStore';
|
|
15
|
+
import type { Oklch } from '../../core/palettes/oklch';
|
|
16
|
+
import ColorEditPanel from '../ColorEditPanel.svelte';
|
|
17
|
+
import CustomColorReplaceStep from '../CustomColorReplaceStep.svelte';
|
|
18
|
+
|
|
19
|
+
interface Props {
|
|
20
|
+
copiedVar?: string | null;
|
|
21
|
+
oncopy?: (variable: string) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { copiedVar = null, oncopy }: Props = $props();
|
|
25
|
+
|
|
26
|
+
const PREFIX = '--color-custom-';
|
|
27
|
+
const customNumber = (v: string) => v.slice(PREFIX.length);
|
|
28
|
+
|
|
29
|
+
let tokens = $derived(
|
|
30
|
+
[...$editorState.customColors.tokens]
|
|
31
|
+
.sort((a, b) => Number(customNumber(a.variable)) - Number(customNumber(b.variable))),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
/** An open edit of one custom colour, or the replace step of its remove. */
|
|
35
|
+
interface Session {
|
|
36
|
+
mode: 'edit' | 'replace';
|
|
37
|
+
variable: string;
|
|
38
|
+
draft: Oklch;
|
|
39
|
+
}
|
|
40
|
+
let session = $state<Session | null>(null);
|
|
41
|
+
// Held outside $state: the store matches an open scope by identity, and a
|
|
42
|
+
// proxied handle would never match.
|
|
43
|
+
let sessionScope: Scope | null = null;
|
|
44
|
+
|
|
45
|
+
function tokenColor(variable: string): Oklch | undefined {
|
|
46
|
+
return get(editorState).customColors.tokens.find((t) => t.variable === variable)?.color;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function openEdit(variable: string) {
|
|
50
|
+
const color = tokenColor(variable);
|
|
51
|
+
if (!color) return;
|
|
52
|
+
sessionScope = beginScope({ label: `edit custom colour ${variable}`, collapseToOne: true, clipUndoFloor: true });
|
|
53
|
+
session = { mode: 'edit', variable, draft: { ...color } };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function editDraft(h: number, c: number, lPct: number) {
|
|
57
|
+
if (!session) return;
|
|
58
|
+
session.draft = { l: lPct / 100, c, h };
|
|
59
|
+
setCustomColor(session.variable, session.draft);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function closeEdit(commit: boolean) {
|
|
63
|
+
if (sessionScope) {
|
|
64
|
+
if (commit) commitScope(sessionScope);
|
|
65
|
+
else cancelScope(sessionScope);
|
|
66
|
+
}
|
|
67
|
+
sessionScope = null;
|
|
68
|
+
session = null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function requestRemove(variable: string) {
|
|
72
|
+
if (removeCustomColor(variable)) return;
|
|
73
|
+
const color = tokenColor(variable);
|
|
74
|
+
if (color) session = { mode: 'replace', variable, draft: { ...color } };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function confirmReplace(replacement: string) {
|
|
78
|
+
if (!session) return;
|
|
79
|
+
const { variable } = session;
|
|
80
|
+
session = null;
|
|
81
|
+
replaceAndRemoveCustomColor(variable, replacement);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
onDestroy(() => {
|
|
85
|
+
if (sessionScope) cancelScope(sessionScope);
|
|
86
|
+
});
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<section class="section" id="custom-colors">
|
|
90
|
+
<h2 class="section-title">Custom Colours</h2>
|
|
91
|
+
<p class="editor-intro">A custom colour holds its own OKLCH value, and every slot that names it follows its edits. Add one from the Custom row of any colour picker. Removing a colour in use first asks which token takes its place.</p>
|
|
92
|
+
{#if tokens.length === 0}
|
|
93
|
+
<p class="custom-empty">This theme has no custom colours.</p>
|
|
94
|
+
{:else}
|
|
95
|
+
<div class="custom-grid">
|
|
96
|
+
{#each tokens as token (token.variable)}
|
|
97
|
+
{@const active = session?.variable === token.variable}
|
|
98
|
+
<div class={['custom-item', { active }]}>
|
|
99
|
+
<div class="custom-box" style="background: var({token.variable});"></div>
|
|
100
|
+
<div class="token-info">
|
|
101
|
+
<button class={['token-variable copyable', { copied: copiedVar === token.variable }]} onclick={() => oncopy?.(token.variable)}>{copiedVar === token.variable ? 'copied!' : token.variable}</button>
|
|
102
|
+
{#if !active}
|
|
103
|
+
<div class="custom-actions">
|
|
104
|
+
<button
|
|
105
|
+
class="custom-btn"
|
|
106
|
+
aria-label="Edit {token.variable}"
|
|
107
|
+
disabled={session !== null}
|
|
108
|
+
onclick={() => openEdit(token.variable)}
|
|
109
|
+
>Edit</button>
|
|
110
|
+
<button
|
|
111
|
+
class="custom-btn"
|
|
112
|
+
aria-label="Remove {token.variable}"
|
|
113
|
+
disabled={session !== null}
|
|
114
|
+
onclick={() => requestRemove(token.variable)}
|
|
115
|
+
>Remove</button>
|
|
116
|
+
</div>
|
|
117
|
+
{/if}
|
|
118
|
+
</div>
|
|
119
|
+
{#if active && session}
|
|
120
|
+
<div class="custom-editor-host">
|
|
121
|
+
{#if session.mode === 'edit'}
|
|
122
|
+
<ColorEditPanel
|
|
123
|
+
title="Custom › {customNumber(session.variable)}"
|
|
124
|
+
hue={session.draft.h}
|
|
125
|
+
chroma={session.draft.c}
|
|
126
|
+
lightness={session.draft.l * 100}
|
|
127
|
+
onHueChromaChange={editDraft}
|
|
128
|
+
onSliderStart={() => beginSliderGesture(`edit ${session?.variable ?? 'custom colour'}`)}
|
|
129
|
+
onConfirm={() => closeEdit(true)}
|
|
130
|
+
onCancel={() => closeEdit(false)}
|
|
131
|
+
/>
|
|
132
|
+
{:else}
|
|
133
|
+
<CustomColorReplaceStep
|
|
134
|
+
variable={session.variable}
|
|
135
|
+
color={session.draft}
|
|
136
|
+
onconfirm={confirmReplace}
|
|
137
|
+
oncancel={() => (session = null)}
|
|
138
|
+
/>
|
|
139
|
+
{/if}
|
|
140
|
+
</div>
|
|
141
|
+
{/if}
|
|
142
|
+
</div>
|
|
143
|
+
{/each}
|
|
144
|
+
</div>
|
|
145
|
+
{/if}
|
|
146
|
+
</section>
|
|
147
|
+
|
|
148
|
+
<style>
|
|
149
|
+
.section {
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
gap: var(--ui-space-24);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.section-title {
|
|
156
|
+
font-size: var(--ui-font-size-2xl);
|
|
157
|
+
font-weight: var(--ui-font-weight-semibold);
|
|
158
|
+
color: var(--ui-text-primary);
|
|
159
|
+
margin: 0;
|
|
160
|
+
padding-bottom: var(--ui-space-8);
|
|
161
|
+
border-bottom: 2px solid var(--ui-border-high);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.editor-intro,
|
|
165
|
+
.custom-empty {
|
|
166
|
+
font-size: var(--ui-font-size-md);
|
|
167
|
+
color: var(--ui-text-tertiary);
|
|
168
|
+
margin: 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.token-variable.copyable {
|
|
172
|
+
all: unset;
|
|
173
|
+
font-size: var(--ui-font-size-md);
|
|
174
|
+
color: var(--ui-text-tertiary);
|
|
175
|
+
font-family: var(--ui-font-mono);
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
transition: color var(--ui-transition-fast);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.token-variable.copyable:hover {
|
|
181
|
+
color: var(--ui-text-accent);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.token-variable.copyable.copied {
|
|
185
|
+
color: var(--ui-text-success);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.custom-grid {
|
|
189
|
+
display: grid;
|
|
190
|
+
grid-template-columns: repeat(auto-fill, minmax(min(14rem, 100%), 1fr));
|
|
191
|
+
gap: var(--ui-space-16);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.custom-item {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: column;
|
|
197
|
+
gap: var(--ui-space-8);
|
|
198
|
+
padding: var(--ui-space-12);
|
|
199
|
+
border: 1px solid var(--ui-border-low);
|
|
200
|
+
border-radius: var(--ui-radius-lg);
|
|
201
|
+
background: var(--ui-surface-lowest);
|
|
202
|
+
min-width: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.custom-item.active {
|
|
206
|
+
grid-column: 1 / -1;
|
|
207
|
+
border-color: var(--ui-text-primary);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.custom-box {
|
|
211
|
+
height: 3rem;
|
|
212
|
+
border-radius: var(--ui-radius-md);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.token-info {
|
|
216
|
+
display: flex;
|
|
217
|
+
align-items: center;
|
|
218
|
+
justify-content: space-between;
|
|
219
|
+
gap: var(--ui-space-8);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.custom-actions {
|
|
223
|
+
display: flex;
|
|
224
|
+
gap: var(--ui-space-4);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.custom-btn {
|
|
228
|
+
padding: var(--ui-space-2) var(--ui-space-10);
|
|
229
|
+
background: var(--ui-surface-low);
|
|
230
|
+
border: 1px solid var(--ui-border-low);
|
|
231
|
+
border-radius: var(--ui-radius-sm);
|
|
232
|
+
color: var(--ui-text-secondary);
|
|
233
|
+
font-size: var(--ui-font-size-xs);
|
|
234
|
+
cursor: pointer;
|
|
235
|
+
font-family: inherit;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.custom-btn:hover:not(:disabled) {
|
|
239
|
+
color: var(--ui-text-primary);
|
|
240
|
+
border-color: var(--ui-border);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.custom-btn:disabled {
|
|
244
|
+
cursor: default;
|
|
245
|
+
opacity: 0.5;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.custom-editor-host {
|
|
249
|
+
max-width: 28rem;
|
|
250
|
+
margin-top: var(--ui-space-8);
|
|
251
|
+
padding-top: var(--ui-space-12);
|
|
252
|
+
border-top: 1px dashed var(--ui-border-low);
|
|
253
|
+
}
|
|
254
|
+
</style>
|
|
@@ -2480,7 +2480,7 @@
|
|
|
2480
2480
|
"createdAt": "2026-05-01T08:28:00.345Z",
|
|
2481
2481
|
"updatedAt": "2026-08-19T22:39:32.785Z",
|
|
2482
2482
|
"aliases": {
|
|
2483
|
-
"--badge-brand-surface": "--surface-brand",
|
|
2483
|
+
"--badge-brand-surface": "--surface-brand-low",
|
|
2484
2484
|
"--badge-brand-text": "--text-brand",
|
|
2485
2485
|
"--badge-brand-border": "--border-brand",
|
|
2486
2486
|
"--badge-brand-text-font-family": "--font-sans",
|
|
@@ -2533,7 +2533,7 @@
|
|
|
2533
2533
|
"--badge-alternate-blur": "--blur-none",
|
|
2534
2534
|
"--badge-alternate-icon-size": "--icon-size-sm",
|
|
2535
2535
|
"--badge-canvas-surface": "--surface-canvas",
|
|
2536
|
-
"--badge-canvas-text": "--text-
|
|
2536
|
+
"--badge-canvas-text": "--text-secondary",
|
|
2537
2537
|
"--badge-canvas-border": "--border-canvas",
|
|
2538
2538
|
"--badge-canvas-text-font-family": "--font-sans",
|
|
2539
2539
|
"--badge-canvas-text-font-size": "--font-size-md",
|
|
@@ -2584,7 +2584,7 @@
|
|
|
2584
2584
|
"--badge-warning-shadow": "--shadow-none",
|
|
2585
2585
|
"--badge-warning-blur": "--blur-none",
|
|
2586
2586
|
"--badge-warning-icon-size": "--icon-size-sm",
|
|
2587
|
-
"--badge-danger-surface": "--surface-danger",
|
|
2587
|
+
"--badge-danger-surface": "--surface-danger-low",
|
|
2588
2588
|
"--badge-danger-text": "--text-danger",
|
|
2589
2589
|
"--badge-danger-border": "--border-danger",
|
|
2590
2590
|
"--badge-danger-text-font-family": "--font-sans",
|
|
@@ -2957,7 +2957,7 @@
|
|
|
2957
2957
|
"--cornerbadge-text-font-size": "--font-size-sm",
|
|
2958
2958
|
"--cornerbadge-text-font-weight": "--font-weight-medium",
|
|
2959
2959
|
"--cornerbadge-text-line-height": "--line-height-none",
|
|
2960
|
-
"--cornerbadge-brand-surface": "--surface-brand",
|
|
2960
|
+
"--cornerbadge-brand-surface": "--surface-brand-low",
|
|
2961
2961
|
"--cornerbadge-brand-border": "--border-brand",
|
|
2962
2962
|
"--cornerbadge-brand-text": "--text-brand",
|
|
2963
2963
|
"--cornerbadge-accent-surface": "--surface-accent",
|
|
@@ -2971,7 +2971,7 @@
|
|
|
2971
2971
|
"--cornerbadge-alternate-text": "--text-alternate",
|
|
2972
2972
|
"--cornerbadge-canvas-surface": "--surface-canvas",
|
|
2973
2973
|
"--cornerbadge-canvas-border": "--border-canvas",
|
|
2974
|
-
"--cornerbadge-canvas-text": "--text-
|
|
2974
|
+
"--cornerbadge-canvas-text": "--text-secondary",
|
|
2975
2975
|
"--cornerbadge-special-surface": "--surface-special",
|
|
2976
2976
|
"--cornerbadge-special-border": "--border-special",
|
|
2977
2977
|
"--cornerbadge-special-text": "--text-special",
|
|
@@ -2981,7 +2981,7 @@
|
|
|
2981
2981
|
"--cornerbadge-warning-surface": "--surface-warning",
|
|
2982
2982
|
"--cornerbadge-warning-border": "--border-warning",
|
|
2983
2983
|
"--cornerbadge-warning-text": "--text-warning",
|
|
2984
|
-
"--cornerbadge-danger-surface": "--surface-danger",
|
|
2984
|
+
"--cornerbadge-danger-surface": "--surface-danger-low",
|
|
2985
2985
|
"--cornerbadge-danger-border": "--border-danger",
|
|
2986
2986
|
"--cornerbadge-danger-text": "--text-danger",
|
|
2987
2987
|
"--cornerbadge-info-surface": "--surface-info",
|
|
@@ -3199,7 +3199,7 @@
|
|
|
3199
3199
|
"--input-border-width": "--border-width-1",
|
|
3200
3200
|
"--input-gap": "--space-8",
|
|
3201
3201
|
"--input-default-surface": "--surface-neutral-lower",
|
|
3202
|
-
"--input-default-border": "--border-neutral",
|
|
3202
|
+
"--input-default-border": "--border-neutral-medium",
|
|
3203
3203
|
"--input-default-text": "--text-primary",
|
|
3204
3204
|
"--input-default-text-font-family": "--font-sans",
|
|
3205
3205
|
"--input-default-text-font-size": "--font-size-sm",
|
|
@@ -3358,7 +3358,7 @@
|
|
|
3358
3358
|
"--notification-warning-text-font-size": "--font-size-md",
|
|
3359
3359
|
"--notification-warning-text-font-weight": "--font-weight-normal",
|
|
3360
3360
|
"--notification-warning-text-line-height": "--line-height-normal",
|
|
3361
|
-
"--notification-danger-surface": "--surface-danger",
|
|
3361
|
+
"--notification-danger-surface": "--surface-danger-low",
|
|
3362
3362
|
"--notification-danger-action-surface": "--surface-neutral-lowest",
|
|
3363
3363
|
"--notification-danger-border": "--border-danger",
|
|
3364
3364
|
"--notification-danger-border-width": "--border-width-1",
|
|
@@ -3442,7 +3442,7 @@
|
|
|
3442
3442
|
"createdAt": "2026-05-10T20:44:44.372Z",
|
|
3443
3443
|
"updatedAt": "2026-08-19T22:39:32.785Z",
|
|
3444
3444
|
"aliases": {
|
|
3445
|
-
"--radiobutton-default-dot-border-color": "--border-neutral",
|
|
3445
|
+
"--radiobutton-default-dot-border-color": "--border-neutral-medium",
|
|
3446
3446
|
"--radiobutton-default-dot-border-width": "--border-width-2",
|
|
3447
3447
|
"--radiobutton-default-dot-fill": "--text-secondary",
|
|
3448
3448
|
"--radiobutton-default-dot-size": "--dot-size-0",
|
|
@@ -3451,7 +3451,7 @@
|
|
|
3451
3451
|
"--radiobutton-default-label-font-size": "--font-size-md",
|
|
3452
3452
|
"--radiobutton-default-label-font-weight": "--font-weight-semibold",
|
|
3453
3453
|
"--radiobutton-default-label-line-height": "--line-height-none",
|
|
3454
|
-
"--radiobutton-hover-dot-border-color": "--border-neutral",
|
|
3454
|
+
"--radiobutton-hover-dot-border-color": "--border-neutral-medium",
|
|
3455
3455
|
"--radiobutton-hover-dot-border-width": "--border-width-2",
|
|
3456
3456
|
"--radiobutton-hover-dot-fill": "--text-secondary",
|
|
3457
3457
|
"--radiobutton-hover-dot-size": "--dot-size-50",
|
|
@@ -3460,7 +3460,7 @@
|
|
|
3460
3460
|
"--radiobutton-hover-label-font-size": "--font-size-md",
|
|
3461
3461
|
"--radiobutton-hover-label-font-weight": "--font-weight-semibold",
|
|
3462
3462
|
"--radiobutton-hover-label-line-height": "--line-height-none",
|
|
3463
|
-
"--radiobutton-selected-dot-border-color": "--border-neutral",
|
|
3463
|
+
"--radiobutton-selected-dot-border-color": "--border-neutral-medium",
|
|
3464
3464
|
"--radiobutton-selected-dot-border-width": "--border-width-2",
|
|
3465
3465
|
"--radiobutton-selected-dot-fill": "--text-secondary",
|
|
3466
3466
|
"--radiobutton-selected-dot-size": "--dot-size-50",
|
|
@@ -3569,7 +3569,7 @@
|
|
|
3569
3569
|
"--segmentedcontrol-hover-tint": "--tint",
|
|
3570
3570
|
"--segmentedcontrol-hover-tint-enabled": "--color-transparent",
|
|
3571
3571
|
"--segmentedcontrol-bar-surface": "color-mix(in srgb, var(--surface-neutral-lowest) 75%, transparent)",
|
|
3572
|
-
"--segmentedcontrol-bar-border": "--border-neutral",
|
|
3572
|
+
"--segmentedcontrol-bar-border": "--border-neutral-medium",
|
|
3573
3573
|
"--segmentedcontrol-bar-border-width": "--border-width-1",
|
|
3574
3574
|
"--segmentedcontrol-bar-radius": "--radius-2xl",
|
|
3575
3575
|
"--segmentedcontrol-bar-padding": "--space-8",
|
|
@@ -3600,7 +3600,7 @@
|
|
|
3600
3600
|
"--segmentedcontrol-selected-text-font-weight": "--font-weight-normal",
|
|
3601
3601
|
"--segmentedcontrol-selected-text-line-height": "--line-height-normal",
|
|
3602
3602
|
"--segmentedcontrol-selected-icon": "--text-secondary",
|
|
3603
|
-
"--segmentedcontrol-selected-border": "--border-brand",
|
|
3603
|
+
"--segmentedcontrol-selected-border": "--border-brand-medium",
|
|
3604
3604
|
"--segmentedcontrol-selected-border-width": "--border-width-1",
|
|
3605
3605
|
"--segmentedcontrol-selected-radius": "--radius-xl",
|
|
3606
3606
|
"--segmentedcontrol-disabled-surface": "--color-transparent",
|
|
@@ -3827,7 +3827,7 @@
|
|
|
3827
3827
|
"--tabbar-hover-tab-bottom-radius": "--radius-md",
|
|
3828
3828
|
"--tabbar-hover-indicator-width": "--border-width-2",
|
|
3829
3829
|
"--tabbar-selected-text": "--text-primary",
|
|
3830
|
-
"--tabbar-selected-border": "--
|
|
3830
|
+
"--tabbar-selected-border": "--border-brand-medium",
|
|
3831
3831
|
"--tabbar-selected-surface": "--tint-low",
|
|
3832
3832
|
"--tabbar-selected-text-font-family": "--font-sans",
|
|
3833
3833
|
"--tabbar-selected-text-font-size": "--font-size-md",
|
|
@@ -3897,7 +3897,7 @@
|
|
|
3897
3897
|
"updatedAt": "2026-08-19T22:39:32.785Z",
|
|
3898
3898
|
"aliases": {
|
|
3899
3899
|
"--toggle-track-surface": "--surface-neutral",
|
|
3900
|
-
"--toggle-track-border": "--border-neutral",
|
|
3900
|
+
"--toggle-track-border": "--border-neutral-medium",
|
|
3901
3901
|
"--toggle-track-border-width": "--border-width-1",
|
|
3902
3902
|
"--toggle-track-radius": "--radius-full",
|
|
3903
3903
|
"--toggle-track-padding": "--space-6",
|
|
@@ -3912,7 +3912,7 @@
|
|
|
3912
3912
|
"--toggle-hover-track-surface": "--surface-neutral-high",
|
|
3913
3913
|
"--toggle-hover-thumb-surface": "--text-primary",
|
|
3914
3914
|
"--toggle-on-track-surface": "--surface-brand-high",
|
|
3915
|
-
"--toggle-on-track-border": "--border-brand",
|
|
3915
|
+
"--toggle-on-track-border": "--border-brand-medium",
|
|
3916
3916
|
"--toggle-on-thumb-surface": "--text-primary",
|
|
3917
3917
|
"--toggle-on-thumb-border": "--border-brand-strong",
|
|
3918
3918
|
"--toggle-on-hover-track-surface": "--surface-brand-higher",
|
|
@@ -3948,13 +3948,13 @@
|
|
|
3948
3948
|
"updatedAt": "2026-09-02T10:55:50.831Z",
|
|
3949
3949
|
"aliases": {
|
|
3950
3950
|
"--slider-single-track-surface": "--surface-neutral-lowest",
|
|
3951
|
-
"--slider-single-track-border": "--border-neutral-
|
|
3951
|
+
"--slider-single-track-border": "--border-neutral-medium",
|
|
3952
3952
|
"--slider-single-track-border-width": "--border-width-1",
|
|
3953
3953
|
"--slider-single-track-height": "--space-8",
|
|
3954
3954
|
"--slider-single-track-radius": "--radius-full",
|
|
3955
3955
|
"--slider-single-fill": "--surface-brand-high",
|
|
3956
3956
|
"--slider-single-thumb-surface": "--surface-neutral-highest",
|
|
3957
|
-
"--slider-single-thumb-border": "--border-brand",
|
|
3957
|
+
"--slider-single-thumb-border": "--border-brand-medium",
|
|
3958
3958
|
"--slider-single-thumb-border-width": "--border-width-2",
|
|
3959
3959
|
"--slider-single-thumb-size": "--font-size-lg",
|
|
3960
3960
|
"--slider-single-thumb-radius": "--radius-full",
|
|
@@ -3966,13 +3966,13 @@
|
|
|
3966
3966
|
"--slider-single-disabled-thumb-surface": "--surface-neutral-lower",
|
|
3967
3967
|
"--slider-single-disabled-thumb-border": "--border-neutral",
|
|
3968
3968
|
"--slider-range-track-surface": "--surface-neutral-lowest",
|
|
3969
|
-
"--slider-range-track-border": "--border-neutral-
|
|
3969
|
+
"--slider-range-track-border": "--border-neutral-medium",
|
|
3970
3970
|
"--slider-range-track-border-width": "--border-width-1",
|
|
3971
3971
|
"--slider-range-track-height": "--space-8",
|
|
3972
3972
|
"--slider-range-track-radius": "--radius-full",
|
|
3973
3973
|
"--slider-range-fill": "--surface-brand-high",
|
|
3974
3974
|
"--slider-range-thumb-surface": "--surface-neutral-highest",
|
|
3975
|
-
"--slider-range-thumb-border": "--border-brand",
|
|
3975
|
+
"--slider-range-thumb-border": "--border-brand-medium",
|
|
3976
3976
|
"--slider-range-thumb-border-width": "--border-width-2",
|
|
3977
3977
|
"--slider-range-thumb-size": "--font-size-lg",
|
|
3978
3978
|
"--slider-range-thumb-radius": "--radius-full",
|