@weasel-js/labkit 1.5.2 → 1.6.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/README.md +3 -7
- package/dist/_dts/{CanvasStackContext-CMMo180l.d.ts → CanvasStackContext-DQgcH1ny.d.ts} +1 -1
- package/dist/_dts/LayerList.d-2c9yup5Y.d.ts +83 -0
- package/dist/_dts/{PrefsForm.d-DPy9I8It.d.ts → PrefsRow.d-DFpPIeIC.d.ts} +16 -1
- package/dist/_dts/{Select.d-ZTiwzYyT.d.ts → Select.d-BchGMC2Y.d.ts} +102 -11
- package/dist/_dts/{frac-B4hFJMiN.d.ts → frac-DTRq7Xpb.d.ts} +18 -10
- package/dist/_dts/inDialog-D5ZKGjiD.d.ts +23 -0
- package/dist/_dts/{index-DlKolEIZ.d.ts → index-B0--8PEM.d.ts} +2 -2
- package/dist/_dts/index-DINmCuLA.d.ts +453 -0
- package/dist/_dts/number.d-OeQYQoUO.d.ts +28 -0
- package/dist/_dts/{types-Db-3NNk1.d.ts → types-B7y8hX1D.d.ts} +2 -2
- package/dist/_dts/{usePanZoom-SSTZe410.d.ts → usePanZoom-Bq73pwFe.d.ts} +2 -2
- package/dist/_dts/{useTrialState-pnAE-UBD.d.ts → useTrialState-CP4jfuKl.d.ts} +1 -1
- package/dist/canvas/index.d.ts +6 -5
- package/dist/chrome/index.d.ts +5 -4
- package/dist/chrome/index.js +7 -7
- package/dist/chunk-2RVCB2PT.js +3 -0
- package/dist/chunk-2RVCB2PT.js.map +1 -0
- package/dist/{chunk-753Y6HE6.js → chunk-3FI7Y4R4.js} +4 -4
- package/dist/chunk-3FI7Y4R4.js.map +1 -0
- package/dist/{chunk-REOBGYMC.js → chunk-AWH3SRPW.js} +31 -5
- package/dist/chunk-AWH3SRPW.js.map +1 -0
- package/dist/{chunk-A2ACAGW6.js → chunk-BVL7Y574.js} +22 -5
- package/dist/chunk-BVL7Y574.js.map +1 -0
- package/dist/{chunk-CKUKF72R.js → chunk-H5VIV7MQ.js} +26 -22
- package/dist/chunk-H5VIV7MQ.js.map +1 -0
- package/dist/chunk-HFRE4QQV.js +400 -0
- package/dist/chunk-HFRE4QQV.js.map +1 -0
- package/dist/{chunk-LRI3MBGR.js → chunk-MOLIUNVH.js} +4 -4
- package/dist/{chunk-LRI3MBGR.js.map → chunk-MOLIUNVH.js.map} +1 -1
- package/dist/chunk-USO6TERP.js +90 -0
- package/dist/chunk-USO6TERP.js.map +1 -0
- package/dist/{chunk-EMXAIRUJ.js → chunk-VQ47KWD5.js} +3 -3
- package/dist/{chunk-EMXAIRUJ.js.map → chunk-VQ47KWD5.js.map} +1 -1
- package/dist/chunk-WUJXJC5O.js +14568 -0
- package/dist/chunk-WUJXJC5O.js.map +1 -0
- package/dist/{chunk-KJCUERQF.js → chunk-ZORVNOKX.js} +6 -25
- package/dist/chunk-ZORVNOKX.js.map +1 -0
- package/dist/config/index.d.ts +50 -7
- package/dist/config/index.js +5 -5
- package/dist/controls/index.d.ts +6 -3
- package/dist/controls/index.js +4 -4
- package/dist/dragdrop/index.d.ts +4 -3
- package/dist/index.d.ts +83 -102
- package/dist/index.js +430 -458
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +6 -35
- package/dist/layers/index.js +2 -3
- package/dist/loupe/index.d.ts +6 -5
- package/dist/passthrough/weasel-ui.d.ts +407 -204
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.d.ts +2 -13
- package/dist/primitives/index.js +4 -4
- package/dist/state/index.d.ts +6 -5
- package/dist/state/index.js +5 -5
- package/dist/styles.css +298 -174
- package/dist/undo/index.d.ts +4 -3
- package/package.json +9 -13
- package/src/annotations/frac.test.ts +7 -0
- package/src/annotations/paint.test.ts +21 -0
- package/src/annotations/paint.ts +12 -0
- package/src/annotations/store.test.ts +31 -0
- package/src/annotations/types.ts +3 -2
- package/src/canvas/Stage.test.tsx +18 -0
- package/src/chrome/regions/SidebarRegion.less +197 -0
- package/src/chrome/regions/SidebarRegion.test.tsx +20 -0
- package/src/chrome/regions/SidebarRegion.tsx +7 -2
- package/src/chrome/types.ts +5 -2
- package/src/config/autoConfig.ts +2 -2
- package/src/config/builder.ts +20 -1
- package/src/config/entry.test.ts +8 -0
- package/src/config/index.ts +2 -0
- package/src/config/rules.ts +2 -0
- package/src/config/sectionTree.test.ts +146 -0
- package/src/config/sectionTree.ts +124 -0
- package/src/controls/ControlPanel.less +4 -0
- package/src/controls/ControlPanel.stories.tsx +55 -2
- package/src/controls/ControlPanel.test.tsx +30 -3
- package/src/controls/ControlPanel.tsx +116 -337
- package/src/controls/inDialog.test.tsx +82 -0
- package/src/controls/inDialog.tsx +46 -0
- package/src/controls/index.ts +1 -0
- package/src/index.ts +11 -26
- package/src/instrument/types.ts +5 -2
- package/src/lab/Lab.nebula.test.tsx +31 -0
- package/src/lab/Lab.tsx +38 -15
- package/src/lab/LabBoundary.test.tsx +66 -0
- package/src/lab/LabBoundary.tsx +56 -0
- package/src/lab/LabHeader.tsx +4 -23
- package/src/lab/LabRoot.tsx +2 -3
- package/src/lab/LabShell.less +0 -1
- package/src/lab/LabShell.stories.tsx +15 -0
- package/src/lab/LabShell.test.tsx +18 -0
- package/src/lab/LabShell.tsx +14 -1
- package/src/lab/LabSwitcher.less +1 -1
- package/src/lab/LabSwitcher.test.tsx +41 -0
- package/src/lab/LabSwitcher.tsx +30 -8
- package/src/lab/index.ts +1 -0
- package/src/layers/AGENTS.md +18 -74
- package/src/layers/index.ts +4 -2
- package/src/passthrough/weasel-ui.ts +25 -10
- package/src/primitives/index.ts +0 -2
- package/src/specimen/Specimen.tsx +42 -56
- package/src/state/types.ts +2 -1
- package/src/styles.less +4 -2
- package/src/theme/Interstellar.stories.tsx +8 -9
- package/src/theme/base.less +3 -20
- package/src/theme/interstellar.test.ts +6 -3
- package/src/theme/interstellar.theme.json +0 -56
- package/src/theme/interstellar.ts +2 -2
- package/src/trial/Trial.canvas.test.tsx +1 -1
- package/src/trial/Trial.tsx +30 -8
- package/dist/_dts/index-8LiKe3A-.d.ts +0 -410
- package/dist/chunk-6BUQ77ZV.js +0 -18
- package/dist/chunk-6BUQ77ZV.js.map +0 -1
- package/dist/chunk-753Y6HE6.js.map +0 -1
- package/dist/chunk-A2ACAGW6.js.map +0 -1
- package/dist/chunk-CKUKF72R.js.map +0 -1
- package/dist/chunk-D35PFTS7.js +0 -170
- package/dist/chunk-D35PFTS7.js.map +0 -1
- package/dist/chunk-FKLT3ITC.js +0 -590
- package/dist/chunk-FKLT3ITC.js.map +0 -1
- package/dist/chunk-KJCUERQF.js.map +0 -1
- package/dist/chunk-LASCBWW7.js +0 -13456
- package/dist/chunk-LASCBWW7.js.map +0 -1
- package/dist/chunk-REOBGYMC.js.map +0 -1
- package/dist/ui/layers/index.d.ts +0 -66
- package/dist/ui/layers/index.js +0 -3
- package/dist/ui/layers/index.js.map +0 -1
- package/src/lab/useSystemMode.ts +0 -30
- package/src/layers/LayerList.less +0 -93
- package/src/layers/LayerList.stories.tsx +0 -66
- package/src/layers/LayerList.test.tsx +0 -232
- package/src/layers/LayerList.tsx +0 -268
- package/src/primitives/Sidebar.less +0 -112
- package/src/primitives/Sidebar.stories.tsx +0 -38
- package/src/primitives/Sidebar.test.tsx +0 -74
- package/src/primitives/Sidebar.tsx +0 -35
- package/src/ui/layers/index.ts +0 -5
|
@@ -9,6 +9,8 @@ const PAGES = [
|
|
|
9
9
|
{ href: '/ingest', label: 'Ingestion' },
|
|
10
10
|
];
|
|
11
11
|
|
|
12
|
+
const open2 = (name: string) =>
|
|
13
|
+
fireEvent.click(screen.getByRole('button', { name: new RegExp(name) }));
|
|
12
14
|
const open = () => fireEvent.click(screen.getByRole('button', { name: /corpus stats/ }));
|
|
13
15
|
|
|
14
16
|
describe('currentPage', () => {
|
|
@@ -27,6 +29,45 @@ describe('currentPage', () => {
|
|
|
27
29
|
it('reports -1 for a page that is not one of them', () => {
|
|
28
30
|
expect(currentPage('/bench', PAGES)).toBe(-1);
|
|
29
31
|
});
|
|
32
|
+
|
|
33
|
+
// One document serving its pages from the hash: every href shares a path, so
|
|
34
|
+
// only the fragment can tell them apart.
|
|
35
|
+
const ROUTES = [
|
|
36
|
+
{ href: '/app/', label: 'App' },
|
|
37
|
+
{ href: '#/dev/tools', label: 'Tools' },
|
|
38
|
+
{ href: '#/dev/registry', label: 'Registry' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
it('tells hash routes on one document apart', () => {
|
|
42
|
+
expect(currentPage('/app/#/dev/registry', ROUTES)).toBe(2);
|
|
43
|
+
expect(currentPage('/app/#/dev/tools', ROUTES)).toBe(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('matches a hash route through its own query and sub-routes', () => {
|
|
47
|
+
expect(currentPage('/app/#/dev/tools?bundle=minimal', ROUTES)).toBe(1);
|
|
48
|
+
expect(currentPage('/app/#/dev/tools/', ROUTES)).toBe(1);
|
|
49
|
+
expect(currentPage('/app/#/dev/registry/tool/rect', ROUTES)).toBe(2);
|
|
50
|
+
expect(currentPage('/app/#/dev/toolsets', ROUTES)).toBe(0);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('falls back to the page without a hash when no route matches', () => {
|
|
54
|
+
expect(currentPage('/app/', ROUTES)).toBe(0);
|
|
55
|
+
expect(currentPage('/app/#/elsewhere', ROUTES)).toBe(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('reads the hash off the current location by default', () => {
|
|
59
|
+
window.history.replaceState(null, '', '/app/#/dev/registry');
|
|
60
|
+
try {
|
|
61
|
+
render(<LabSwitcher title="Registry" pages={ROUTES} />);
|
|
62
|
+
open2('Registry');
|
|
63
|
+
expect(screen.getByRole('menuitem', { name: 'Registry' })).toHaveAttribute(
|
|
64
|
+
'aria-current',
|
|
65
|
+
'page',
|
|
66
|
+
);
|
|
67
|
+
} finally {
|
|
68
|
+
window.history.replaceState(null, '', '/');
|
|
69
|
+
}
|
|
70
|
+
});
|
|
30
71
|
});
|
|
31
72
|
|
|
32
73
|
describe('<LabSwitcher>', () => {
|
package/src/lab/LabSwitcher.tsx
CHANGED
|
@@ -2,7 +2,8 @@ import { useCallback, useEffect, useId, useRef, useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
/** One page in a project's set of labs. */
|
|
4
4
|
export interface LabPage {
|
|
5
|
-
/** The page's own URL, and how the switcher knows which page is open.
|
|
5
|
+
/** The page's own URL, and how the switcher knows which page is open. A
|
|
6
|
+
* hash route (`#/dev/tools`) names a page on the current document. */
|
|
6
7
|
href: string;
|
|
7
8
|
label: string;
|
|
8
9
|
}
|
|
@@ -18,18 +19,39 @@ export interface LabSwitcherProps {
|
|
|
18
19
|
className?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** A URL split into the document it names and the hash route on it, each
|
|
23
|
+
* without its query, trailing slash or `.html`. */
|
|
24
|
+
function locate(url: string): { doc: string; route: string } {
|
|
25
|
+
const hash = url.indexOf('#');
|
|
26
|
+
const trim = (part: string) => part.replace(/\?.*$/, '').replace(/\/$/, '');
|
|
27
|
+
return {
|
|
28
|
+
doc: trim(hash < 0 ? url : url.slice(0, hash)).replace(/\.html$/, ''),
|
|
29
|
+
route: hash < 0 ? '' : trim(url.slice(hash + 1)),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
/** Which of `pages` a path is on, or -1.
|
|
22
34
|
*
|
|
23
35
|
* Matched on the end of the path so a query string, a trailing slash or a
|
|
24
36
|
* leftover `.html` cannot lose it: a project whose dev server maps `/stats`
|
|
25
37
|
* to `stats.html` serves both spellings, and a bookmark from before the URLs
|
|
26
|
-
* lost their extension still resolves to the same page.
|
|
38
|
+
* lost their extension still resolves to the same page.
|
|
39
|
+
*
|
|
40
|
+
* A page whose `href` carries a hash is a route on a single document and wins
|
|
41
|
+
* when the path's hash is that route or one under it. A page without one
|
|
42
|
+
* ignores the hash, so an in-page anchor does not lose it. */
|
|
27
43
|
export function currentPage(path: string, pages: readonly LabPage[]): number {
|
|
28
|
-
const here = path
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
.
|
|
32
|
-
|
|
44
|
+
const here = locate(path);
|
|
45
|
+
const onDoc = (doc: string) => here.doc.endsWith(doc);
|
|
46
|
+
const routed = pages.findIndex((p) => {
|
|
47
|
+
if (!p.href.includes('#')) return false;
|
|
48
|
+
const page = locate(p.href);
|
|
49
|
+
return (
|
|
50
|
+
onDoc(page.doc) && (here.route === page.route || here.route.startsWith(`${page.route}/`))
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
if (routed >= 0) return routed;
|
|
54
|
+
return pages.findIndex((p) => !p.href.includes('#') && onDoc(locate(p.href).doc));
|
|
33
55
|
}
|
|
34
56
|
|
|
35
57
|
/** A project's lab title, doubling as the way to reach its other labs.
|
|
@@ -47,7 +69,7 @@ export function LabSwitcher({ title, pages, path, className }: LabSwitcherProps)
|
|
|
47
69
|
const root = useRef<HTMLDivElement>(null);
|
|
48
70
|
const menuId = useId();
|
|
49
71
|
const here = currentPage(
|
|
50
|
-
path ?? (typeof window === 'undefined' ? '' : window.location.pathname),
|
|
72
|
+
path ?? (typeof window === 'undefined' ? '' : window.location.pathname + window.location.hash),
|
|
51
73
|
pages,
|
|
52
74
|
);
|
|
53
75
|
|
package/src/lab/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { LabProps } from './Lab';
|
|
2
2
|
export { Lab } from './Lab';
|
|
3
|
+
export { LabBoundary, type LabBoundaryProps } from './LabBoundary';
|
|
3
4
|
export type { LabContextValue } from './LabContext';
|
|
4
5
|
export { LabContext, useLabContext } from './LabContext';
|
|
5
6
|
export type { LabPaletteProps } from './LabPalette';
|
package/src/layers/AGENTS.md
CHANGED
|
@@ -1,33 +1,11 @@
|
|
|
1
1
|
# Layers — Agent Guide
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`src/layers/` re-exports `<LayerList>` from `@weasel-js/ui`, along with the
|
|
4
|
+
`layers` capability types. The component itself — rows, cards, nesting,
|
|
5
|
+
selection, visibility, reorder — is documented at its source in
|
|
6
|
+
`packages/ui/src/components/LayerList/`.
|
|
4
7
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
| File | Role |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `LayerList.tsx` | Layer toggle/reorder list, flat or nested (sidebar widget) |
|
|
10
|
-
| `LayerList.less` | Row styling, drag handle, pinned-row variant, subtree indent |
|
|
11
|
-
| `LayerList.stories.tsx` | Flat and nested renderings |
|
|
12
|
-
|
|
13
|
-
## Props
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
interface LayerListProps {
|
|
17
|
-
layers: LayerTreeNode[]; // LayerDescriptor + { children?, defaultCollapsed? }
|
|
18
|
-
visibility: Record<string, boolean>; // missing key → visible
|
|
19
|
-
onReorder: (newOrder: LayerTreeNode[]) => void;
|
|
20
|
-
onToggle: (id: string, visible: boolean) => void;
|
|
21
|
-
collapsedIds?: readonly string[]; // supplying it makes collapse controlled
|
|
22
|
-
onCollapsedChange?: (ids: string[]) => void;
|
|
23
|
-
className?: string;
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
`LayerDescriptor` lives in `src/instrument/types.ts`; `LayerTreeNode` extends it
|
|
28
|
-
in `LayerList.tsx`, so a plain `LayerDescriptor[]` is still a valid `layers`.
|
|
29
|
-
|
|
30
|
-
## How it integrates
|
|
8
|
+
## How the capability uses it
|
|
31
9
|
|
|
32
10
|
The instrument declares layer ids:
|
|
33
11
|
|
|
@@ -35,53 +13,19 @@ The instrument declares layer ids:
|
|
|
35
13
|
layers: { ids: ['grid', 'plants'] }
|
|
36
14
|
```
|
|
37
15
|
|
|
38
|
-
`Trial.tsx`
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Setting `alwaysOn: true` on a `LayerDescriptor` does two things:
|
|
45
|
-
|
|
46
|
-
1. The row renders with a 🔒 badge instead of a drag handle and visibility checkbox.
|
|
47
|
-
2. The row is excluded from reorder operations — pinned rows always sort to the bottom of the rendered list.
|
|
48
|
-
|
|
49
|
-
This is intended for legend/HUD layers that should never be toggled off. Visibility for pinned rows is **not** read from the `visibility` prop; they always render.
|
|
50
|
-
|
|
51
|
-
## Nesting
|
|
52
|
-
|
|
53
|
-
A node with `children` renders an expandable subtree. The expand control is
|
|
54
|
-
`<Disclosure>` from `@weasel-js/ui` — the same twisty every other collapsible
|
|
55
|
-
surface uses.
|
|
56
|
-
|
|
57
|
-
Reordering is scoped to siblings: a drag moves a row within its own parent's
|
|
58
|
-
child list and never reparents it. `onReorder` still receives the whole tree,
|
|
59
|
-
with only that sibling group's order changed.
|
|
60
|
-
|
|
61
|
-
The twisty column appears only when some node in the tree has children — a flat
|
|
62
|
-
list renders exactly the rows it always did. Within a tree, childless rows get
|
|
63
|
-
`.lk-layer-list__twisty-gap` so labels stay aligned down a level.
|
|
64
|
-
|
|
65
|
-
Collapse is uncontrolled by default, seeded once from each node's
|
|
66
|
-
`defaultCollapsed`. Pass `collapsedIds` to own it; `onCollapsedChange` fires
|
|
67
|
-
either way.
|
|
68
|
-
|
|
69
|
-
## Drag handle customization
|
|
70
|
-
|
|
71
|
-
The drag handle is a button with class `lk-layer-list__handle` holding `<DragHandleGlyph>` (from `@weasel-js/ui`), the same grip `LayerStack` uses. Its padding is transparent and cancelled by an equal negative margin, so the grab target is larger than the drawn dots without widening the row. Row pitch — height plus row gap — is measured from the DOM when a drag starts, so restyling the row does not skew drag distance. It used to be a hardcoded `28`, which had already drifted from the rendered height by the time it was found.
|
|
72
|
-
|
|
73
|
-
Pointer capture is acquired on `pointerdown` and released on `pointerup`, so dragging works across the document without requiring window-level listeners.
|
|
74
|
-
|
|
75
|
-
## Empty state
|
|
76
|
-
|
|
77
|
-
If `layers.length === 0`, renders `.lk-layer-list__empty` with the text "No layers". Trial already guards this case (`layerDescriptors.length > 0`) so the empty state is rare in practice.
|
|
16
|
+
`Trial.tsx` turns each id into a `LayerDescriptor` (`label === id` unless the
|
|
17
|
+
entry is a descriptor), keeps `visibility` and `layerOrder` in local state, and
|
|
18
|
+
builds the list's items from them in the order the canvas draws. The order a
|
|
19
|
+
drag produces is applied to `instrument.canvas.layers` before they reach
|
|
20
|
+
`<CanvasStack>`, and each toggle and reorder emits `layers.toggle` /
|
|
21
|
+
`layers.reorder` on the bus.
|
|
78
22
|
|
|
79
|
-
|
|
23
|
+
`layers.ids` and `canvas.layers[].id` are assumed to match. A canvas layer not
|
|
24
|
+
in `layers.ids` keeps its default order and is always visible.
|
|
80
25
|
|
|
81
|
-
|
|
82
|
-
- Multi-select reorder (current implementation is single-row)
|
|
83
|
-
- Right-click context menu
|
|
84
|
-
- Reparenting by drag (nesting renders, but a drag stays within one parent)
|
|
85
|
-
- Solo/mute UI common in DAW-style apps
|
|
26
|
+
## `alwaysOn`
|
|
86
27
|
|
|
87
|
-
|
|
28
|
+
A descriptor with `alwaysOn: true` becomes a `locked` item, pinned below the
|
|
29
|
+
rest: it shows a lock in place of the grip and has no visibility checkbox,
|
|
30
|
+
cannot be dragged, and no drag can cross it. It always renders, whatever
|
|
31
|
+
`visibility` says. Intended for legend and HUD layers.
|
package/src/layers/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// LayerList lives in `@weasel-js/ui`. Named, not `export *` — a star re-export
|
|
2
|
+
// of an external package emits no binding in the bundle.
|
|
3
|
+
export type { LayerListItem, LayerListProps, LayerMove } from '@weasel-js/ui';
|
|
4
|
+
export { LayerList, moveLayers } from '@weasel-js/ui';
|
|
1
5
|
export type { LayerCapability, LayerDescriptor } from '../instrument/types';
|
|
2
|
-
export type { LayerListProps, LayerTreeNode } from './LayerList';
|
|
3
|
-
export { LayerList } from './LayerList';
|
|
@@ -8,11 +8,6 @@
|
|
|
8
8
|
export {
|
|
9
9
|
ActionBar,
|
|
10
10
|
type ActionBarProps,
|
|
11
|
-
ActionsBar,
|
|
12
|
-
type ActionsBarItem,
|
|
13
|
-
type ActionsBarProps,
|
|
14
|
-
type ActionsBarSize,
|
|
15
|
-
type ActionsBarVariant,
|
|
16
11
|
type AddPointMode,
|
|
17
12
|
type AnchorRenderProps,
|
|
18
13
|
type AsyncOption,
|
|
@@ -22,12 +17,17 @@ export {
|
|
|
22
17
|
type BadgeProps,
|
|
23
18
|
type BadgeShape,
|
|
24
19
|
type BadgeSize,
|
|
25
|
-
type
|
|
20
|
+
type BadgeStatus,
|
|
26
21
|
type BadgeVariant,
|
|
27
22
|
type BoundsCtx,
|
|
28
23
|
type BuiltInEdgeName,
|
|
29
24
|
type BuiltinPref,
|
|
30
25
|
Button,
|
|
26
|
+
ButtonBar,
|
|
27
|
+
type ButtonBarItem,
|
|
28
|
+
type ButtonBarProps,
|
|
29
|
+
type ButtonBarSize,
|
|
30
|
+
type ButtonBarVariant,
|
|
31
31
|
type ButtonProps,
|
|
32
32
|
type ButtonSize,
|
|
33
33
|
type ButtonVariant,
|
|
@@ -38,6 +38,8 @@ export {
|
|
|
38
38
|
type CheckboxProps,
|
|
39
39
|
type ChromaCurve,
|
|
40
40
|
type ChromaCurvePoint,
|
|
41
|
+
ColorModeControl,
|
|
42
|
+
type ColorModeControlProps,
|
|
41
43
|
ComboBox,
|
|
42
44
|
type ComboBoxCommit,
|
|
43
45
|
type ComboBoxFilter,
|
|
@@ -56,10 +58,13 @@ export {
|
|
|
56
58
|
Dialog,
|
|
57
59
|
type DialogProps,
|
|
58
60
|
Disclosure,
|
|
59
|
-
|
|
61
|
+
DisclosureMark,
|
|
62
|
+
type DisclosureMarkProps,
|
|
60
63
|
type DisclosureProps,
|
|
61
64
|
DisclosureRow,
|
|
62
65
|
type DisclosureRowProps,
|
|
66
|
+
DragGhost,
|
|
67
|
+
type DragGhostProps,
|
|
63
68
|
DragHandleGlyph,
|
|
64
69
|
type DragHandleGlyphProps,
|
|
65
70
|
detectPlatform,
|
|
@@ -98,16 +103,20 @@ export {
|
|
|
98
103
|
keyGlyph,
|
|
99
104
|
keySpecFromKey,
|
|
100
105
|
keySpecsFromMods,
|
|
106
|
+
keySpecsFromShortcut,
|
|
107
|
+
LayerList,
|
|
101
108
|
type LayerListItem,
|
|
102
|
-
|
|
103
|
-
type
|
|
104
|
-
|
|
109
|
+
type LayerListProps,
|
|
110
|
+
type LayerMove,
|
|
111
|
+
ListEditor,
|
|
112
|
+
type ListEditorProps,
|
|
105
113
|
type LogicalMod,
|
|
106
114
|
type LogicalModSpec,
|
|
107
115
|
MenuButton,
|
|
108
116
|
type MenuButtonItem,
|
|
109
117
|
type MenuButtonProps,
|
|
110
118
|
MINUS_SIGN,
|
|
119
|
+
moveLayers,
|
|
111
120
|
NumberField,
|
|
112
121
|
type NumberFieldProps,
|
|
113
122
|
OptionsBar,
|
|
@@ -145,6 +154,11 @@ export {
|
|
|
145
154
|
type PrefRenderer,
|
|
146
155
|
type PrefString,
|
|
147
156
|
type PrefStringControl,
|
|
157
|
+
PrefsDialog,
|
|
158
|
+
type PrefsDialogProps,
|
|
159
|
+
PrefsForm,
|
|
160
|
+
type PrefsFormProps,
|
|
161
|
+
type PrefsLayout,
|
|
148
162
|
paintGradientTrack,
|
|
149
163
|
prefValueAtPath,
|
|
150
164
|
Radio,
|
|
@@ -155,6 +169,7 @@ export {
|
|
|
155
169
|
type RangeSliderProps,
|
|
156
170
|
type ReorderDragHandlers,
|
|
157
171
|
type ReorderDragState,
|
|
172
|
+
type ReorderGhost,
|
|
158
173
|
type RovingItem,
|
|
159
174
|
type RovingTabIndex,
|
|
160
175
|
Select,
|
package/src/primitives/index.ts
CHANGED
|
@@ -7,8 +7,6 @@ export type { LegendEntry, LegendMark, LegendProps } from './Legend';
|
|
|
7
7
|
export { Legend } from './Legend';
|
|
8
8
|
export type { ScaleIndicatorProps } from './ScaleIndicator';
|
|
9
9
|
export { ScaleIndicator } from './ScaleIndicator';
|
|
10
|
-
export type { SidebarProps } from './Sidebar';
|
|
11
|
-
export { Sidebar } from './Sidebar';
|
|
12
10
|
export type { SplitProps } from './Split';
|
|
13
11
|
export { Split } from './Split';
|
|
14
12
|
export type { StatusBarProps, StatusBarSectionProps } from './StatusBar';
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import type { FillStyle, GradientFill, Track } from '@weasel-js/core';
|
|
2
2
|
import {
|
|
3
|
-
ActionsBar,
|
|
4
3
|
Badge,
|
|
5
4
|
type Band,
|
|
6
5
|
BandEditor,
|
|
7
6
|
Button,
|
|
7
|
+
ButtonBar,
|
|
8
8
|
Callout,
|
|
9
9
|
Checkbox,
|
|
10
|
-
CheckboxRow,
|
|
11
10
|
ColorField,
|
|
12
|
-
ColorRow,
|
|
13
11
|
ComboBox,
|
|
14
12
|
type ControlPoint,
|
|
15
13
|
CurveEditor,
|
|
@@ -24,11 +22,11 @@ import {
|
|
|
24
22
|
ItemList,
|
|
25
23
|
KeyCap,
|
|
26
24
|
KeySequence,
|
|
27
|
-
|
|
28
|
-
type
|
|
25
|
+
LayerList,
|
|
26
|
+
type LayerListItem,
|
|
29
27
|
MenuButton,
|
|
28
|
+
moveLayers,
|
|
30
29
|
NumberField,
|
|
31
|
-
NumberRow,
|
|
32
30
|
OptionsBar,
|
|
33
31
|
PaintInput,
|
|
34
32
|
Plot2D,
|
|
@@ -36,6 +34,7 @@ import {
|
|
|
36
34
|
Powerline,
|
|
37
35
|
type PrefGroup,
|
|
38
36
|
PrefsForm,
|
|
37
|
+
PropertyField,
|
|
39
38
|
PropertyGroup,
|
|
40
39
|
PropertyList,
|
|
41
40
|
PropertyPanel,
|
|
@@ -44,10 +43,9 @@ import {
|
|
|
44
43
|
RangeSlider,
|
|
45
44
|
ResizeHandle,
|
|
46
45
|
Select,
|
|
47
|
-
|
|
46
|
+
Sidebar,
|
|
48
47
|
SidebarPanel,
|
|
49
48
|
Slider,
|
|
50
|
-
SliderRow,
|
|
51
49
|
StatusBarItem,
|
|
52
50
|
StatusBarSpacer,
|
|
53
51
|
Switch,
|
|
@@ -55,18 +53,15 @@ import {
|
|
|
55
53
|
TabList,
|
|
56
54
|
TabPanel,
|
|
57
55
|
Tabs,
|
|
58
|
-
TextRow,
|
|
59
56
|
type Thumb,
|
|
60
57
|
Timeline,
|
|
61
58
|
ToastRegion,
|
|
62
59
|
ToggleBar,
|
|
63
|
-
ToggleRow,
|
|
64
60
|
ToolButton,
|
|
65
61
|
ToolGroup,
|
|
66
62
|
ToolOptionsBar,
|
|
67
63
|
Tooltip,
|
|
68
64
|
TooltipTrigger,
|
|
69
|
-
Sidebar as UiSidebar,
|
|
70
65
|
StatusBar as UiStatusBar,
|
|
71
66
|
} from '@weasel-js/ui';
|
|
72
67
|
import { type CSSProperties, type ReactNode, useId, useMemo, useRef, useState } from 'react';
|
|
@@ -76,7 +71,6 @@ import { FloatingPanel } from '../primitives/FloatingPanel';
|
|
|
76
71
|
import { JobProgress } from '../primitives/JobProgress';
|
|
77
72
|
import { Legend, type LegendEntry } from '../primitives/Legend';
|
|
78
73
|
import { ScaleIndicator } from '../primitives/ScaleIndicator';
|
|
79
|
-
import { Sidebar } from '../primitives/Sidebar';
|
|
80
74
|
import { Split } from '../primitives/Split';
|
|
81
75
|
import { StatusBar } from '../primitives/StatusBar';
|
|
82
76
|
import { Toolbar } from '../primitives/Toolbar';
|
|
@@ -213,19 +207,19 @@ function ButtonsAndToggles() {
|
|
|
213
207
|
</Cell>
|
|
214
208
|
<Cell label="Badge">
|
|
215
209
|
<div className="lk-specimen__row">
|
|
216
|
-
<Badge shape="pill"
|
|
210
|
+
<Badge shape="pill" status="accent" variant="outline" size="sm">
|
|
217
211
|
ACCENT
|
|
218
212
|
</Badge>
|
|
219
|
-
<Badge
|
|
213
|
+
<Badge status="info" variant="subtle">
|
|
220
214
|
INFO
|
|
221
215
|
</Badge>
|
|
222
|
-
<Badge
|
|
216
|
+
<Badge status="warn" variant="solid">
|
|
223
217
|
WARN
|
|
224
218
|
</Badge>
|
|
225
|
-
<Badge
|
|
219
|
+
<Badge status="danger" variant="solid">
|
|
226
220
|
DANGER
|
|
227
221
|
</Badge>
|
|
228
|
-
<Badge
|
|
222
|
+
<Badge status="muted">MUTED</Badge>
|
|
229
223
|
</div>
|
|
230
224
|
</Cell>
|
|
231
225
|
<Cell label="Checkbox, Switch">
|
|
@@ -269,7 +263,7 @@ function ButtonsAndToggles() {
|
|
|
269
263
|
]}
|
|
270
264
|
/>
|
|
271
265
|
</Cell>
|
|
272
|
-
<Cell label="OptionsBar,
|
|
266
|
+
<Cell label="OptionsBar, ButtonBar">
|
|
273
267
|
<div className="lk-specimen__row">
|
|
274
268
|
<OptionsBar
|
|
275
269
|
ariaLabel="Text style"
|
|
@@ -278,7 +272,7 @@ function ButtonsAndToggles() {
|
|
|
278
272
|
{ value: 'i', label: 'I', selected: italic, onChange: setItalic },
|
|
279
273
|
]}
|
|
280
274
|
/>
|
|
281
|
-
<
|
|
275
|
+
<ButtonBar
|
|
282
276
|
items={[
|
|
283
277
|
{ value: 'undo', label: 'Undo', onAction: () => {} },
|
|
284
278
|
{ value: 'redo', label: 'Redo', onAction: () => {} },
|
|
@@ -297,7 +291,6 @@ function ButtonsAndToggles() {
|
|
|
297
291
|
]}
|
|
298
292
|
/>
|
|
299
293
|
<Disclosure open={open} onToggle={() => setOpen((o) => !o)} label="Shapes" />
|
|
300
|
-
<Disclosure open={false} onToggle={() => {}} label="Down" direction="down" />
|
|
301
294
|
</div>
|
|
302
295
|
</Cell>
|
|
303
296
|
<Cell label="Tabs">
|
|
@@ -436,7 +429,7 @@ function PanelsAndRows() {
|
|
|
436
429
|
const [label, setLabel] = useState('Badge');
|
|
437
430
|
const [visible, setVisible] = useState(true);
|
|
438
431
|
const [prefs, setPrefs] = useState<Record<string, unknown>>({});
|
|
439
|
-
const [layers, setLayers] = useState<
|
|
432
|
+
const [layers, setLayers] = useState<LayerListItem[]>([
|
|
440
433
|
{ id: 'base', label: 'Base coat' },
|
|
441
434
|
{ id: 'wash', label: 'Wash' },
|
|
442
435
|
]);
|
|
@@ -446,7 +439,9 @@ function PanelsAndRows() {
|
|
|
446
439
|
<Cell label="PropertyPanel">
|
|
447
440
|
<PropertyPanel title="Shape">
|
|
448
441
|
<PropertyList>
|
|
449
|
-
<
|
|
442
|
+
<PropertyField
|
|
443
|
+
kind="number"
|
|
444
|
+
control="slider"
|
|
450
445
|
label="Opacity"
|
|
451
446
|
value={opacity}
|
|
452
447
|
min={0}
|
|
@@ -454,7 +449,9 @@ function PanelsAndRows() {
|
|
|
454
449
|
step={0.01}
|
|
455
450
|
onChange={setOpacity}
|
|
456
451
|
/>
|
|
457
|
-
<
|
|
452
|
+
<PropertyField
|
|
453
|
+
kind="number"
|
|
454
|
+
control="slider"
|
|
458
455
|
label="Radius"
|
|
459
456
|
value={radius}
|
|
460
457
|
min={0}
|
|
@@ -462,16 +459,18 @@ function PanelsAndRows() {
|
|
|
462
459
|
unit="px"
|
|
463
460
|
onChange={setRadius}
|
|
464
461
|
/>
|
|
465
|
-
<
|
|
462
|
+
<PropertyField
|
|
463
|
+
kind="color"
|
|
466
464
|
label="Fill"
|
|
467
465
|
value={fill}
|
|
468
466
|
onChange={setFill}
|
|
469
467
|
alpha={alpha}
|
|
470
468
|
onAlphaChange={setAlpha}
|
|
471
469
|
/>
|
|
472
|
-
<
|
|
473
|
-
<
|
|
474
|
-
<
|
|
470
|
+
<PropertyField kind="color" label="Stroke" value={stroke} onChange={setStroke} />
|
|
471
|
+
<PropertyField kind="number" label="Count" value={count} min={0} max={100} step={1} onChange={setCount} />
|
|
472
|
+
<PropertyField
|
|
473
|
+
kind="enum"
|
|
475
474
|
label="Line cap"
|
|
476
475
|
value={cap}
|
|
477
476
|
onChange={setCap}
|
|
@@ -480,7 +479,9 @@ function PanelsAndRows() {
|
|
|
480
479
|
{ value: 'round', label: 'Round' },
|
|
481
480
|
]}
|
|
482
481
|
/>
|
|
483
|
-
<
|
|
482
|
+
<PropertyField
|
|
483
|
+
kind="enum"
|
|
484
|
+
control="toggle"
|
|
484
485
|
label="Align"
|
|
485
486
|
value={side}
|
|
486
487
|
onChange={setSide}
|
|
@@ -490,10 +491,10 @@ function PanelsAndRows() {
|
|
|
490
491
|
{ value: 'right', label: 'R' },
|
|
491
492
|
]}
|
|
492
493
|
/>
|
|
493
|
-
<
|
|
494
|
-
<
|
|
494
|
+
<PropertyField kind="string" label="Label" value={label} onChange={setLabel} />
|
|
495
|
+
<PropertyField kind="boolean" label="Visible" value={visible} onChange={setVisible} />
|
|
495
496
|
<PropertyGroup title="Bevel" defaultCollapsed>
|
|
496
|
-
<
|
|
497
|
+
<PropertyField kind="number" control="slider" label="Rings" value={32} min={4} max={96} step={1} onChange={() => {}} />
|
|
497
498
|
</PropertyGroup>
|
|
498
499
|
</PropertyList>
|
|
499
500
|
</PropertyPanel>
|
|
@@ -505,18 +506,16 @@ function PanelsAndRows() {
|
|
|
505
506
|
onChange={(path, value) => setPrefs((prev) => setAt(prev, path, value))}
|
|
506
507
|
/>
|
|
507
508
|
</Cell>
|
|
508
|
-
<Cell label="
|
|
509
|
-
<
|
|
509
|
+
<Cell label="LayerList">
|
|
510
|
+
<LayerList
|
|
510
511
|
items={layers}
|
|
511
|
-
onReorder={(
|
|
512
|
-
setLayers(ids.flatMap((id) => layers.filter((item) => item.id === id)))
|
|
513
|
-
}
|
|
512
|
+
onReorder={(move) => setLayers(moveLayers(layers, move))}
|
|
514
513
|
renderBody={(item) => <div>settings for {item.label}</div>}
|
|
515
514
|
/>
|
|
516
515
|
</Cell>
|
|
517
516
|
<Cell label="Sidebar, SidebarPanel">
|
|
518
517
|
<div className="lk-specimen__box">
|
|
519
|
-
<
|
|
518
|
+
<Sidebar side="right" ariaLabel="Specimen sidebar">
|
|
520
519
|
<SidebarPanel
|
|
521
520
|
title="Selection"
|
|
522
521
|
collapsed={panelCollapsed}
|
|
@@ -525,7 +524,7 @@ function PanelsAndRows() {
|
|
|
525
524
|
>
|
|
526
525
|
<div className="lk-specimen__pad">2 items selected</div>
|
|
527
526
|
</SidebarPanel>
|
|
528
|
-
</
|
|
527
|
+
</Sidebar>
|
|
529
528
|
</div>
|
|
530
529
|
</Cell>
|
|
531
530
|
</Section>
|
|
@@ -554,8 +553,8 @@ function OverlaysAndFeedback() {
|
|
|
554
553
|
triggerRef={calloutAnchor}
|
|
555
554
|
isOpen={calloutOpen}
|
|
556
555
|
onOpenChange={setCalloutOpen}
|
|
557
|
-
|
|
558
|
-
title="
|
|
556
|
+
stance="notice"
|
|
557
|
+
title="Notice"
|
|
559
558
|
>
|
|
560
559
|
Neutral guidance.
|
|
561
560
|
</Callout>
|
|
@@ -587,9 +586,9 @@ function OverlaysAndFeedback() {
|
|
|
587
586
|
variant="solid"
|
|
588
587
|
size="sm"
|
|
589
588
|
segments={[
|
|
590
|
-
{ text: 'main',
|
|
591
|
-
{ text: '✓ 12',
|
|
592
|
-
{ text: '~/proj',
|
|
589
|
+
{ text: 'main', status: 'accent', endCap: 'chevron' },
|
|
590
|
+
{ text: '✓ 12', status: 'info', endCap: 'slant' },
|
|
591
|
+
{ text: '~/proj', status: 'muted' },
|
|
593
592
|
]}
|
|
594
593
|
/>
|
|
595
594
|
</Cell>
|
|
@@ -799,7 +798,6 @@ function EditorsAndPlots() {
|
|
|
799
798
|
}
|
|
800
799
|
|
|
801
800
|
function LabChrome() {
|
|
802
|
-
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
803
801
|
const [zoom, setZoom] = useState(1);
|
|
804
802
|
return (
|
|
805
803
|
<Section title="Lab chrome">
|
|
@@ -823,18 +821,6 @@ function LabChrome() {
|
|
|
823
821
|
<StatusBar.Section>Zoom: 100%</StatusBar.Section>
|
|
824
822
|
</StatusBar>
|
|
825
823
|
</Cell>
|
|
826
|
-
<Cell label="Sidebar">
|
|
827
|
-
<div className="lk-specimen__box">
|
|
828
|
-
<div className="lk-specimen__box-main">main</div>
|
|
829
|
-
<Sidebar
|
|
830
|
-
title="Controls"
|
|
831
|
-
collapsed={sidebarCollapsed}
|
|
832
|
-
onToggle={() => setSidebarCollapsed((v) => !v)}
|
|
833
|
-
>
|
|
834
|
-
<p>One slider</p>
|
|
835
|
-
</Sidebar>
|
|
836
|
-
</div>
|
|
837
|
-
</Cell>
|
|
838
824
|
<Cell label="Legend, JobProgress">
|
|
839
825
|
<Legend entries={LEGEND} />
|
|
840
826
|
<JobProgress job={JOB} />
|
package/src/state/types.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ColorModePreference } from '@weasel-js/theme';
|
|
1
2
|
import type { Auto } from '../config/auto';
|
|
2
3
|
import type { ConfigPath, ResolvedConfig, ValueAtPath } from '../config/types';
|
|
3
4
|
import type { InstrumentList } from '../instrument/types';
|
|
@@ -78,7 +79,7 @@ export interface SavedSnapshot {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/** `auto` follows the OS; the other two are an explicit choice. */
|
|
81
|
-
export type LabMode =
|
|
82
|
+
export type LabMode = ColorModePreference;
|
|
82
83
|
|
|
83
84
|
/** How much room the lab's own chrome takes — the theme's density axis, named
|
|
84
85
|
* the way the theme names it. A lab's instruments are unaffected: this sizes
|
package/src/styles.less
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// Imports compile-time only. Component .less files are added in later steps.
|
|
2
|
+
// Left as a CSS @import for the consumer's bundler to resolve; build-css.mjs
|
|
3
|
+
// swaps it for the faces themselves, pointed at dist/fonts/.
|
|
4
|
+
@import (css) '@weasel-js/theme/faces.css';
|
|
2
5
|
@import './theme/base.less';
|
|
3
6
|
@import './lab/Workspace.less';
|
|
4
7
|
@import './lab/LabShell.less';
|
|
5
8
|
@import './lab/LabSwitcher.less';
|
|
6
9
|
@import './primitives/Toolbar.less';
|
|
7
|
-
@import './primitives/Sidebar.less';
|
|
8
10
|
@import './primitives/Split.less';
|
|
9
11
|
@import './primitives/ZoomControl.less';
|
|
10
12
|
@import './primitives/StatusBar.less';
|
|
@@ -17,11 +19,11 @@
|
|
|
17
19
|
@import './trial/Trial.less';
|
|
18
20
|
@import './chrome/regions/ViewportRegion.less';
|
|
19
21
|
@import './chrome/regions/PaletteRegion.less';
|
|
22
|
+
@import './chrome/regions/SidebarRegion.less';
|
|
20
23
|
@import './controls/ControlPanel.less';
|
|
21
24
|
@import './canvas/CanvasStack.less';
|
|
22
25
|
@import './canvas/Stage.less';
|
|
23
26
|
@import './loupe/Loupe.less';
|
|
24
|
-
@import './layers/LayerList.less';
|
|
25
27
|
@import './annotations/Annotations.less';
|
|
26
28
|
@import './dragdrop/Palette.less';
|
|
27
29
|
@import './dragdrop/DragGhost.less';
|