@weasel-js/labkit 1.2.0 → 1.3.0-pre.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_dts/{DrawCommand-C_XboUpz.d.ts → DrawCommand-DBB45NfN.d.ts} +196 -52
- package/dist/_dts/PrefsForm-BYa6cWnO.d.ts +201 -0
- package/dist/_dts/index-DgcNdEdh.d.ts +314 -0
- package/dist/_dts/types-1Sdxy_Pv.d.ts +90 -0
- package/dist/_dts/types-AHlQxBNN.d.ts +162 -0
- package/dist/_dts/{useTrialState-BMNIx3Cy.d.ts → useTrialState-CsGMjhu9.d.ts} +5 -87
- package/dist/canvas/index.d.ts +7 -3
- package/dist/canvas/index.js +2 -1
- package/dist/chrome/index.d.ts +86 -0
- package/dist/chrome/index.js +8 -0
- package/dist/chrome/index.js.map +1 -0
- package/dist/{chunk-VUU5UXHE.js → chunk-4TMMVIDM.js} +8 -5
- package/dist/chunk-4TMMVIDM.js.map +1 -0
- package/dist/{chunk-THBG7FQZ.js → chunk-HFDVGF4X.js} +15 -12
- package/dist/chunk-HFDVGF4X.js.map +1 -0
- package/dist/{chunk-574LJAV4.js → chunk-NS54R52R.js} +31 -21
- package/dist/chunk-NS54R52R.js.map +1 -0
- package/dist/{chunk-G5TJVQQT.js → chunk-O2BULFHX.js} +5 -14
- package/dist/chunk-O2BULFHX.js.map +1 -0
- package/dist/chunk-O7NVSCLN.js +266 -0
- package/dist/chunk-O7NVSCLN.js.map +1 -0
- package/dist/chunk-PO6L3NSH.js +366 -0
- package/dist/chunk-PO6L3NSH.js.map +1 -0
- package/dist/chunk-PQJ5B2U2.js +27 -0
- package/dist/chunk-PQJ5B2U2.js.map +1 -0
- package/dist/chunk-RVNN4CHQ.js +212 -0
- package/dist/chunk-RVNN4CHQ.js.map +1 -0
- package/dist/chunk-TLGRYALP.js +6151 -0
- package/dist/chunk-TLGRYALP.js.map +1 -0
- package/dist/{chunk-SFL7NFKN.js → chunk-V7PRSIRQ.js} +15 -7
- package/dist/chunk-V7PRSIRQ.js.map +1 -0
- package/dist/{chunk-BOHF3PQO.js → chunk-Z6HJ5FEM.js} +8111 -5190
- package/dist/chunk-Z6HJ5FEM.js.map +1 -0
- package/dist/chunk-ZZAYVX4X.js +505 -0
- package/dist/chunk-ZZAYVX4X.js.map +1 -0
- package/dist/controls/index.d.ts +19 -5
- package/dist/controls/index.js +3 -1
- package/dist/dragdrop/index.d.ts +4 -2
- package/dist/index.d.ts +246 -106
- package/dist/index.js +673 -559
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +5 -3
- package/dist/layers/index.js +2 -1
- package/dist/passthrough/weasel-canvas.d.ts +69 -13
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +3799 -3672
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/primitives/index.d.ts +102 -8
- package/dist/primitives/index.js +4 -1
- package/dist/state/index.d.ts +3 -2
- package/dist/state/index.js +2 -2
- package/dist/styles.css +542 -153
- package/dist/surface/index.js +2 -1
- package/dist/ui/layers/index.js +4 -3
- package/dist/undo/index.d.ts +4 -2
- package/package.json +16 -7
- package/src/canvas/AGENTS.md +4 -0
- package/src/canvas/CanvasStack.tsx +6 -2
- package/src/canvas/useLayerScheduler.ts +22 -15
- package/src/canvas/usePanZoom.test.ts +80 -0
- package/src/canvas/usePanZoom.ts +16 -2
- package/src/chrome/ChromeRegions.stories.tsx +106 -0
- package/src/chrome/builtins.test.ts +153 -0
- package/src/chrome/builtins.tsx +205 -0
- package/src/chrome/index.ts +25 -0
- package/src/chrome/merge.test.ts +51 -0
- package/src/chrome/merge.ts +52 -0
- package/src/chrome/regions/PaletteRegion.less +14 -0
- package/src/chrome/regions/PaletteRegion.test.tsx +36 -0
- package/src/chrome/regions/PaletteRegion.tsx +41 -0
- package/src/chrome/regions/SidebarRegion.tsx +56 -0
- package/src/chrome/regions/StatusRegion.tsx +31 -0
- package/src/chrome/regions/TitleBarRegion.tsx +41 -0
- package/src/chrome/regions/ToolbarRegion.test.tsx +82 -0
- package/src/chrome/regions/ToolbarRegion.tsx +71 -0
- package/src/chrome/regions/ViewportRegion.less +42 -0
- package/src/chrome/regions/ViewportRegion.tsx +37 -0
- package/src/chrome/regions/regions.test.tsx +81 -0
- package/src/chrome/types.ts +127 -0
- package/src/config/builder.test.ts +87 -0
- package/src/config/builder.ts +224 -0
- package/src/config/fromConfigField.test.ts +93 -0
- package/src/config/fromConfigField.ts +74 -0
- package/src/config/index.ts +22 -0
- package/src/config/resolve.test.ts +120 -0
- package/src/config/resolve.ts +67 -0
- package/src/config/rules.ts +68 -0
- package/src/config/types.ts +108 -0
- package/src/config/useConfigSchema.ts +30 -0
- package/src/config/visible.ts +20 -0
- package/src/controls/ControlPanel.less +4 -58
- package/src/controls/ControlPanel.stories.tsx +86 -0
- package/src/controls/ControlPanel.test.tsx +223 -10
- package/src/controls/ControlPanel.tsx +202 -203
- package/src/dragdrop/DragDropRuntime.tsx +36 -18
- package/src/dragdrop/DragGhost.less +1 -1
- package/src/dragdrop/Palette.less +1 -1
- package/src/index.ts +25 -3
- package/src/instrument/SineWave.smoke.test.tsx +8 -1
- package/src/instrument/defineInstrument.test.ts +38 -1
- package/src/instrument/defineInstrument.ts +31 -4
- package/src/instrument/index.ts +1 -0
- package/src/instrument/types.ts +27 -4
- package/src/instrument/validateConfigSchema.test.ts +13 -3
- package/src/instrument/validateConfigSchema.ts +7 -10
- package/src/lab/Lab.chrome.test.tsx +65 -0
- package/src/lab/Lab.tsx +58 -15
- package/src/lab/LabContext.ts +6 -0
- package/src/lab/LabFullChrome.stories.tsx +308 -0
- package/src/lab/LabHeader.test.tsx +42 -0
- package/src/lab/LabHeader.tsx +57 -0
- package/src/lab/LabPalette.test.tsx +35 -0
- package/src/lab/LabPalette.tsx +34 -0
- package/src/lab/LabShell.less +50 -3
- package/src/lab/Workspace.less +1 -30
- package/src/lab/Workspace.test.tsx +20 -10
- package/src/lab/Workspace.tsx +5 -8
- package/src/lab/index.ts +2 -0
- package/src/layers/AGENTS.md +1 -1
- package/src/layers/LayerList.less +31 -7
- package/src/layers/LayerList.tsx +17 -4
- package/src/passthrough/weasel-ui.ts +23 -0
- package/src/primitives/DragHandleGlyph.tsx +29 -0
- package/src/primitives/FloatingPanel.less +28 -0
- package/src/primitives/FloatingPanel.stories.tsx +46 -0
- package/src/primitives/FloatingPanel.test.tsx +240 -0
- package/src/primitives/FloatingPanel.tsx +190 -0
- package/src/primitives/FpsMeter.test.tsx +44 -0
- package/src/primitives/FpsMeter.tsx +20 -9
- package/src/primitives/JobProgress.less +69 -0
- package/src/primitives/JobProgress.stories.tsx +48 -0
- package/src/primitives/JobProgress.tsx +65 -0
- package/src/primitives/Legend.less +47 -0
- package/src/primitives/Legend.stories.tsx +32 -0
- package/src/primitives/Legend.test.tsx +57 -0
- package/src/primitives/Legend.tsx +40 -0
- package/src/primitives/Sidebar.less +32 -2
- package/src/primitives/StatusBar.less +7 -0
- package/src/primitives/StatusBar.tsx +10 -3
- package/src/primitives/Toolbar.less +50 -3
- package/src/primitives/Toolbar.test.tsx +67 -1
- package/src/primitives/Toolbar.tsx +72 -6
- package/src/primitives/ZoomControl.less +31 -0
- package/src/primitives/ZoomControl.tsx +76 -0
- package/src/primitives/floating.entry.test.tsx +14 -0
- package/src/primitives/index.ts +10 -2
- package/src/primitives/useRovingTabIndex.test.ts +27 -0
- package/src/primitives/useRovingTabIndex.ts +79 -0
- package/src/state/store.ts +11 -3
- package/src/state/toolSlot.test.ts +36 -0
- package/src/state/types.ts +4 -0
- package/src/styles.less +6 -0
- package/src/surface/useTiledSurface.ts +14 -10
- package/src/test-setup.ts +26 -0
- package/src/theme/base.less +19 -2
- package/src/theme/interstellar.tokens.json +6 -2
- package/src/tools/types.ts +24 -0
- package/src/trial/Trial.config.test.tsx +113 -0
- package/src/trial/Trial.job.test.tsx +13 -15
- package/src/trial/Trial.less +115 -10
- package/src/trial/Trial.stories.tsx +1 -0
- package/src/trial/Trial.test.tsx +67 -96
- package/src/trial/Trial.tsx +80 -39
- package/src/trial/TrialChrome.tsx +99 -80
- package/src/trial/TrialDragContext.ts +10 -0
- package/src/trial/TrialTitleBar.tsx +41 -0
- package/src/trial/index.ts +1 -15
- package/src/trial/trialChrome.borders.test.ts +38 -0
- package/src/ui/layers/LayerStack.less +9 -9
- package/src/ui/layers/LayerStack.tsx +1 -13
- package/src/ui/properties/CurveField.less +2 -2
- package/src/ui/properties/CurveField.test.tsx +11 -11
- package/src/ui/properties/PropertyGroup.less +2 -2
- package/src/ui/properties/PropertyPanel.less +55 -41
- package/src/ui/properties/SpeechBalloonPanels.stories.tsx +4 -2
- package/src/ui/properties/storyLayouts.tsx +2 -2
- package/dist/_dts/index-JFAYj5Tv.d.ts +0 -144
- package/dist/_dts/types-x92Kfeme.d.ts +0 -62
- package/dist/chunk-574LJAV4.js.map +0 -1
- package/dist/chunk-5R2ATYPJ.js +0 -201
- package/dist/chunk-5R2ATYPJ.js.map +0 -1
- package/dist/chunk-73KA7WBO.js +0 -5992
- package/dist/chunk-73KA7WBO.js.map +0 -1
- package/dist/chunk-BOHF3PQO.js.map +0 -1
- package/dist/chunk-G5TJVQQT.js.map +0 -1
- package/dist/chunk-PMAU3SEE.js +0 -126
- package/dist/chunk-PMAU3SEE.js.map +0 -1
- package/dist/chunk-SFL7NFKN.js.map +0 -1
- package/dist/chunk-THBG7FQZ.js.map +0 -1
- package/dist/chunk-VUU5UXHE.js.map +0 -1
- package/src/instrument/capabilityDetector.test.ts +0 -64
- package/src/instrument/capabilityDetector.ts +0 -20
- package/src/trial/DefaultSidebar.tsx +0 -29
- package/src/trial/DefaultStatusBar.tsx +0 -19
- package/src/trial/DefaultToolbar.tsx +0 -92
- package/src/trial/slotTypes.ts +0 -54
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { NodeId } from 'windease';
|
|
3
|
+
|
|
4
|
+
/** Supplied by `<Workspace>` when trials are reorderable, so a trial's title
|
|
5
|
+
* bar can be the drag surface. Null when reordering is off. */
|
|
6
|
+
export const TrialDragContext = createContext<{ nodeId: NodeId } | null>(null);
|
|
7
|
+
|
|
8
|
+
export function useTrialDrag(): { nodeId: NodeId } | null {
|
|
9
|
+
return useContext(TrialDragContext);
|
|
10
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { NodeId } from 'windease';
|
|
3
|
+
import { useDragHandle } from 'windease/react';
|
|
4
|
+
import { useTrialDrag } from './TrialDragContext';
|
|
5
|
+
|
|
6
|
+
/** Props for `<TrialTitleBar>`. */
|
|
7
|
+
export interface TrialTitleBarProps {
|
|
8
|
+
title: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// `useDragHandle` needs a node id and windease's DragProvider, so the draggable
|
|
13
|
+
// form is a separate component rather than a conditional hook.
|
|
14
|
+
function Draggable({ nodeId, title, children }: TrialTitleBarProps & { nodeId: NodeId }) {
|
|
15
|
+
const handlers = useDragHandle(nodeId);
|
|
16
|
+
return (
|
|
17
|
+
<div className="lk-trial__titlebar lk-trial__titlebar--draggable" {...handlers}>
|
|
18
|
+
<span className="lk-trial__title">{title}</span>
|
|
19
|
+
{children}
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** A trial's title bar. When the workspace allows reordering the whole bar is
|
|
25
|
+
* the drag surface — there is no separate grip, because a window's title bar
|
|
26
|
+
* is already the thing you expect to drag. */
|
|
27
|
+
export function TrialTitleBar({ title, children }: TrialTitleBarProps) {
|
|
28
|
+
const drag = useTrialDrag();
|
|
29
|
+
if (drag)
|
|
30
|
+
return (
|
|
31
|
+
<Draggable nodeId={drag.nodeId} title={title}>
|
|
32
|
+
{children}
|
|
33
|
+
</Draggable>
|
|
34
|
+
);
|
|
35
|
+
return (
|
|
36
|
+
<div className="lk-trial__titlebar">
|
|
37
|
+
<span className="lk-trial__title">{title}</span>
|
|
38
|
+
{children}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
package/src/trial/index.ts
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
export type { DefaultSidebarProps } from './DefaultSidebar';
|
|
2
|
-
export { DefaultSidebar } from './DefaultSidebar';
|
|
3
|
-
export type { DefaultStatusBarProps } from './DefaultStatusBar';
|
|
4
|
-
export { DefaultStatusBar } from './DefaultStatusBar';
|
|
5
|
-
export type { DefaultToolbarProps } from './DefaultToolbar';
|
|
6
|
-
export { DefaultToolbar } from './DefaultToolbar';
|
|
7
|
-
export type {
|
|
8
|
-
SidebarSlot,
|
|
9
|
-
StatusBarSlot,
|
|
10
|
-
ToolbarSlot,
|
|
11
|
-
TrialSidebarContext,
|
|
12
|
-
TrialStatusBarContext,
|
|
13
|
-
TrialToolbarContext,
|
|
14
|
-
} from './slotTypes';
|
|
15
1
|
export type { TrialProps } from './Trial';
|
|
16
2
|
export { Trial } from './Trial';
|
|
17
|
-
export type { TrialChromeProps } from './TrialChrome';
|
|
3
|
+
export type { TrialChromeProps, UndoBindings } from './TrialChrome';
|
|
18
4
|
export { TrialChrome } from './TrialChrome';
|
|
19
5
|
export {
|
|
20
6
|
addTrial,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
|
|
6
|
+
const less = readFileSync(join(dirname(fileURLToPath(import.meta.url)), 'Trial.less'), 'utf8');
|
|
7
|
+
|
|
8
|
+
/** The body of one rule, by selector. Resolves Less's `&__suffix` nesting and
|
|
9
|
+
* matches braces, so a nested block cannot end the slice early. */
|
|
10
|
+
function rule(selector: string): string {
|
|
11
|
+
const nested = selector.replace(/^\.[a-z-]+?(__|--)/, '&$1');
|
|
12
|
+
const start = [selector, nested].map((s) => less.indexOf(`${s} {`)).find((i) => i !== -1);
|
|
13
|
+
if (start === undefined) throw new Error(`no rule for ${selector}`);
|
|
14
|
+
const open = less.indexOf('{', start);
|
|
15
|
+
let depth = 0;
|
|
16
|
+
for (let i = open; i < less.length; i += 1) {
|
|
17
|
+
if (less[i] === '{') depth += 1;
|
|
18
|
+
else if (less[i] === '}') {
|
|
19
|
+
depth -= 1;
|
|
20
|
+
if (depth === 0) return less.slice(open + 1, i);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`unterminated rule for ${selector}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe('trial chrome seams', () => {
|
|
27
|
+
// A `not.toMatch` passes on an empty string, so pin that `rule()` found the
|
|
28
|
+
// rule it was asked for.
|
|
29
|
+
it('isolates the rule it is asked for', () => {
|
|
30
|
+
expect(rule('.lk-trial__toolbar')).toMatch(/flex-shrink/);
|
|
31
|
+
expect(rule('.lk-trial__status')).toMatch(/flex-shrink/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('lets the component draw its own border, not the wrapper', () => {
|
|
35
|
+
expect(rule('.lk-trial__toolbar')).not.toMatch(/border-bottom:\s*[^;]*solid/);
|
|
36
|
+
expect(rule('.lk-trial__status')).not.toMatch(/border-top:\s*[^;]*solid/);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
margin: 0;
|
|
15
15
|
font-family: var(--wzl-font-display);
|
|
16
16
|
font-weight: var(--wzl-font-weight-light);
|
|
17
|
-
font-size:
|
|
17
|
+
font-size: var(--wzl-font-size-lg);
|
|
18
18
|
color: var(--wzl-fg);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
border: 1px dashed var(--wzl-border);
|
|
29
29
|
border-radius: var(--wzl-radius-sm);
|
|
30
30
|
padding: 2px 8px;
|
|
31
|
-
font-size:
|
|
31
|
+
font-size: var(--wzl-font-size-sm);
|
|
32
32
|
color: var(--wzl-fg-subtle);
|
|
33
33
|
cursor: pointer;
|
|
34
34
|
}
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
.lk-layer-stack__drop-hint {
|
|
47
47
|
height: 2px;
|
|
48
48
|
background: var(--wzl-accent);
|
|
49
|
-
border-radius:
|
|
49
|
+
border-radius: var(--wzl-radius-sm);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.lk-layer-stack__empty {
|
|
53
53
|
color: var(--wzl-fg-subtle);
|
|
54
|
-
font-size:
|
|
54
|
+
font-size: var(--wzl-font-size);
|
|
55
55
|
padding: 8px;
|
|
56
56
|
text-align: center;
|
|
57
57
|
}
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
min-width: 22px;
|
|
97
97
|
height: 22px;
|
|
98
98
|
border-radius: var(--wzl-radius-sm);
|
|
99
|
-
font-weight:
|
|
100
|
-
font-size:
|
|
99
|
+
font-weight: var(--wzl-font-weight-bold);
|
|
100
|
+
font-size: var(--wzl-font-size);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
.lk-layer-card.has-accent .lk-layer-card__handle {
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
.lk-layer-card__kind,
|
|
113
113
|
.lk-layer-card__primary {
|
|
114
114
|
flex: 1;
|
|
115
|
-
font-size:
|
|
115
|
+
font-size: var(--wzl-font-size);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
.lk-layer-card__primary {
|
|
@@ -121,14 +121,14 @@
|
|
|
121
121
|
color: var(--wzl-fg);
|
|
122
122
|
font: inherit;
|
|
123
123
|
text-transform: uppercase;
|
|
124
|
-
letter-spacing:
|
|
124
|
+
letter-spacing: var(--wzl-tracking-wide);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
.lk-root .lk-layer-card__remove {
|
|
128
128
|
background: transparent;
|
|
129
129
|
border: 0;
|
|
130
130
|
color: var(--wzl-fg-subtle);
|
|
131
|
-
font-size:
|
|
131
|
+
font-size: var(--wzl-font-size-lg);
|
|
132
132
|
cursor: pointer;
|
|
133
133
|
padding: 2px 6px;
|
|
134
134
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CSSProperties, type ReactNode, type RefCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { dlog, useReorderDragList } from '../../passthrough/weasel-ui';
|
|
3
|
+
import { DragHandleGlyph } from '../../primitives/DragHandleGlyph';
|
|
3
4
|
|
|
4
5
|
/** One card in a layer stack: its identity, the label shown when collapsed,
|
|
5
6
|
* and the optional select hoisted into its header. */
|
|
@@ -205,16 +206,3 @@ export function LayerStack({
|
|
|
205
206
|
</div>
|
|
206
207
|
);
|
|
207
208
|
}
|
|
208
|
-
|
|
209
|
-
function DragHandleGlyph() {
|
|
210
|
-
return (
|
|
211
|
-
<svg width="12" height="16" viewBox="0 0 8 16" fill="currentColor" aria-hidden="true">
|
|
212
|
-
<circle cx="2" cy="3" r="1.1" />
|
|
213
|
-
<circle cx="6" cy="3" r="1.1" />
|
|
214
|
-
<circle cx="2" cy="8" r="1.1" />
|
|
215
|
-
<circle cx="6" cy="8" r="1.1" />
|
|
216
|
-
<circle cx="2" cy="13" r="1.1" />
|
|
217
|
-
<circle cx="6" cy="13" r="1.1" />
|
|
218
|
-
</svg>
|
|
219
|
-
);
|
|
220
|
-
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
display: flex;
|
|
20
20
|
justify-content: space-between;
|
|
21
21
|
font-variant-numeric: tabular-nums;
|
|
22
|
-
font-size:
|
|
22
|
+
font-size: var(--wzl-font-size);
|
|
23
23
|
color: var(--wzl-fg-subtle);
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
border-radius: var(--wzl-radius-sm);
|
|
40
40
|
color: var(--wzl-fg);
|
|
41
41
|
padding: 4px 10px;
|
|
42
|
-
font-size:
|
|
42
|
+
font-size: var(--wzl-font-size-sm);
|
|
43
43
|
cursor: pointer;
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { assert, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
4
|
// CurveEditor uses weasel's own bundled React and fails in jsdom.
|
|
5
5
|
// Mock it out — these tests only assert on readouts and the flip button.
|
|
@@ -81,13 +81,13 @@ describe('CurveField', () => {
|
|
|
81
81
|
/>,
|
|
82
82
|
);
|
|
83
83
|
const overlay = container.querySelector('.lk-curve-field__marks');
|
|
84
|
-
|
|
85
|
-
const rect = overlay
|
|
86
|
-
|
|
84
|
+
assert(overlay);
|
|
85
|
+
const rect = overlay.querySelector('rect');
|
|
86
|
+
assert(rect);
|
|
87
87
|
// x = 0.2 * 200 = 40; width = (0.4 - 0.2) * 200 = 40.
|
|
88
|
-
expect(rect
|
|
89
|
-
expect(rect
|
|
90
|
-
expect(rect
|
|
88
|
+
expect(rect.getAttribute('x')).toBe('40');
|
|
89
|
+
expect(rect.getAttribute('width')).toBe('40');
|
|
90
|
+
expect(rect.getAttribute('fill')).toBe('#ffcc00');
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
it('renders a line mark as a positioned line', () => {
|
|
@@ -104,10 +104,10 @@ describe('CurveField', () => {
|
|
|
104
104
|
/>,
|
|
105
105
|
);
|
|
106
106
|
const line = container.querySelector('.lk-curve-field__marks line');
|
|
107
|
-
|
|
108
|
-
expect(line
|
|
109
|
-
expect(line
|
|
110
|
-
expect(line
|
|
107
|
+
assert(line);
|
|
108
|
+
expect(line.getAttribute('x1')).toBe('140');
|
|
109
|
+
expect(line.getAttribute('x2')).toBe('140');
|
|
110
|
+
expect(line.getAttribute('stroke')).toBe('#ffcc00');
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
it('omits the marks overlay when marks is undefined', () => {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
margin: 0 0 8px;
|
|
14
14
|
font-family: var(--wzl-font-display);
|
|
15
15
|
font-weight: var(--wzl-font-weight-light);
|
|
16
|
-
font-size:
|
|
17
|
-
letter-spacing:
|
|
16
|
+
font-size: var(--wzl-font-size-sm);
|
|
17
|
+
letter-spacing: var(--wzl-tracking-wider);
|
|
18
18
|
text-transform: uppercase;
|
|
19
19
|
color: var(--wzl-fg-subtle);
|
|
20
20
|
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
.lk-property-panel__title {
|
|
16
16
|
font-family: var(--wzl-font-display);
|
|
17
17
|
font-weight: var(--wzl-font-weight-light);
|
|
18
|
-
font-size:
|
|
19
|
-
line-height:
|
|
18
|
+
font-size: var(--wzl-font-size-lg);
|
|
19
|
+
line-height: var(--wzl-leading-snug);
|
|
20
20
|
letter-spacing: 0.01em;
|
|
21
21
|
color: var(--wzl-fg);
|
|
22
22
|
margin: 0 0 12px;
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
.lk-property-row__label {
|
|
86
86
|
font-family: var(--wzl-font-display);
|
|
87
87
|
font-weight: var(--wzl-font-weight-light);
|
|
88
|
-
font-size:
|
|
89
|
-
line-height:
|
|
88
|
+
font-size: var(--wzl-font-size-sm);
|
|
89
|
+
line-height: var(--wzl-leading-snug);
|
|
90
90
|
color: var(--wzl-fg-muted);
|
|
91
91
|
text-transform: uppercase;
|
|
92
92
|
letter-spacing: 0.05em;
|
|
@@ -108,14 +108,13 @@
|
|
|
108
108
|
.lk-property-row__readout-input {
|
|
109
109
|
font: inherit;
|
|
110
110
|
font-weight: var(--wzl-font-weight-medium);
|
|
111
|
-
// Force
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
line-height: 1;
|
|
111
|
+
// Force leading-tight — the label parent inherits 1.2, which would make the
|
|
112
|
+
// input box ~3px taller than the speech-balloons reference.
|
|
113
|
+
line-height: var(--wzl-leading-tight);
|
|
115
114
|
color: var(--wzl-accent);
|
|
116
115
|
background: transparent;
|
|
117
116
|
border: 1px solid transparent;
|
|
118
|
-
border-radius:
|
|
117
|
+
border-radius: var(--wzl-radius-sm);
|
|
119
118
|
padding: 1px 0;
|
|
120
119
|
margin: 0;
|
|
121
120
|
width: calc(5em - 24px);
|
|
@@ -126,10 +125,10 @@
|
|
|
126
125
|
-moz-appearance: textfield;
|
|
127
126
|
}
|
|
128
127
|
.lk-property-row__readout-input:hover {
|
|
129
|
-
background:
|
|
128
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
130
129
|
}
|
|
131
130
|
.lk-property-row__readout-input:focus {
|
|
132
|
-
background:
|
|
131
|
+
background: var(--wzl-surface-sunken);
|
|
133
132
|
border-color: var(--wzl-accent);
|
|
134
133
|
}
|
|
135
134
|
.lk-property-row__readout-input::-webkit-inner-spin-button,
|
|
@@ -148,8 +147,8 @@
|
|
|
148
147
|
// Word-style units (e.g. "px") read as a small dim suffix next to the digits.
|
|
149
148
|
.lk-property-row__readout-unit {
|
|
150
149
|
color: var(--wzl-fg-muted);
|
|
151
|
-
font-size:
|
|
152
|
-
line-height:
|
|
150
|
+
font-size: var(--wzl-font-size-2xs);
|
|
151
|
+
line-height: var(--wzl-leading-tight);
|
|
153
152
|
pointer-events: none;
|
|
154
153
|
}
|
|
155
154
|
// Symbol units (e.g. `<sup>°</sup>`) lean on the browser's native super
|
|
@@ -157,7 +156,7 @@
|
|
|
157
156
|
// would re-collapse the glyph onto the baseline.
|
|
158
157
|
.lk-property-row__readout-group sup {
|
|
159
158
|
color: var(--wzl-fg-muted);
|
|
160
|
-
font-size:
|
|
159
|
+
font-size: var(--wzl-font-size-2xs);
|
|
161
160
|
pointer-events: none;
|
|
162
161
|
}
|
|
163
162
|
|
|
@@ -174,12 +173,12 @@
|
|
|
174
173
|
}
|
|
175
174
|
.lk-property-row input[type='range']::-webkit-slider-runnable-track {
|
|
176
175
|
height: 4px;
|
|
177
|
-
border-radius:
|
|
176
|
+
border-radius: var(--wzl-radius-sm);
|
|
178
177
|
background: color-mix(in srgb, var(--wzl-accent) 18%, transparent);
|
|
179
178
|
}
|
|
180
179
|
.lk-property-row input[type='range']::-moz-range-track {
|
|
181
180
|
height: 4px;
|
|
182
|
-
border-radius:
|
|
181
|
+
border-radius: var(--wzl-radius-sm);
|
|
183
182
|
background: color-mix(in srgb, var(--wzl-accent) 18%, transparent);
|
|
184
183
|
}
|
|
185
184
|
.lk-property-row input[type='range']::-webkit-slider-thumb {
|
|
@@ -225,12 +224,15 @@
|
|
|
225
224
|
|
|
226
225
|
.lk-property-row input[type='text']:not(.lk-property-row__readout-input),
|
|
227
226
|
.lk-property-row input[type='number'] {
|
|
228
|
-
background:
|
|
227
|
+
background: var(--wzl-surface-sunken);
|
|
229
228
|
color: var(--wzl-fg);
|
|
230
229
|
border: 1px solid var(--wzl-border);
|
|
231
230
|
border-radius: var(--wzl-radius-sm);
|
|
232
231
|
padding: 6px 8px;
|
|
233
|
-
font:
|
|
232
|
+
font-family: var(--wzl-font-ui);
|
|
233
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
234
|
+
font-size: var(--wzl-font-size);
|
|
235
|
+
line-height: var(--wzl-leading-tight);
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
.lk-property-row input[type='text']:not(.lk-property-row__readout-input):focus,
|
|
@@ -248,7 +250,10 @@
|
|
|
248
250
|
border: 0;
|
|
249
251
|
border-radius: 0;
|
|
250
252
|
padding: 2px 0;
|
|
251
|
-
font:
|
|
253
|
+
font-family: var(--wzl-font-ui);
|
|
254
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
255
|
+
font-size: var(--wzl-font-size);
|
|
256
|
+
line-height: var(--wzl-leading-tight);
|
|
252
257
|
cursor: pointer;
|
|
253
258
|
}
|
|
254
259
|
.lk-property-row select:focus {
|
|
@@ -344,7 +349,7 @@
|
|
|
344
349
|
.lk-property-row--checkbox .lk-property-row__label {
|
|
345
350
|
text-transform: none;
|
|
346
351
|
letter-spacing: normal;
|
|
347
|
-
font-size:
|
|
352
|
+
font-size: var(--wzl-font-size);
|
|
348
353
|
color: var(--wzl-fg);
|
|
349
354
|
// Place the label after the checkbox visually.
|
|
350
355
|
order: 1;
|
|
@@ -374,7 +379,10 @@
|
|
|
374
379
|
color: var(--wzl-fg-muted);
|
|
375
380
|
border: 0;
|
|
376
381
|
border-radius: 0;
|
|
377
|
-
font:
|
|
382
|
+
font-family: var(--wzl-font-ui);
|
|
383
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
384
|
+
font-size: var(--wzl-font-size-sm);
|
|
385
|
+
line-height: var(--wzl-leading-tight);
|
|
378
386
|
cursor: pointer;
|
|
379
387
|
backdrop-filter: none;
|
|
380
388
|
-webkit-backdrop-filter: none;
|
|
@@ -391,12 +399,12 @@
|
|
|
391
399
|
|
|
392
400
|
.lk-property-row__toggle-button--selected {
|
|
393
401
|
background: var(--wzl-accent);
|
|
394
|
-
color:
|
|
402
|
+
color: var(--wzl-fg-on-accent);
|
|
395
403
|
font-weight: var(--wzl-font-weight-medium);
|
|
396
404
|
}
|
|
397
405
|
|
|
398
406
|
.lk-property-row__toggle-button--selected:hover {
|
|
399
|
-
color:
|
|
407
|
+
color: var(--wzl-fg-on-accent);
|
|
400
408
|
}
|
|
401
409
|
|
|
402
410
|
// ── Subpanel ────────────────────────────────────────────────────────
|
|
@@ -420,12 +428,12 @@
|
|
|
420
428
|
}
|
|
421
429
|
.lk-subpanel__title {
|
|
422
430
|
font-family: var(--wzl-font-display);
|
|
423
|
-
font-weight:
|
|
424
|
-
font-size:
|
|
425
|
-
line-height:
|
|
431
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
432
|
+
font-size: var(--wzl-font-size-sm);
|
|
433
|
+
line-height: var(--wzl-leading-tight);
|
|
426
434
|
color: var(--wzl-fg);
|
|
427
435
|
text-transform: uppercase;
|
|
428
|
-
letter-spacing:
|
|
436
|
+
letter-spacing: var(--wzl-tracking-wider);
|
|
429
437
|
margin: 0;
|
|
430
438
|
padding: 6px 0 4px;
|
|
431
439
|
display: flex;
|
|
@@ -508,24 +516,27 @@
|
|
|
508
516
|
min-width: 14px;
|
|
509
517
|
padding: 0 2px;
|
|
510
518
|
color: var(--lk-panel-accent, var(--wzl-fg-muted));
|
|
511
|
-
font-size:
|
|
512
|
-
font-weight:
|
|
513
|
-
font-family:
|
|
519
|
+
font-size: var(--wzl-font-size);
|
|
520
|
+
font-weight: var(--wzl-font-weight-bold);
|
|
521
|
+
font-family: var(--wzl-font-mono);
|
|
514
522
|
line-height: 1;
|
|
515
523
|
}
|
|
516
524
|
|
|
517
525
|
.lk-effect-card__title {
|
|
518
526
|
font-family: var(--wzl-font-display);
|
|
519
|
-
font-weight:
|
|
520
|
-
font-size:
|
|
521
|
-
line-height:
|
|
527
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
528
|
+
font-size: var(--wzl-font-size);
|
|
529
|
+
line-height: var(--wzl-leading-tight);
|
|
522
530
|
color: var(--wzl-fg);
|
|
523
531
|
text-transform: uppercase;
|
|
524
532
|
letter-spacing: 0.04em;
|
|
525
533
|
}
|
|
526
534
|
|
|
527
535
|
.lk-effect-card__primary {
|
|
528
|
-
font:
|
|
536
|
+
font-family: var(--wzl-font-ui);
|
|
537
|
+
font-weight: var(--wzl-font-weight-medium);
|
|
538
|
+
font-size: var(--wzl-font-size-sm);
|
|
539
|
+
line-height: var(--wzl-leading-tight);
|
|
529
540
|
color: var(--wzl-fg);
|
|
530
541
|
background: rgba(0, 0, 0, 0.3);
|
|
531
542
|
border: 1px solid var(--wzl-border);
|
|
@@ -547,19 +558,19 @@
|
|
|
547
558
|
background: transparent;
|
|
548
559
|
color: var(--wzl-fg-muted);
|
|
549
560
|
border: 1px solid transparent;
|
|
550
|
-
border-radius:
|
|
561
|
+
border-radius: var(--wzl-radius-sm);
|
|
551
562
|
width: 22px;
|
|
552
563
|
height: 22px;
|
|
553
|
-
font-size:
|
|
564
|
+
font-size: var(--wzl-font-size);
|
|
554
565
|
cursor: pointer;
|
|
555
566
|
display: inline-flex;
|
|
556
567
|
align-items: center;
|
|
557
568
|
justify-content: center;
|
|
558
569
|
}
|
|
559
570
|
.lk-effect-card__remove:hover {
|
|
560
|
-
color:
|
|
561
|
-
border-color:
|
|
562
|
-
background:
|
|
571
|
+
color: var(--wzl-danger-fg, var(--wzl-danger));
|
|
572
|
+
border-color: color-mix(in srgb, var(--wzl-danger) 40%, transparent);
|
|
573
|
+
background: color-mix(in srgb, var(--wzl-danger) 8%, transparent);
|
|
563
574
|
}
|
|
564
575
|
|
|
565
576
|
.lk-effect-card__body {
|
|
@@ -578,12 +589,15 @@
|
|
|
578
589
|
.lk-effect-card-list__drop-hint {
|
|
579
590
|
height: 0;
|
|
580
591
|
border-top: 2px solid var(--wzl-accent);
|
|
581
|
-
border-radius:
|
|
592
|
+
border-radius: var(--wzl-radius-sm);
|
|
582
593
|
margin: 2px 0;
|
|
583
594
|
box-shadow: 0 0 6px color-mix(in srgb, var(--wzl-accent) 60%, transparent);
|
|
584
595
|
}
|
|
585
596
|
.lk-effect-card-list__empty {
|
|
586
|
-
font: var(--wzl-font-
|
|
597
|
+
font-family: var(--wzl-font-display);
|
|
598
|
+
font-weight: var(--wzl-font-weight-light);
|
|
599
|
+
font-size: var(--wzl-font-size-sm);
|
|
600
|
+
line-height: var(--wzl-leading);
|
|
587
601
|
color: var(--wzl-fg-muted);
|
|
588
602
|
text-align: center;
|
|
589
603
|
padding: 16px 12px;
|
|
@@ -299,7 +299,8 @@ export const RightSidebarTails: Story = {
|
|
|
299
299
|
const next = prev.filter((t) => t.id !== sourceId);
|
|
300
300
|
const idx = next.findIndex((t) => t.id === targetId);
|
|
301
301
|
const insertAt = position === 'before' ? idx : idx + 1;
|
|
302
|
-
const src = prev.find((t) => t.id === sourceId)
|
|
302
|
+
const src = prev.find((t) => t.id === sourceId);
|
|
303
|
+
if (!src) return prev;
|
|
303
304
|
next.splice(insertAt, 0, src);
|
|
304
305
|
return next;
|
|
305
306
|
});
|
|
@@ -348,7 +349,8 @@ export const LayerStack: Story = {
|
|
|
348
349
|
const next = prev.filter((t) => t.id !== sourceId);
|
|
349
350
|
const idx = next.findIndex((t) => t.id === targetId);
|
|
350
351
|
const insertAt = position === 'before' ? idx : idx + 1;
|
|
351
|
-
const src = prev.find((t) => t.id === sourceId)
|
|
352
|
+
const src = prev.find((t) => t.id === sourceId);
|
|
353
|
+
if (!src) return prev;
|
|
352
354
|
next.splice(insertAt, 0, src);
|
|
353
355
|
return next;
|
|
354
356
|
});
|
|
@@ -7,10 +7,10 @@ import type { ReactNode } from 'react';
|
|
|
7
7
|
*/
|
|
8
8
|
export function SideBySide({ block, inline }: { block: ReactNode; inline: ReactNode }) {
|
|
9
9
|
const labelStyle = {
|
|
10
|
-
font: '
|
|
10
|
+
font: 'var(--wzl-font-weight-normal) var(--wzl-font-size-sm)/var(--wzl-leading-tight) var(--wzl-font-ui)',
|
|
11
11
|
color: 'var(--wzl-fg-muted)',
|
|
12
12
|
textTransform: 'uppercase' as const,
|
|
13
|
-
letterSpacing: '
|
|
13
|
+
letterSpacing: 'var(--wzl-tracking-wider)',
|
|
14
14
|
margin: '0 0 8px',
|
|
15
15
|
};
|
|
16
16
|
return (
|