@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
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Svelte action: keep an absolutely-positioned element inside the viewport.
|
|
3
|
-
*
|
|
4
|
-
* Measures the element after layout, computes how far it overflows any
|
|
5
|
-
* viewport edge, and shifts it back via CSS `translate`. The original
|
|
6
|
-
* positioning (top/left/right/bottom) stays untouched so the *natural*
|
|
7
|
-
* placement is preserved when there's room — the action only nudges when
|
|
8
|
-
* the element would otherwise draw off-screen.
|
|
9
|
-
*
|
|
10
|
-
* Use on popovers and dropdowns whose trigger position is dynamic
|
|
11
|
-
* (cards in a wrapping flex grid, dropdowns near a panel edge, etc.).
|
|
12
|
-
*
|
|
13
|
-
* The CSS `translate` property is used instead of `transform` so it doesn't
|
|
14
|
-
* collide with `transform`-based entrance animations.
|
|
15
|
-
*
|
|
16
|
-
* Recomputes on:
|
|
17
|
-
* - mount (after first paint)
|
|
18
|
-
* - element resize (content reflow)
|
|
19
|
-
* - window resize
|
|
20
|
-
* - any scroll up the ancestor chain
|
|
21
|
-
*
|
|
22
|
-
* Usage:
|
|
23
|
-
* <div class="popover" use:keepInViewport>...</div>
|
|
24
|
-
* <div class="popover" use:keepInViewport={{ margin: 12 }}>...</div>
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
export type KeepInViewportOptions = {
|
|
28
|
-
/** Minimum gap (px) between the element and the viewport edges. Default 8. */
|
|
29
|
-
margin?: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export function keepInViewport(
|
|
33
|
-
node: HTMLElement,
|
|
34
|
-
options: KeepInViewportOptions = {},
|
|
35
|
-
) {
|
|
36
|
-
let margin = options.margin ?? 8;
|
|
37
|
-
let pendingFrame: number | null = null;
|
|
38
|
-
|
|
39
|
-
function measure(): void {
|
|
40
|
-
if (pendingFrame !== null) return;
|
|
41
|
-
pendingFrame = requestAnimationFrame(() => {
|
|
42
|
-
pendingFrame = null;
|
|
43
|
-
// Reset our own translate before measuring so the rect reflects the
|
|
44
|
-
// element's natural placement, not last frame's correction.
|
|
45
|
-
node.style.translate = '';
|
|
46
|
-
const rect = node.getBoundingClientRect();
|
|
47
|
-
const vw = window.innerWidth;
|
|
48
|
-
const vh = window.innerHeight;
|
|
49
|
-
let dx = 0;
|
|
50
|
-
let dy = 0;
|
|
51
|
-
if (rect.left < margin) dx = margin - rect.left;
|
|
52
|
-
else if (rect.right > vw - margin) dx = vw - margin - rect.right;
|
|
53
|
-
if (rect.top < margin) dy = margin - rect.top;
|
|
54
|
-
else if (rect.bottom > vh - margin) dy = vh - margin - rect.bottom;
|
|
55
|
-
if (dx !== 0 || dy !== 0) {
|
|
56
|
-
node.style.translate = `${dx}px ${dy}px`;
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
measure();
|
|
62
|
-
|
|
63
|
-
const ro = new ResizeObserver(measure);
|
|
64
|
-
ro.observe(node);
|
|
65
|
-
window.addEventListener('resize', measure);
|
|
66
|
-
// Capture-phase scroll listener: catches scroll on any ancestor, not just
|
|
67
|
-
// window. The trigger's nearest scrolling parent (a panel, a modal body)
|
|
68
|
-
// shifts the popover's viewport position when scrolled.
|
|
69
|
-
window.addEventListener('scroll', measure, true);
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
update(next: KeepInViewportOptions = {}) {
|
|
73
|
-
margin = next.margin ?? 8;
|
|
74
|
-
measure();
|
|
75
|
-
},
|
|
76
|
-
destroy() {
|
|
77
|
-
if (pendingFrame !== null) cancelAnimationFrame(pendingFrame);
|
|
78
|
-
ro.disconnect();
|
|
79
|
-
window.removeEventListener('resize', measure);
|
|
80
|
-
window.removeEventListener('scroll', measure, true);
|
|
81
|
-
node.style.translate = '';
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../testing/componentContract.ts"],"sourcesContent":["export type ContractRule =\n | 'contract-listed'\n | 'contract-render'\n | 'contract-alias'\n | 'contract-persist'\n | 'contract-theme'\n | 'contract-states'\n | 'contract-interaction'\n | 'contract-behavior'\n | 'contract-sketch'\n | 'contract-missing';\n\n/**\n * A failed obligation, carrying the rule id the CLI reports it under. A defect\n * fixture names the rule it expects, and `check-component --tests` maps a\n * reporter error onto a finding.\n */\nexport class ContractViolation extends Error {\n constructor(\n readonly rule: ContractRule,\n readonly component: string,\n message: string,\n ) {\n super(`[${rule}] ${component}: ${message}`);\n this.name = 'ContractViolation';\n }\n}\n\nexport interface Inapplicable {\n applicable: false;\n reason: string;\n}\n\nexport function isInapplicable(value: unknown): value is Inapplicable {\n return typeof value === 'object' && value !== null && (value as Inapplicable).applicable === false;\n}\n\nexport interface PartLocator {\n /** Resolved inside the preview stage unless `portal` is set. */\n selector: string;\n /** Read computed style from this pseudo-element of the part, e.g.\n * `'::after'`. Chromium's `getComputedStyle` only tolerates the bare form\n * (`'after'`) for `::before`/`::after`; use the full `::` syntax so a\n * future pseudo-element (`::placeholder`, `::marker`, ...) works the same\n * way without a silent fallback to the host element's own style. */\n pseudo?: string;\n /** Rendered outside the preview stage. Resolved against the document. */\n portal?: boolean;\n}\n\nexport type PartDeclaration = string | PartLocator;\n\n/**\n * An editor control the preview is gated behind: a canvas-toolbar checkbox, an\n * optional-content switch. `check` sets a checkbox to a state and is safe to\n * repeat; `value` picks a select option; neither clicks once.\n */\nexport interface ControlStep {\n kind: 'control';\n /** Selector inside the visible variant group. */\n selector: string;\n check?: boolean;\n value?: string;\n}\n\nexport type SetupStep = InteractionAction | ControlStep;\n\n/** Which VariantGroup, which state tab, and what has to happen first. */\nexport interface View {\n /** Variant tab label. Omitted when the editor renders one variant. */\n variant?: string;\n /** State tab label. Omitted when the editor renders no state strip. */\n state?: string;\n /** Run after the tabs are selected. Portaled and toolbar-gated parts exist\n * only once these have run. */\n setup?: SetupStep[];\n}\n\n/** Part key -> CSS property -> the design token that must drive it. */\nexport type PaintMap = Record<string, Record<string, string>>;\n\nexport interface PropertyExpectation extends View {\n paints: PaintMap;\n}\n\nexport interface StateExpectation extends View {\n state: string;\n /** Class the root part carries while the editor previews this state. */\n forceClass?: string;\n /** Part key -> attributes it must carry. A null value requires the absence. */\n attributes?: Record<string, Record<string, string | null>>;\n /** What the state repaints, as computed-value equality against its token. */\n paints?: PaintMap;\n}\n\n/**\n * `token` and `opacity` drive the token selector for `variable`. `gradient`\n * drives the gradient editor for `variable`. `literal` drives `control` and\n * reads `variable` back off the root, which is where an intrinsic lands: the\n * editors write those into the alias bucket. `config` drives `control` and\n * reads `configKey` out of the config bucket, which holds editor metadata that\n * never reaches `:root`.\n */\nexport type PersistenceShape = 'token' | 'literal' | 'opacity' | 'gradient' | 'config';\n\nexport interface PersistenceCase extends View {\n shape: PersistenceShape;\n /** The alias the value is read back from. Omitted for `config`. */\n variable?: string;\n /** Selector inside the visible variant group, for `literal` and `config`. */\n control?: string;\n /** The config-bucket key, for `config`. */\n configKey?: string;\n /** Where the persisted value must land once the page has reloaded. */\n observe: { part: string; css: string };\n}\n\nexport interface PersistenceExpectation {\n cases: PersistenceCase[];\n /** The alias Reset must return to the value the server holds for it. It has\n * to be one a case above moves, so the saved value and the value the\n * component booted with are different and Reset can be seen to choose. */\n resetVariable: string;\n}\n\nexport interface ThemeExpectation extends View {\n /** Theme slug shown in the Theme Picker, e.g. `ocean`. */\n theme: string;\n /** Variables whose root value the theme must move. */\n changed: string[];\n /**\n * Variables the theme must leave exactly as they were. Two theme JSON files\n * can name the identical design token (e.g. both `--border-neutral`) and\n * still resolve to different rendered colors, because many color primitives\n * are computed per theme from a palette/seed even when the alias string is\n * unchanged — comparing the two files' alias *names* does not establish\n * invariance. Pick `unchanged` candidates from token families a theme never\n * recolors: `--shadow-*`, `--icon-size-*`, `--font-size-*`,\n * `--line-height-*`, `--font-family`/`--font-mono`, and the spacing/radius/\n * border-width scale steps (`--space-*`, `--radius-*`, `--border-width-*`)\n * are all fixed constants, not palette-derived — verify a candidate's\n * *resolved* value is identical between the two theme files before trusting\n * it, not just that the alias name matches.\n */\n unchanged: string[];\n /** Variables the theme's own component config aliases, and the design token\n * each must resolve to under it. */\n aliasedTo: Record<string, string>;\n /** Where the theme's value must land in the rendered preview. */\n observe: { part: string; css: string; variable: string };\n}\n\nexport type InteractionAction =\n | { kind: 'press'; part: string; key: string }\n | { kind: 'click'; part: string }\n | { kind: 'type'; part: string; text: string }\n | { kind: 'dragTo'; part: string; along: string; fraction: number };\n\nexport type InteractionOutcome =\n | { kind: 'attribute'; part: string; name: string; value: string }\n | { kind: 'valueMoves'; part: string; direction: 'up' | 'down' }\n | { kind: 'valueBecomes'; part: string; value: string }\n | { kind: 'valueChanges'; part: string }\n | { kind: 'valueHolds'; part: string }\n /** Whether the part takes focus. The only outcome a button with no state\n * attribute has: a disabled one refuses it and an enabled one takes it. */\n | { kind: 'focused'; part: string; value: boolean };\n\nexport interface InteractionCase extends View {\n name: string;\n action: InteractionAction;\n expect: InteractionOutcome;\n}\n\nexport interface InteractionExpectation {\n /** The part carrying the interactive role. */\n part: string;\n role: string;\n cases: InteractionCase[];\n}\n\n/**\n * One mounted case under happy-dom: props in, a DOM event, one assertion. It\n * carries what a browser cannot reach, the callback a controlled component\n * calls instead of moving its own state.\n */\nexport interface BehaviorCase {\n name: string;\n /** Props the fixture mounts with. A snippet-valued prop is not\n * expressible; a component whose behavior needs one records that case\n * as inapplicable with the reason. */\n props?: Record<string, unknown>;\n action?: { kind: 'click' | 'keydown' | 'input'; part: string; key?: string; value?: string };\n expect:\n | { kind: 'callback'; prop: string; args: unknown[] }\n | { kind: 'no-callback'; prop: string }\n | { kind: 'attribute'; part: string; name: string; value: string | null }\n | { kind: 'text'; part: string; value: string };\n}\n\nexport interface BehaviorExpectation {\n cases: BehaviorCase[];\n}\n\nexport interface SketchPartExpectation {\n part: string;\n /** The design token `--sketch-fill` must resolve to on this part. */\n fill?: string;\n /** The design token `--sketch-stroke` must resolve to on this part. */\n stroke?: string;\n}\n\nexport interface SketchExpectation extends View {\n /** Sketchstyle id the paint is asserted under. */\n style: string;\n parts: SketchPartExpectation[];\n}\n\nexport interface ComponentContract {\n id: string;\n origin: 'system' | 'custom';\n parts: Record<string, PartDeclaration>;\n /** Part key of the component's own root element in the preview. */\n root: string;\n /** The view every obligation opens with. */\n view?: View;\n states: StateExpectation[] | Inapplicable;\n properties: PropertyExpectation[];\n /**\n * Aliases no paint map can pin, each with the reason. A token consumed\n * inside `calc()` or handed to a gradient function never appears verbatim in\n * a computed style, so the probe cannot read it back — that is the only\n * class this belongs to. A token a sibling alias merely happens to carry\n * the same rendered value through (a base padding token behind four\n * per-side overrides, say) is not in this class: the per-side entries pin\n * their own aliases, not the base one, and a paint map that drives the base\n * token directly and observes the per-side CSS property can pin it too. Put\n * that here and Wave 4's coverage JSON records the base token as covered\n * when nothing asserts the link between it and what actually painted.\n */\n uncovered?: Record<string, string>;\n persistence: PersistenceExpectation;\n theme: ThemeExpectation;\n interaction: InteractionExpectation | Inapplicable;\n /** What the component does when it is driven, proven under happy-dom. */\n behavior: BehaviorExpectation | Inapplicable;\n sketch: SketchExpectation | Inapplicable;\n}\n\n/** Roles whose components must declare interaction cases. */\nconst INTERACTIVE_ROLES = new Set([\n 'button', 'switch', 'checkbox', 'radio', 'slider', 'spinbutton', 'textbox',\n 'combobox', 'listbox', 'menuitem', 'tab', 'link', 'searchbox', 'option',\n]);\n\nexport function requiresInteraction(role: string | null): boolean {\n return role !== null && INTERACTIVE_ROLES.has(role);\n}\n\nexport function partLocator(contract: ComponentContract, key: string): PartLocator {\n const declared = contract.parts[key];\n if (declared === undefined) {\n throw new ContractViolation('contract-render', contract.id, `no part named \"${key}\" is declared`);\n }\n return typeof declared === 'string' ? { selector: declared } : declared;\n}\n"],"mappings":";AAiBO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAC3C,YACW,MACA,WACT,SACA;AACA,UAAM,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,EAAE;AAJjC;AACA;AAIT,SAAK,OAAO;AAAA,EACd;AAAA,EANW;AAAA,EACA;AAMb;AAOO,SAAS,eAAe,OAAuC;AACpE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAS,MAAuB,eAAe;AAC/F;AAuNA,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EAAU;AAAA,EAAU;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAAA,EAAc;AAAA,EACjE;AAAA,EAAY;AAAA,EAAW;AAAA,EAAY;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAa;AACjE,CAAC;AAEM,SAAS,oBAAoB,MAA8B;AAChE,SAAO,SAAS,QAAQ,kBAAkB,IAAI,IAAI;AACpD;AAEO,SAAS,YAAY,UAA6B,KAA0B;AACjF,QAAM,WAAW,SAAS,MAAM,GAAG;AACnC,MAAI,aAAa,QAAW;AAC1B,UAAM,IAAI,kBAAkB,mBAAmB,SAAS,IAAI,kBAAkB,GAAG,eAAe;AAAA,EAClG;AACA,SAAO,OAAO,aAAa,WAAW,EAAE,UAAU,SAAS,IAAI;AACjE;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../testing/config.ts","../editor/core/routing/ownedRoutes.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { DEFAULT_COMPONENTS_PATH } from '../editor/core/routing/ownedRoutes';\n\n/** The file a project puts its shared test settings in, at the project root. */\nexport const TESTING_CONFIG_FILE = 'live-tokens.testing.ts';\n\n/** The components route the run drives, published from the settings so the\n * suites need no argument. */\nexport const COMPONENTS_PATH_ENV = 'LIVE_TOKENS_COMPONENTS_PATH';\n\n/** Narrows a run to one component. */\nexport const COMPONENT_ENV = 'LIVE_TOKENS_COMPONENT';\n\n/** The page targets a run opens, as JSON: `[{ source, route }]`. */\nexport const PAGES_ENV = 'LIVE_TOKENS_PAGES';\n\n/** The viewports every page rule runs at, as JSON: `[{ width, height }]`. */\nexport const PAGE_VIEWPORTS_ENV = 'LIVE_TOKENS_PAGE_VIEWPORTS';\n\nexport interface PageViewport {\n width: number;\n height: number;\n}\n\n/** The contract project's own desktop size, and the phone the text styles\n * carry media overrides for. Nothing here is derived from a page. */\nexport const DEFAULT_PAGE_VIEWPORTS: PageViewport[] = [\n { width: 1280, height: 900 },\n { width: 390, height: 844 },\n];\n\n/** What `resolveDataDirs` falls back to, restated because that resolver is\n * plugin-side and the tarball ships the plugin built rather than as source.\n * `vite-plugin/testingConfig.test.ts` pins the two together. */\nconst DEFAULT_DATA_DIR = 'src/live-tokens/data';\n\nconst DEFAULT_DEV_COMMAND = 'npm run dev -- --host {host} --port {port}';\n\nexport interface LiveTokensTestingConfig {\n /** Vite config a generated Vitest config merges. Default `vite.config.ts`. */\n viteConfig?: string;\n /** Command that starts the dev server. `{host}` and `{port}` are substituted.\n * Default `npm run dev -- --host {host} --port {port}`. */\n devCommand?: string;\n /** Fixed port for the dev server. Omitted, the run takes a free one. */\n port?: number;\n /** The components route, when `editorRoutes` moved it off the owned default. */\n componentsPath?: string;\n /** The plugin's data directory. Default: `dataDir` from\n * `live-tokens.config.json`, else `src/live-tokens/data`. The run never uses\n * it directly; it is the tree the isolated copy is made from. */\n dataDir?: string;\n /** Module that registers the project's components without mounting the app.\n * The registry contract imports it before it selects entries. */\n registrySetup?: string;\n /** Module exporting the `ComponentContract[]` a custom component adds to the\n * shipped list (default export or a named `contracts` export). The suite\n * files are static Playwright entry points, so an env var naming this path\n * plus a dynamic import inside `selectedContracts()` is the only way a\n * custom contract reaches them. */\n contractsModule?: string;\n /** Page source path to the concrete URL that renders it, for a route the\n * `pages` object cannot express: one served by `resolve()`, or one whose\n * parameters only the project knows. Page paths are relative to the\n * project root. */\n pageRoutes?: Record<string, string>;\n /** Replaces the two sizes every page rule runs at. */\n pageViewports?: PageViewport[];\n}\n\nexport interface ResolvedTestingConfig {\n root: string;\n viteConfig: string;\n devCommand: string;\n port?: number;\n componentsPath: string;\n dataDir: string;\n registrySetup?: string;\n contractsModule?: string;\n pageRoutes: Record<string, string>;\n pageViewports: PageViewport[];\n}\n\n/** Types the settings file without importing the interface by hand. */\nexport function defineTestingConfig(config: LiveTokensTestingConfig): LiveTokensTestingConfig {\n return config;\n}\n\n/** `dataDir` as the plugin resolves it, from the same file the plugin reads. */\nfunction configuredDataDir(root: string): string {\n try {\n const parsed = JSON.parse(fs.readFileSync(path.join(root, 'live-tokens.config.json'), 'utf-8'));\n if (parsed && typeof parsed === 'object' && typeof parsed.dataDir === 'string') {\n return path.resolve(root, parsed.dataDir);\n }\n } catch {\n // Missing or unparseable reads as absent, matching `readLiveTokensConfig`.\n }\n return path.resolve(root, DEFAULT_DATA_DIR);\n}\n\nexport function resolveTestingConfig(\n config: LiveTokensTestingConfig = {},\n root: string = process.cwd(),\n): ResolvedTestingConfig {\n const projectRoot = path.resolve(root);\n return {\n root: projectRoot,\n viteConfig: path.resolve(projectRoot, config.viteConfig ?? 'vite.config.ts'),\n devCommand: config.devCommand ?? DEFAULT_DEV_COMMAND,\n port: config.port,\n componentsPath: config.componentsPath ?? DEFAULT_COMPONENTS_PATH,\n dataDir: config.dataDir ? path.resolve(projectRoot, config.dataDir) : configuredDataDir(projectRoot),\n registrySetup: config.registrySetup\n ? path.resolve(projectRoot, config.registrySetup)\n : undefined,\n contractsModule: config.contractsModule\n ? path.resolve(projectRoot, config.contractsModule)\n : undefined,\n pageRoutes: config.pageRoutes ?? {},\n pageViewports: config.pageViewports?.length ? config.pageViewports : DEFAULT_PAGE_VIEWPORTS,\n };\n}\n\nexport function devServerCommand(command: string, host: string, port: number): string {\n return command.replaceAll('{host}', host).replaceAll('{port}', String(port));\n}\n","// The package's dev-only editor surfaces live under a reserved `/live-tokens/*`\n// namespace so they can never collide with a consumer's own routes — the\n// consumer owns the rest of the URL space. Keeping the defaults in one place\n// is the guard against the nav rail and the dispatcher drifting onto different\n// paths (the collision/shadow class these constants exist to prevent).\n//\n// A consumer relocates or disables each surface via the `editorRoutes` prop on\n// <LiveTokensRouter>; these are only the defaults.\nexport const DEFAULT_EDITOR_PATH = '/live-tokens/editor';\nexport const DEFAULT_COMPONENTS_PATH = '/live-tokens/components';\nexport const DEFAULT_COLORS_PATH = '/live-tokens/colors';\nexport const DEFAULT_DOCS_PATH = '/live-tokens/docs';\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;;;ACQV,IAAM,0BAA0B;;;ADJhC,IAAM,sBAAsB;AAI5B,IAAM,sBAAsB;AAG5B,IAAM,gBAAgB;AAGtB,IAAM,YAAY;AAGlB,IAAM,qBAAqB;AAS3B,IAAM,yBAAyC;AAAA,EACpD,EAAE,OAAO,MAAM,QAAQ,IAAI;AAAA,EAC3B,EAAE,OAAO,KAAK,QAAQ,IAAI;AAC5B;AAKA,IAAM,mBAAmB;AAEzB,IAAM,sBAAsB;AAgDrB,SAAS,oBAAoB,QAA0D;AAC5F,SAAO;AACT;AAGA,SAAS,kBAAkB,MAAsB;AAC/C,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,MAAM,yBAAyB,GAAG,OAAO,CAAC;AAC9F,QAAI,UAAU,OAAO,WAAW,YAAY,OAAO,OAAO,YAAY,UAAU;AAC9E,aAAO,KAAK,QAAQ,MAAM,OAAO,OAAO;AAAA,IAC1C;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,KAAK,QAAQ,MAAM,gBAAgB;AAC5C;AAEO,SAAS,qBACd,SAAkC,CAAC,GACnC,OAAe,QAAQ,IAAI,GACJ;AACvB,QAAM,cAAc,KAAK,QAAQ,IAAI;AACrC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY,KAAK,QAAQ,aAAa,OAAO,cAAc,gBAAgB;AAAA,IAC3E,YAAY,OAAO,cAAc;AAAA,IACjC,MAAM,OAAO;AAAA,IACb,gBAAgB,OAAO,kBAAkB;AAAA,IACzC,SAAS,OAAO,UAAU,KAAK,QAAQ,aAAa,OAAO,OAAO,IAAI,kBAAkB,WAAW;AAAA,IACnG,eAAe,OAAO,gBAClB,KAAK,QAAQ,aAAa,OAAO,aAAa,IAC9C;AAAA,IACJ,iBAAiB,OAAO,kBACpB,KAAK,QAAQ,aAAa,OAAO,eAAe,IAChD;AAAA,IACJ,YAAY,OAAO,cAAc,CAAC;AAAA,IAClC,eAAe,OAAO,eAAe,SAAS,OAAO,gBAAgB;AAAA,EACvE;AACF;AAEO,SAAS,iBAAiB,SAAiB,MAAc,MAAsB;AACpF,SAAO,QAAQ,WAAW,UAAU,IAAI,EAAE,WAAW,UAAU,OAAO,IAAI,CAAC;AAC7E;","names":[]}
|