@weasel-js/labkit 1.3.0-pre.0 → 1.3.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.
Files changed (110) hide show
  1. package/dist/_dts/{index-DgcNdEdh.d.ts → types-BttTIent.d.ts} +2 -2
  2. package/dist/_dts/{types-AHlQxBNN.d.ts → types-DCGEcMO_.d.ts} +1 -1
  3. package/dist/canvas/index.d.ts +2 -2
  4. package/dist/canvas/index.js +3 -2
  5. package/dist/chrome/index.d.ts +3 -3
  6. package/dist/chrome/index.js +6 -5
  7. package/dist/chunk-3XXPU73K.js +138 -0
  8. package/dist/chunk-3XXPU73K.js.map +1 -0
  9. package/dist/{chunk-PO6L3NSH.js → chunk-6X5RBC6G.js} +17 -17
  10. package/dist/chunk-6X5RBC6G.js.map +1 -0
  11. package/dist/{chunk-NS54R52R.js → chunk-BDJXIBRZ.js} +5 -17
  12. package/dist/chunk-BDJXIBRZ.js.map +1 -0
  13. package/dist/{chunk-V7PRSIRQ.js → chunk-BMW4TDP5.js} +4 -4
  14. package/dist/chunk-BMW4TDP5.js.map +1 -0
  15. package/dist/{chunk-O7NVSCLN.js → chunk-JDROYQM3.js} +8 -8
  16. package/dist/chunk-JDROYQM3.js.map +1 -0
  17. package/dist/{chunk-HFDVGF4X.js → chunk-LGKRIUSW.js} +3 -3
  18. package/dist/{chunk-HFDVGF4X.js.map → chunk-LGKRIUSW.js.map} +1 -1
  19. package/dist/{chunk-Z6HJ5FEM.js → chunk-QCICIHEO.js} +19 -7
  20. package/dist/{chunk-Z6HJ5FEM.js.map → chunk-QCICIHEO.js.map} +1 -1
  21. package/dist/{chunk-RVNN4CHQ.js → chunk-QRYPXSGP.js} +5 -5
  22. package/dist/{chunk-RVNN4CHQ.js.map → chunk-QRYPXSGP.js.map} +1 -1
  23. package/dist/chunk-RGT4EJIB.js +6961 -0
  24. package/dist/chunk-RGT4EJIB.js.map +1 -0
  25. package/dist/chunk-SBXNQW4G.js +3 -0
  26. package/dist/chunk-SBXNQW4G.js.map +1 -0
  27. package/dist/chunk-T66HU3HX.js +17 -0
  28. package/dist/chunk-T66HU3HX.js.map +1 -0
  29. package/dist/chunk-WTI26YTM.js +266 -0
  30. package/dist/chunk-WTI26YTM.js.map +1 -0
  31. package/dist/controls/index.d.ts +2 -2
  32. package/dist/controls/index.js +3 -3
  33. package/dist/dragdrop/index.d.ts +44 -3
  34. package/dist/dragdrop/index.js +3 -1
  35. package/dist/index.d.ts +571 -541
  36. package/dist/index.js +69 -541
  37. package/dist/index.js.map +1 -1
  38. package/dist/layers/index.d.ts +3 -3
  39. package/dist/layers/index.js +4 -2
  40. package/dist/passthrough/weasel-canvas.js +1 -1
  41. package/dist/passthrough/weasel-ui.d.ts +15 -2
  42. package/dist/passthrough/weasel-ui.js +3 -2
  43. package/dist/primitives/index.js +5 -4
  44. package/dist/styles.css +1 -703
  45. package/dist/surface/index.js +2 -2
  46. package/dist/ui/layers/index.d.ts +8 -2
  47. package/dist/ui/layers/index.js +2 -4
  48. package/dist/undo/index.d.ts +2 -2
  49. package/package.json +5 -5
  50. package/src/config/builder.test.ts +7 -1
  51. package/src/config/builder.ts +1 -5
  52. package/src/config/resolve.test.ts +1 -2
  53. package/src/controls/ControlPanel.stories.tsx +41 -2
  54. package/src/controls/ControlPanel.test.tsx +31 -9
  55. package/src/controls/ControlPanel.tsx +56 -22
  56. package/src/dragdrop/index.ts +11 -0
  57. package/src/index.ts +49 -2
  58. package/src/lab/index.ts +1 -1
  59. package/src/layers/AGENTS.md +1 -1
  60. package/src/layers/LayerList.tsx +1 -1
  61. package/src/passthrough/weasel-ui.ts +22 -17
  62. package/src/styles.less +0 -4
  63. package/src/theme/Interstellar.stories.tsx +1 -1
  64. package/src/trial/Trial.config.test.tsx +3 -8
  65. package/src/ui/layers/index.ts +5 -1
  66. package/dist/chunk-NS54R52R.js.map +0 -1
  67. package/dist/chunk-O2BULFHX.js +0 -152
  68. package/dist/chunk-O2BULFHX.js.map +0 -1
  69. package/dist/chunk-O7NVSCLN.js.map +0 -1
  70. package/dist/chunk-PO6L3NSH.js.map +0 -1
  71. package/dist/chunk-PQJ5B2U2.js +0 -27
  72. package/dist/chunk-PQJ5B2U2.js.map +0 -1
  73. package/dist/chunk-TLGRYALP.js +0 -6151
  74. package/dist/chunk-TLGRYALP.js.map +0 -1
  75. package/dist/chunk-V7PRSIRQ.js.map +0 -1
  76. package/dist/chunk-ZZAYVX4X.js +0 -505
  77. package/dist/chunk-ZZAYVX4X.js.map +0 -1
  78. package/src/primitives/DragHandleGlyph.tsx +0 -29
  79. package/src/ui/format.test.ts +0 -33
  80. package/src/ui/format.ts +0 -30
  81. package/src/ui/layers/LayerStack.less +0 -143
  82. package/src/ui/layers/LayerStack.stories.tsx +0 -45
  83. package/src/ui/layers/LayerStack.test.tsx +0 -170
  84. package/src/ui/layers/LayerStack.tsx +0 -208
  85. package/src/ui/properties/CheckboxRow.stories.tsx +0 -27
  86. package/src/ui/properties/ColorRow.stories.tsx +0 -106
  87. package/src/ui/properties/CurveField.less +0 -48
  88. package/src/ui/properties/CurveField.stories.tsx +0 -20
  89. package/src/ui/properties/CurveField.test.tsx +0 -127
  90. package/src/ui/properties/CurveField.tsx +0 -184
  91. package/src/ui/properties/EffectCard.tsx +0 -324
  92. package/src/ui/properties/Gallery.stories.tsx +0 -178
  93. package/src/ui/properties/NumberRow.stories.tsx +0 -65
  94. package/src/ui/properties/PropertyGroup.less +0 -50
  95. package/src/ui/properties/PropertyGroup.stories.tsx +0 -34
  96. package/src/ui/properties/PropertyGroup.test.tsx +0 -33
  97. package/src/ui/properties/PropertyGroup.tsx +0 -45
  98. package/src/ui/properties/PropertyList.stories.tsx +0 -83
  99. package/src/ui/properties/PropertyPanel.less +0 -606
  100. package/src/ui/properties/PropertyPanel.stories.tsx +0 -190
  101. package/src/ui/properties/PropertyPanel.test.tsx +0 -193
  102. package/src/ui/properties/PropertyPanel.tsx +0 -469
  103. package/src/ui/properties/PropertyRow.stories.tsx +0 -53
  104. package/src/ui/properties/SelectRow.stories.tsx +0 -58
  105. package/src/ui/properties/SliderRow.stories.tsx +0 -74
  106. package/src/ui/properties/SpeechBalloonPanels.stories.tsx +0 -398
  107. package/src/ui/properties/TextRow.stories.tsx +0 -62
  108. package/src/ui/properties/ToggleRow.stories.tsx +0 -57
  109. package/src/ui/properties/index.ts +0 -39
  110. package/src/ui/properties/storyLayouts.tsx +0 -36
@@ -1,5 +1,5 @@
1
1
  import { ComponentType, ReactNode } from 'react';
2
- import { R as ResolvedConfig, d as ConfigField, c as ConfigSchema } from './types-AHlQxBNN.js';
2
+ import { R as ResolvedConfig, C as ConfigField, a as ConfigSchema } from './types-DCGEcMO_.js';
3
3
  import { c as SavedSnapshot } from './types-1Sdxy_Pv.js';
4
4
  import { J as JobHandle, a as JobCapability } from './types-DJ79Tg5J.js';
5
5
 
@@ -311,4 +311,4 @@ interface Instrument<TS = unknown, TC = unknown, TItem = unknown> {
311
311
  * an `Instrument<unknown, unknown>[]`; it is contained to this alias. */
312
312
  type InstrumentList = readonly Instrument<any, any, any>[];
313
313
 
314
- export type { CanvasCapability as C, DragDropCapability as D, HitResult as H, Instrument as I, LayerCapability as L, PaletteItem as P, RenderContext as R, SidebarSection as S, TrialContribution as T, UndoCapability as U, ViewTransform as V, InstrumentList as a, TrialTool as b, CanvasLayer as c, DragFeedback as d, IconComponent as e, LayerDescriptor as f, Point as g, StatusReadout as h, SystemEvent as i, ToolCapability as j, ToolItem as k, ToolbarItem as l, TrialChromeContext as m, TrialRegion as n, ViewportControl as o };
314
+ export type { CanvasCapability as C, DragFeedback as D, HitResult as H, Instrument as I, LayerCapability as L, PaletteItem as P, RenderContext as R, SidebarSection as S, TrialContribution as T, UndoCapability as U, ViewTransform as V, Point as a, DragDropCapability as b, InstrumentList as c, TrialTool as d, CanvasLayer as e, IconComponent as f, LayerDescriptor as g, StatusReadout as h, SystemEvent as i, ToolCapability as j, ToolItem as k, ToolbarItem as l, TrialChromeContext as m, TrialRegion as n, ViewportControl as o };
@@ -159,4 +159,4 @@ interface ColorField extends ConfigFieldBase {
159
159
  * panel renders, and what `validateConfigSchema` checks. */
160
160
  type ConfigField = SliderField | CheckboxField | SelectField | NumberField | TextField | ColorField;
161
161
 
162
- export type { Annotations as A, ConfigNode as C, InferConfig as I, LeafPatch as L, NodeOptions as N, ResolvedConfig as R, SectionSpec as S, TextField as T, ControlRenderer as a, ConfigOption as b, ConfigSchema as c, ConfigField as d, ConfigRule as e, ConfigRuleContext as f, CheckboxField as g, ColorField as h, ConfigFieldBase as i, ConfigFieldType as j, ConfigOf as k, NodeValue as l, NumberField as m, SelectField as n, SelectOption as o, SliderField as p };
162
+ export type { Annotations as A, ConfigField as C, InferConfig as I, LeafPatch as L, NodeOptions as N, ResolvedConfig as R, SectionSpec as S, TextField as T, ConfigSchema as a, ConfigNode as b, ControlRenderer as c, ConfigOption as d, ConfigRule as e, ConfigRuleContext as f, CheckboxField as g, ColorField as h, ConfigFieldBase as i, ConfigFieldType as j, ConfigOf as k, NodeValue as l, NumberField as m, SelectField as n, SelectOption as o, SliderField as p };
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { V as ViewTransform, g as Point } from '../_dts/index-DgcNdEdh.js';
5
- import '../_dts/types-AHlQxBNN.js';
4
+ import { V as ViewTransform, a as Point } from '../_dts/types-BttTIent.js';
5
+ import '../_dts/types-DCGEcMO_.js';
6
6
  import '../_dts/PrefsForm-BYa6cWnO.js';
7
7
  import '../_dts/types-1Sdxy_Pv.js';
8
8
  import '../_dts/types-DJ79Tg5J.js';
@@ -1,5 +1,6 @@
1
- export { CanvasStack, screenToWorld, worldToScreen } from '../chunk-NS54R52R.js';
1
+ export { CanvasStack } from '../chunk-BDJXIBRZ.js';
2
+ export { screenToWorld, worldToScreen } from '../chunk-T66HU3HX.js';
2
3
  export { CanvasStackContext } from '../chunk-CPUJ3QXL.js';
3
- import '../chunk-Z6HJ5FEM.js';
4
+ import '../chunk-QCICIHEO.js';
4
5
  //# sourceMappingURL=index.js.map
5
6
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
- import { a as ControlRenderer } from '../_dts/types-AHlQxBNN.js';
2
- import { I as Instrument, m as TrialChromeContext, T as TrialContribution } from '../_dts/index-DgcNdEdh.js';
3
- export { e as IconComponent, S as SidebarSection, h as StatusReadout, k as ToolItem, l as ToolbarItem, n as TrialRegion, o as ViewportControl } from '../_dts/index-DgcNdEdh.js';
1
+ import { c as ControlRenderer } from '../_dts/types-DCGEcMO_.js';
2
+ import { I as Instrument, m as TrialChromeContext, T as TrialContribution } from '../_dts/types-BttTIent.js';
3
+ export { f as IconComponent, S as SidebarSection, h as StatusReadout, k as ToolItem, l as ToolbarItem, n as TrialRegion, o as ViewportControl } from '../_dts/types-BttTIent.js';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
  import '../_dts/PrefsForm-BYa6cWnO.js';
6
6
  import 'react';
@@ -1,8 +1,9 @@
1
- export { PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, mergeContributions, suppressContributions } from '../chunk-PO6L3NSH.js';
2
- import '../chunk-O7NVSCLN.js';
3
- import '../chunk-ZZAYVX4X.js';
4
- import '../chunk-TLGRYALP.js';
1
+ export { PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, mergeContributions, suppressContributions } from '../chunk-6X5RBC6G.js';
2
+ import '../chunk-JDROYQM3.js';
3
+ import '../chunk-WTI26YTM.js';
5
4
  import '../chunk-CPUJ3QXL.js';
6
- import '../chunk-Z6HJ5FEM.js';
5
+ import '../chunk-SBXNQW4G.js';
6
+ import '../chunk-RGT4EJIB.js';
7
+ import '../chunk-QCICIHEO.js';
7
8
  //# sourceMappingURL=index.js.map
8
9
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,138 @@
1
+ import { screenToWorld } from './chunk-T66HU3HX.js';
2
+ import { useVisibleRaf } from './chunk-QCICIHEO.js';
3
+ import { useState, useEffect, useRef, useCallback } from 'react';
4
+ import { createPortal } from 'react-dom';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ function DragGhost({ item, screenPos }) {
8
+ const [mounted, setMounted] = useState(false);
9
+ useEffect(() => setMounted(true), []);
10
+ if (!mounted || typeof document === "undefined") return null;
11
+ const style = {
12
+ left: `${screenPos.x + 12}px`,
13
+ top: `${screenPos.y + 12}px`
14
+ };
15
+ return createPortal(
16
+ /* @__PURE__ */ jsx("div", { className: "lk-drag-ghost", style, children: /* @__PURE__ */ jsx("span", { className: "lk-drag-ghost__label", children: item.label }) }),
17
+ document.body
18
+ );
19
+ }
20
+ function useDragDrop({
21
+ capability,
22
+ canvasContainerRef,
23
+ view,
24
+ state,
25
+ config,
26
+ setState,
27
+ emit
28
+ }) {
29
+ const [drag, setDrag] = useState(null);
30
+ const dragRef = useRef(null);
31
+ dragRef.current = drag;
32
+ const pendingPos = useRef(null);
33
+ const isOverCanvas = useCallback(
34
+ (screenPos) => {
35
+ const el = canvasContainerRef.current;
36
+ if (!el) return false;
37
+ const r = el.getBoundingClientRect();
38
+ return screenPos.x >= r.left && screenPos.x <= r.right && screenPos.y >= r.top && screenPos.y <= r.bottom;
39
+ },
40
+ [canvasContainerRef]
41
+ );
42
+ const screenToWorldFromContainer = useCallback(
43
+ (screenPos) => {
44
+ const el = canvasContainerRef.current;
45
+ if (!el) return null;
46
+ const r = el.getBoundingClientRect();
47
+ return screenToWorld({ x: screenPos.x - r.left, y: screenPos.y - r.top }, view);
48
+ },
49
+ [canvasContainerRef, view]
50
+ );
51
+ const frameLoop = useVisibleRaf(() => {
52
+ const screenPos = pendingPos.current;
53
+ pendingPos.current = null;
54
+ const active = dragRef.current;
55
+ if (!active || !screenPos) return;
56
+ let feedback = null;
57
+ if (capability.onDragOver && isOverCanvas(screenPos)) {
58
+ const world = screenToWorldFromContainer(screenPos);
59
+ if (world) feedback = capability.onDragOver(world, active.item, state, config);
60
+ }
61
+ setDrag({ ...active, screenPos, feedback });
62
+ });
63
+ useEffect(() => {
64
+ if (!drag) return;
65
+ const handleMove = (e) => {
66
+ const screenPos = { x: e.clientX, y: e.clientY };
67
+ const current = dragRef.current;
68
+ if (!current) return;
69
+ if (pendingPos.current !== null) {
70
+ pendingPos.current = screenPos;
71
+ dragRef.current = { ...current, screenPos };
72
+ setDrag(dragRef.current);
73
+ return;
74
+ }
75
+ pendingPos.current = screenPos;
76
+ frameLoop.request();
77
+ };
78
+ const handleUp = (e) => {
79
+ const screenPos = { x: e.clientX, y: e.clientY };
80
+ const active = dragRef.current;
81
+ if (!active) return;
82
+ pendingPos.current = null;
83
+ frameLoop.cancel();
84
+ if (isOverCanvas(screenPos)) {
85
+ const world = screenToWorldFromContainer(screenPos);
86
+ if (world) {
87
+ const nextState = capability.onDrop(world, active.item, state, config);
88
+ setState(nextState);
89
+ emit("canvas.itemAdded");
90
+ }
91
+ }
92
+ setDrag(null);
93
+ };
94
+ window.addEventListener("pointermove", handleMove);
95
+ window.addEventListener("pointerup", handleUp);
96
+ return () => {
97
+ window.removeEventListener("pointermove", handleMove);
98
+ window.removeEventListener("pointerup", handleUp);
99
+ };
100
+ }, [
101
+ drag,
102
+ capability,
103
+ state,
104
+ config,
105
+ setState,
106
+ emit,
107
+ frameLoop,
108
+ isOverCanvas,
109
+ screenToWorldFromContainer
110
+ ]);
111
+ const startDrag = useCallback((item, originScreenPos) => {
112
+ setDrag({ item, screenPos: originScreenPos, feedback: null });
113
+ }, []);
114
+ return { drag, startDrag };
115
+ }
116
+ function DragOverlay({ drag }) {
117
+ if (!drag) return null;
118
+ return /* @__PURE__ */ jsx(DragGhost, { item: drag.item, screenPos: drag.screenPos });
119
+ }
120
+ function Palette({ items, onDragStart, className }) {
121
+ return /* @__PURE__ */ jsx("div", { className: className ? `lk-palette ${className}` : "lk-palette", children: items.map((item) => /* @__PURE__ */ jsx(
122
+ "button",
123
+ {
124
+ type: "button",
125
+ className: "lk-palette__item",
126
+ onPointerDown: (e) => {
127
+ e.preventDefault();
128
+ onDragStart(item, { x: e.clientX, y: e.clientY });
129
+ },
130
+ children: /* @__PURE__ */ jsx("span", { className: "lk-palette__label", children: item.label })
131
+ },
132
+ item.id
133
+ )) });
134
+ }
135
+
136
+ export { DragGhost, DragOverlay, Palette, useDragDrop };
137
+ //# sourceMappingURL=chunk-3XXPU73K.js.map
138
+ //# sourceMappingURL=chunk-3XXPU73K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dragdrop/DragGhost.tsx","../src/dragdrop/DragDropRuntime.tsx","../src/dragdrop/Palette.tsx"],"names":["useState","useEffect","jsx"],"mappings":"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","file":"chunk-3XXPU73K.js","sourcesContent":["import { type ReactPortal, useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PaletteItem, Point } from '../instrument/types';\n\nexport interface DragGhostProps {\n item: PaletteItem;\n screenPos: Point;\n}\n\nexport function DragGhost({ item, screenPos }: DragGhostProps): ReactPortal | null {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n if (!mounted || typeof document === 'undefined') return null;\n const style = {\n left: `${screenPos.x + 12}px`,\n top: `${screenPos.y + 12}px`,\n };\n return createPortal(\n <div className=\"lk-drag-ghost\" style={style}>\n <span className=\"lk-drag-ghost__label\">{item.label}</span>\n </div>,\n document.body,\n );\n}\n","import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useCallback, useEffect, useRef, useState } from 'react';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport type {\n DragDropCapability,\n DragFeedback,\n PaletteItem,\n Point,\n ViewTransform,\n} from '../instrument/types';\nimport { DragGhost } from './DragGhost';\n\nexport interface DragState {\n item: PaletteItem;\n screenPos: Point;\n feedback: DragFeedback | null;\n}\n\nexport interface UseDragDropArgs<TS, TC> {\n capability: DragDropCapability<TS, TC>;\n canvasContainerRef: RefObject<HTMLElement | null>;\n view: ViewTransform;\n state: TS;\n config: TC;\n setState: (next: TS | ((prev: TS) => TS)) => void;\n emit: (event: string) => void;\n}\n\nexport interface UseDragDropResult {\n drag: DragState | null;\n startDrag: (item: PaletteItem, originScreenPos: Point) => void;\n}\n\nexport function useDragDrop<TS, TC>({\n capability,\n canvasContainerRef,\n view,\n state,\n config,\n setState,\n emit,\n}: UseDragDropArgs<TS, TC>): UseDragDropResult {\n const [drag, setDrag] = useState<DragState | null>(null);\n const dragRef = useRef<DragState | null>(null);\n dragRef.current = drag;\n /** The move the next frame will resolve. Doubles as the throttle's flag:\n * non-null means a frame is already queued. */\n const pendingPos = useRef<Point | null>(null);\n\n const isOverCanvas = useCallback(\n (screenPos: Point): boolean => {\n const el = canvasContainerRef.current;\n if (!el) return false;\n const r = el.getBoundingClientRect();\n return (\n screenPos.x >= r.left &&\n screenPos.x <= r.right &&\n screenPos.y >= r.top &&\n screenPos.y <= r.bottom\n );\n },\n [canvasContainerRef],\n );\n\n const screenToWorldFromContainer = useCallback(\n (screenPos: Point): Point | null => {\n const el = canvasContainerRef.current;\n if (!el) return null;\n const r = el.getBoundingClientRect();\n return screenToWorld({ x: screenPos.x - r.left, y: screenPos.y - r.top }, view);\n },\n [canvasContainerRef, view],\n );\n\n const frameLoop = useVisibleRaf(() => {\n const screenPos = pendingPos.current;\n pendingPos.current = null;\n const active = dragRef.current;\n if (!active || !screenPos) return;\n let feedback: DragFeedback | null = null;\n if (capability.onDragOver && isOverCanvas(screenPos)) {\n const world = screenToWorldFromContainer(screenPos);\n if (world) feedback = capability.onDragOver(world, active.item, state, config);\n }\n setDrag({ ...active, screenPos, feedback });\n });\n\n useEffect(() => {\n if (!drag) return;\n const handleMove = (e: PointerEvent) => {\n const screenPos = { x: e.clientX, y: e.clientY };\n const current = dragRef.current;\n if (!current) return;\n if (pendingPos.current !== null) {\n // A frame is already queued: keep the ghost under the cursor and let\n // that frame probe the drop target from the newest position.\n pendingPos.current = screenPos;\n dragRef.current = { ...current, screenPos };\n setDrag(dragRef.current);\n return;\n }\n pendingPos.current = screenPos;\n frameLoop.request();\n };\n const handleUp = (e: PointerEvent) => {\n const screenPos = { x: e.clientX, y: e.clientY };\n const active = dragRef.current;\n if (!active) return;\n pendingPos.current = null;\n frameLoop.cancel();\n if (isOverCanvas(screenPos)) {\n const world = screenToWorldFromContainer(screenPos);\n if (world) {\n const nextState = capability.onDrop(world, active.item, state, config);\n setState(nextState);\n emit('canvas.itemAdded');\n }\n }\n setDrag(null);\n };\n window.addEventListener('pointermove', handleMove);\n window.addEventListener('pointerup', handleUp);\n return () => {\n window.removeEventListener('pointermove', handleMove);\n window.removeEventListener('pointerup', handleUp);\n };\n }, [\n drag,\n capability,\n state,\n config,\n setState,\n emit,\n frameLoop,\n isOverCanvas,\n screenToWorldFromContainer,\n ]);\n\n const startDrag = useCallback((item: PaletteItem, originScreenPos: Point) => {\n setDrag({ item, screenPos: originScreenPos, feedback: null });\n }, []);\n\n return { drag, startDrag };\n}\n\nexport interface DragOverlayProps {\n drag: DragState | null;\n}\n\nexport function DragOverlay({ drag }: DragOverlayProps) {\n if (!drag) return null;\n return <DragGhost item={drag.item} screenPos={drag.screenPos} />;\n}\n","import type { PaletteItem, Point } from '../instrument/types';\n\nexport interface PaletteProps {\n items: PaletteItem[];\n onDragStart: (item: PaletteItem, originScreenPos: Point) => void;\n className?: string;\n}\n\nexport function Palette({ items, onDragStart, className }: PaletteProps) {\n return (\n <div className={className ? `lk-palette ${className}` : 'lk-palette'}>\n {items.map((item) => (\n <button\n type=\"button\"\n key={item.id}\n className=\"lk-palette__item\"\n onPointerDown={(e) => {\n e.preventDefault();\n onDragStart(item, { x: e.clientX, y: e.clientY });\n }}\n >\n <span className=\"lk-palette__label\">{item.label}</span>\n </button>\n ))}\n </div>\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { ZoomControl, ScaleIndicator, FpsMeter, StatusBar, Toolbar } from './chunk-O7NVSCLN.js';
2
- import { ControlPanel } from './chunk-ZZAYVX4X.js';
3
- import { St, Ct, wt, gt, Tt, Et, p2, ft, pt, mt, n3, o5 } from './chunk-TLGRYALP.js';
1
+ import { ZoomControl, ScaleIndicator, FpsMeter, StatusBar, Toolbar } from './chunk-JDROYQM3.js';
2
+ import { ControlPanel } from './chunk-WTI26YTM.js';
3
+ import { Ht, Ut, Wt, It2, Gt, Kt, p, Mt, Nt, Pt, n4, o4 } from './chunk-RGT4EJIB.js';
4
4
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
5
5
  import { useState } from 'react';
6
6
 
@@ -14,7 +14,7 @@ function builtinContributions(instrument, ctx, controls) {
14
14
  region: "toolbar",
15
15
  group: "history",
16
16
  item: {
17
- icon: St,
17
+ icon: Ht,
18
18
  label: "Undo",
19
19
  shortcut: "Mod+Z",
20
20
  disabled: !ctx.canUndo,
@@ -26,7 +26,7 @@ function builtinContributions(instrument, ctx, controls) {
26
26
  region: "toolbar",
27
27
  group: "history",
28
28
  item: {
29
- icon: Ct,
29
+ icon: Ut,
30
30
  label: "Redo",
31
31
  shortcut: "Mod+Shift+Z",
32
32
  disabled: !ctx.canRedo,
@@ -48,7 +48,7 @@ function builtinContributions(instrument, ctx, controls) {
48
48
  region: "viewport",
49
49
  group: "zoom",
50
50
  item: {
51
- icon: wt,
51
+ icon: Wt,
52
52
  label: "Zoom out",
53
53
  onActivate: () => ctx.setZoom(zoom / ZOOM_STEP)
54
54
  }
@@ -58,7 +58,7 @@ function builtinContributions(instrument, ctx, controls) {
58
58
  region: "viewport",
59
59
  group: "zoom",
60
60
  item: {
61
- icon: gt,
61
+ icon: It2,
62
62
  label: "Zoom in",
63
63
  onActivate: () => ctx.setZoom(zoom * ZOOM_STEP)
64
64
  }
@@ -67,7 +67,7 @@ function builtinContributions(instrument, ctx, controls) {
67
67
  id: "actual-size",
68
68
  region: "viewport",
69
69
  group: "zoom",
70
- item: { icon: Tt, label: "Actual size", onActivate: () => ctx.setZoom(1) }
70
+ item: { icon: Gt, label: "Actual size", onActivate: () => ctx.setZoom(1) }
71
71
  });
72
72
  out.push({
73
73
  id: "zoom-control",
@@ -112,7 +112,7 @@ function builtinContributions(instrument, ctx, controls) {
112
112
  region: "toolbar",
113
113
  group: "history",
114
114
  item: {
115
- icon: Et,
115
+ icon: Kt,
116
116
  label: "Save snapshot",
117
117
  shortcut: "Mod+S",
118
118
  onActivate: () => ctx.saveSnapshot()
@@ -125,7 +125,7 @@ function builtinContributions(instrument, ctx, controls) {
125
125
  group: "trial",
126
126
  end: true,
127
127
  render: (c) => /* @__PURE__ */ jsx(
128
- p2,
128
+ p,
129
129
  {
130
130
  className: "lk-toolbar__load-select",
131
131
  "aria-label": "Load snapshot",
@@ -144,21 +144,21 @@ function builtinContributions(instrument, ctx, controls) {
144
144
  region: "toolbar",
145
145
  group: "trial",
146
146
  end: true,
147
- item: { icon: ft, label: "Clone trial", onActivate: ctx.clone }
147
+ item: { icon: Mt, label: "Clone trial", onActivate: ctx.clone }
148
148
  });
149
149
  out.push({
150
150
  id: "reset",
151
151
  region: "toolbar",
152
152
  group: "trial",
153
153
  end: true,
154
- item: { icon: pt, label: "Reset trial", onActivate: ctx.reset }
154
+ item: { icon: Nt, label: "Reset trial", onActivate: ctx.reset }
155
155
  });
156
156
  out.push({
157
157
  id: "close",
158
158
  region: "titlebar",
159
159
  end: true,
160
160
  item: {
161
- icon: mt,
161
+ icon: Pt,
162
162
  label: ctx.isLastTrial ? "Cannot close the last trial" : "Close trial",
163
163
  danger: true,
164
164
  disabled: ctx.isLastTrial,
@@ -206,12 +206,12 @@ function PaletteRegion({ contributions, ctx }) {
206
206
  role: "toolbar",
207
207
  "aria-label": "Tools",
208
208
  "aria-orientation": "vertical",
209
- children: /* @__PURE__ */ jsx(n3, { orientation: "vertical", children: contributions.map((c) => {
209
+ children: /* @__PURE__ */ jsx(n4, { orientation: "vertical", children: contributions.map((c) => {
210
210
  if (c.render) return /* @__PURE__ */ jsx("span", { children: c.render(ctx) }, c.id);
211
211
  if (c.region !== "palette" || !c.item) return null;
212
212
  const { icon: Icon, label, shortcut, disabled } = c.item;
213
213
  return /* @__PURE__ */ jsx(
214
- o5,
214
+ o4,
215
215
  {
216
216
  icon: /* @__PURE__ */ jsx(Icon, { size: 16 }),
217
217
  label,
@@ -362,5 +362,5 @@ function ViewportRegion({ contributions, ctx }) {
362
362
  }
363
363
 
364
364
  export { PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, mergeContributions, suppressContributions };
365
- //# sourceMappingURL=chunk-PO6L3NSH.js.map
366
- //# sourceMappingURL=chunk-PO6L3NSH.js.map
365
+ //# sourceMappingURL=chunk-6X5RBC6G.js.map
366
+ //# sourceMappingURL=chunk-6X5RBC6G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/chrome/builtins.tsx","../src/chrome/merge.ts","../src/chrome/regions/PaletteRegion.tsx","../src/chrome/regions/SidebarRegion.tsx","../src/chrome/regions/StatusRegion.tsx","../src/chrome/regions/TitleBarRegion.tsx","../src/chrome/regions/ToolbarRegion.tsx","../src/chrome/regions/ViewportRegion.tsx"],"names":["It","jsx","n","o","renderEntry","jsxs"],"mappings":"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","file":"chunk-6X5RBC6G.js","sourcesContent":["import {\n CloneIcon,\n CloseIcon,\n FitIcon,\n RedoIcon,\n ResetIcon,\n SnapshotIcon,\n UndoIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@weasel-js/ui';\nimport type { ControlRenderer } from '../config/types';\nimport { ControlPanel } from '../controls/ControlPanel';\nimport type { Instrument } from '../instrument/types';\nimport { Select } from '../passthrough/weasel-ui';\nimport { FpsMeter } from '../primitives/FpsMeter';\nimport { ScaleIndicator } from '../primitives/ScaleIndicator';\nimport { ZoomControl } from '../primitives/ZoomControl';\nimport type { TrialChromeContext, TrialContribution } from './types';\n\nconst ZOOM_STEP = 1.25;\n\n/**\n * The contributions a trial gets from what its instrument declared. This is\n * the whole \"declaring a capability provides the chrome\" rule — it replaces\n * the presence checks that used to be spread across the runtime.\n */\nexport function builtinContributions(\n instrument: Instrument,\n ctx: TrialChromeContext,\n controls?: Record<string, ControlRenderer>,\n): TrialContribution[] {\n const out: TrialContribution[] = [];\n const zoom = ctx.zoom;\n\n if (instrument.undo != null) {\n out.push({\n id: 'undo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: UndoIcon,\n label: 'Undo',\n shortcut: 'Mod+Z',\n disabled: !ctx.canUndo,\n onActivate: ctx.undo,\n },\n });\n out.push({\n id: 'redo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: RedoIcon,\n label: 'Redo',\n shortcut: 'Mod+Shift+Z',\n disabled: !ctx.canRedo,\n onActivate: ctx.redo,\n },\n });\n }\n\n // A tool id shares the contribution namespace, so a tool called `close`\n // collides with the built-in close button and throws. Both are contributions\n // to one trial's chrome.\n for (const t of instrument.tools?.tools ?? []) {\n out.push({\n id: t.id,\n region: 'palette',\n group: t.group,\n item: { icon: t.icon, label: t.label, shortcut: t.shortcut },\n });\n }\n\n // Zoom acts on the view of the trial, so it is a viewport control. A trial\n // holding a non-2D view reports zoom as null and gets none of this.\n if (instrument.canvas != null && zoom !== null) {\n out.push({\n id: 'zoom-out',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomOutIcon,\n label: 'Zoom out',\n onActivate: () => ctx.setZoom(zoom / ZOOM_STEP),\n },\n });\n out.push({\n id: 'zoom-in',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomInIcon,\n label: 'Zoom in',\n onActivate: () => ctx.setZoom(zoom * ZOOM_STEP),\n },\n });\n out.push({\n id: 'actual-size',\n region: 'viewport',\n group: 'zoom',\n item: { icon: FitIcon, label: 'Actual size', onActivate: () => ctx.setZoom(1) },\n });\n out.push({\n id: 'zoom-control',\n region: 'viewport',\n group: 'zoom',\n render: (c) => <ZoomControl zoom={c.zoom ?? 1} onZoomChange={c.setZoom} />,\n });\n out.push({\n id: 'scale',\n region: 'status',\n group: 'view',\n render: () => <ScaleIndicator />,\n });\n out.push({\n id: 'fps',\n region: 'status',\n group: 'view',\n end: true,\n render: () => <FpsMeter />,\n });\n }\n\n if (Object.keys(ctx.configSchema.group.children).length > 0) {\n out.push({\n id: 'settings',\n region: 'sidebar',\n item: {\n title: 'Settings',\n body: (\n <ControlPanel\n schema={ctx.configSchema}\n config={ctx.config as Record<string, unknown>}\n setConfig={(key, value) => ctx.setConfig(String(key), value)}\n renderers={controls}\n />\n ),\n },\n });\n }\n\n out.push({\n id: 'snapshot',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: SnapshotIcon,\n label: 'Save snapshot',\n shortcut: 'Mod+S',\n onActivate: () => ctx.saveSnapshot(),\n },\n });\n if (ctx.savedSnapshots.length > 0) {\n // A picker is not an icon button, so it takes the render escape. Held at\n // `selectedKey={null}` so it stays a \"load one\" action rather than\n // drifting into a display of what was loaded last.\n out.push({\n id: 'snapshot-load',\n region: 'toolbar',\n group: 'trial',\n end: true,\n render: (c) => (\n <Select\n className=\"lk-toolbar__load-select\"\n aria-label=\"Load snapshot\"\n placeholder=\"Load…\"\n selectedKey={null}\n options={c.savedSnapshots.map((sn) => ({ value: sn.id, label: sn.name }))}\n onSelectionChange={(id) => {\n if (id != null) c.loadSnapshot(String(id));\n }}\n />\n ),\n });\n }\n out.push({\n id: 'clone',\n region: 'toolbar',\n group: 'trial',\n end: true,\n item: { icon: CloneIcon, label: 'Clone trial', onActivate: ctx.clone },\n });\n out.push({\n id: 'reset',\n region: 'toolbar',\n group: 'trial',\n end: true,\n item: { icon: ResetIcon, label: 'Reset trial', onActivate: ctx.reset },\n });\n out.push({\n id: 'close',\n region: 'titlebar',\n end: true,\n item: {\n icon: CloseIcon,\n label: ctx.isLastTrial ? 'Cannot close the last trial' : 'Close trial',\n danger: true,\n disabled: ctx.isLastTrial,\n onActivate: ctx.close,\n },\n });\n\n return out;\n}\n","import type { TrialContribution } from './types';\n\n/**\n * Concatenate contribution bundles into one list, preserving order — order\n * decides how a region lays its contributions out, so it is part of the\n * result, not an accident of it.\n *\n * Throws on a duplicate id rather than dropping one: a contribution silently\n * losing to a later bundle is the failure a registry exists to prevent.\n */\nexport function mergeContributions(\n ...bundles: readonly TrialContribution[][]\n): TrialContribution[] {\n const out: TrialContribution[] = [];\n const seen = new Set<string>();\n for (const bundle of bundles) {\n for (const entry of bundle) {\n if (seen.has(entry.id)) {\n throw new Error(\n `[labkit] mergeContributions: duplicate contribution id \"${entry.id}\". ` +\n 'Two bundles registered the same id; rename one, or suppress the ' +\n 'built-in before adding yours.',\n );\n }\n seen.add(entry.id);\n out.push(entry);\n }\n }\n return out;\n}\n\n/**\n * Drop contributions by id. Throws when an id is not present: a typo that\n * silently suppresses nothing is the same class of bug as a duplicate id\n * silently winning.\n */\nexport function suppressContributions(\n bundle: readonly TrialContribution[],\n ids: readonly string[],\n): TrialContribution[] {\n const present = new Set(bundle.map((c) => c.id));\n for (const id of ids) {\n if (!present.has(id)) {\n throw new Error(\n `[labkit] cannot suppress \"${id}\": no contribution with that id. ` +\n `Present ids: ${[...present].join(', ')}`,\n );\n }\n }\n const drop = new Set(ids);\n return bundle.filter((c) => !drop.has(c.id));\n}\n","import { ToolButton, ToolGroup } from '../../passthrough/weasel-ui';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<PaletteRegion>`. */\nexport interface PaletteRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\n/** A trial's tool strip. Selection lives in the trial's or the lab's tool\n * slot; this region only reflects it. */\nexport function PaletteRegion({ contributions, ctx }: PaletteRegionProps) {\n if (contributions.length === 0) return null;\n return (\n <div\n className=\"lk-palette-region\"\n role=\"toolbar\"\n aria-label=\"Tools\"\n aria-orientation=\"vertical\"\n >\n <ToolGroup orientation=\"vertical\">\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'palette' || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled } = c.item;\n return (\n <ToolButton\n key={c.id}\n icon={<Icon size={16} />}\n label={label}\n shortcut={shortcut}\n active={ctx.activeToolId === c.id}\n disabled={disabled}\n onClick={() => ctx.setActiveTool(c.id)}\n />\n );\n })}\n </ToolGroup>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport { useState } from 'react';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<SidebarRegion>`. */\nexport interface SidebarRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\nfunction Section({\n title,\n defaultCollapsed,\n children,\n}: {\n title: string;\n defaultCollapsed: boolean;\n children: ReactNode;\n}) {\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n return (\n <section className=\"lk-sidebar-section\">\n <button\n type=\"button\"\n className=\"lk-sidebar-section__head\"\n aria-expanded={!collapsed}\n onClick={() => setCollapsed((c) => !c)}\n >\n {title}\n </button>\n {collapsed ? null : <div className=\"lk-sidebar-section__body\">{children}</div>}\n </section>\n );\n}\n\n/** Lays a trial's `sidebar` contributions out as titled, collapsible sections. */\nexport function SidebarRegion({ contributions, ctx }: SidebarRegionProps) {\n if (contributions.length === 0) return null;\n return (\n <>\n {contributions.map((c) => {\n if (c.render) return <div key={c.id}>{c.render(ctx)}</div>;\n if (c.region !== 'sidebar' || !c.item) return null;\n return (\n <Section\n key={c.id}\n title={c.item.title}\n defaultCollapsed={c.item.defaultCollapsed ?? false}\n >\n {c.item.body}\n </Section>\n );\n })}\n </>\n );\n}\n","import { StatusBar } from '../../primitives/StatusBar';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<StatusRegion>`. */\nexport interface StatusRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\n/** Lays a trial's `status` contributions out as readouts. */\nexport function StatusRegion({ contributions, ctx }: StatusRegionProps) {\n if (contributions.length === 0) return null;\n return (\n <StatusBar>\n {contributions.map((c) => {\n if (c.render)\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n {c.render(ctx)}\n </StatusBar.Section>\n );\n if (c.region !== 'status' || !c.item) return null;\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n <span title={c.item.title}>{c.item.text}</span>\n </StatusBar.Section>\n );\n })}\n </StatusBar>\n );\n}\n","import type { ReactNode } from 'react';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<TitleBarRegion>`. */\nexport interface TitleBarRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\nfunction renderEntry(c: TrialContribution, ctx: TrialChromeContext): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'titlebar' || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, danger } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className={`lk-titlebar-button${danger ? ' lk-titlebar-button--danger' : ''}`}\n disabled={disabled}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={c.item.onActivate}\n // The bar behind these buttons is the window drag surface, so a press\n // that lands here must not also start a drag.\n onPointerDown={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <Icon size={14} />\n </button>\n );\n}\n\n/** Lays a trial's `titlebar` contributions out, at the far end of the bar. */\nexport function TitleBarRegion({ contributions, ctx }: TitleBarRegionProps) {\n if (contributions.length === 0) return null;\n return (\n <span className=\"lk-trial__titlebar-actions\">\n {contributions.map((c) => renderEntry(c, ctx))}\n </span>\n );\n}\n","import type { ReactNode } from 'react';\nimport { Toolbar } from '../../primitives/Toolbar';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<ToolbarRegion>`. */\nexport interface ToolbarRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\ninterface Group {\n key: string;\n end: boolean;\n entries: TrialContribution[];\n}\n\n/** Bucket by group, preserving first-appearance order. Ungrouped\n * contributions each become their own bucket so they stay in place. */\nfunction groupsOf(contributions: readonly TrialContribution[]): Group[] {\n const groups: Group[] = [];\n const byKey = new Map<string, Group>();\n for (const c of contributions) {\n if (c.group == null) {\n groups.push({ key: c.id, end: c.end ?? false, entries: [c] });\n continue;\n }\n let g = byKey.get(c.group);\n if (!g) {\n g = { key: c.group, end: c.end ?? false, entries: [] };\n byKey.set(c.group, g);\n groups.push(g);\n }\n g.entries.push(c);\n }\n return groups;\n}\n\nfunction renderEntry(c: TrialContribution, ctx: TrialChromeContext): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'toolbar' || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, danger, showLabel } = c.item;\n return (\n <Toolbar.Button\n key={c.id}\n iconOnly={!showLabel}\n variant={danger ? 'danger' : 'default'}\n disabled={disabled}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={c.item.onActivate}\n >\n <Icon size={16} />\n {showLabel ? <span>{label}</span> : null}\n </Toolbar.Button>\n );\n}\n\n/** Lays a trial's `toolbar` contributions out, grouped by their `group`. */\nexport function ToolbarRegion({ contributions, ctx }: ToolbarRegionProps) {\n if (contributions.length === 0) return null;\n const groups = groupsOf(contributions);\n return (\n <Toolbar aria-label=\"Trial actions\">\n {groups.map((g) => (\n <Toolbar.Group key={g.key} end={g.end} aria-label={g.key}>\n {g.entries.map((c) => renderEntry(c, ctx))}\n </Toolbar.Group>\n ))}\n </Toolbar>\n );\n}\n","import type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<ViewportRegion>`. */\nexport interface ViewportRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\n/**\n * Controls acting on the view of a trial. Anchored inside the content well\n * rather than in the toolbar, which acts on the trial itself.\n */\nexport function ViewportRegion({ contributions, ctx }: ViewportRegionProps) {\n if (contributions.length === 0) return null;\n return (\n <div className=\"lk-viewport-controls\" role=\"toolbar\" aria-label=\"View\">\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'viewport' || !c.item) return null;\n const { icon: Icon, label, disabled } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className=\"lk-viewport-controls__button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={c.item.onActivate}\n >\n <Icon size={16} />\n </button>\n );\n })}\n </div>\n );\n}\n"]}
@@ -1,21 +1,9 @@
1
+ import { screenToWorld } from './chunk-T66HU3HX.js';
1
2
  import { CanvasStackContext } from './chunk-CPUJ3QXL.js';
2
- import { useVisibleRaf } from './chunk-Z6HJ5FEM.js';
3
+ import { useVisibleRaf } from './chunk-QCICIHEO.js';
3
4
  import { useRef, useState, useEffect, useMemo, useCallback } from 'react';
4
5
  import { jsx, jsxs } from 'react/jsx-runtime';
5
6
 
6
- // src/canvas/canvasCoords.ts
7
- function worldToScreen(world, view) {
8
- return {
9
- x: world.x * view.zoom + view.pan.x,
10
- y: world.y * view.zoom + view.pan.y
11
- };
12
- }
13
- function screenToWorld(screen, view) {
14
- return {
15
- x: (screen.x - view.pan.x) / view.zoom,
16
- y: (screen.y - view.pan.y) / view.zoom
17
- };
18
- }
19
7
  function useLayerScheduler({
20
8
  layers,
21
9
  view,
@@ -227,6 +215,6 @@ function CanvasStack({
227
215
  ) });
228
216
  }
229
217
 
230
- export { CanvasStack, screenToWorld, worldToScreen };
231
- //# sourceMappingURL=chunk-NS54R52R.js.map
232
- //# sourceMappingURL=chunk-NS54R52R.js.map
218
+ export { CanvasStack };
219
+ //# sourceMappingURL=chunk-BDJXIBRZ.js.map
220
+ //# sourceMappingURL=chunk-BDJXIBRZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/canvas/useLayerScheduler.ts","../src/canvas/usePanZoom.ts","../src/canvas/CanvasStack.tsx"],"names":["useRef","useEffect"],"mappings":"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","file":"chunk-BDJXIBRZ.js","sourcesContent":["import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\n\n/** One layer of a canvas stack: its id, whether it is currently shown, and how\n * it paints itself. */\nexport interface CanvasLayerDescriptor {\n id: string;\n visible: boolean;\n render: (ctx: CanvasRenderingContext2D, view: ViewTransform) => void;\n}\n\ninterface SchedulerOptions {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n canvasRefs: RefObject<Map<string, HTMLCanvasElement>>;\n size: { width: number; height: number; dpr: number };\n /** The element the stack occupies. Given one, the scheduler also stops while\n * the stack sits outside the viewport. */\n host?: RefObject<Element | null>;\n}\n\nexport function useLayerScheduler({\n layers,\n view,\n canvasRefs,\n size,\n host,\n}: SchedulerOptions): void {\n const dirty = useRef<Set<string>>(new Set());\n const lastRenderRef = useRef<Map<string, CanvasLayerDescriptor['render']>>(new Map());\n\n useEffect(() => {\n for (const layer of layers) {\n const prev = lastRenderRef.current.get(layer.id);\n if (prev !== layer.render) dirty.current.add(layer.id);\n lastRenderRef.current.set(layer.id, layer.render);\n }\n for (const id of [...lastRenderRef.current.keys()]) {\n if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);\n }\n }, [layers]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-mark dirty when view or size changes\n useEffect(() => {\n for (const layer of layers) dirty.current.add(layer.id);\n }, [view, size, layers]);\n\n // Painting only what is dirty is not the same as doing nothing: a hidden tab\n // still commits React updates, and the effect above marks every layer dirty\n // on any view or size change. The gate is what actually stops the work.\n const frameLoop = useVisibleRaf(\n () => {\n if (dirty.current.size === 0) return;\n const map = canvasRefs.current;\n if (!map) {\n dirty.current.clear();\n return;\n }\n for (const layer of layers) {\n if (!dirty.current.has(layer.id)) continue;\n if (!layer.visible) continue;\n const canvas = map.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n ctx.save();\n ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);\n ctx.clearRect(0, 0, size.width, size.height);\n layer.render(ctx, view);\n ctx.restore();\n }\n dirty.current.clear();\n },\n { target: host },\n );\n\n useEffect(() => {\n if (dirty.current.size > 0) frameLoop.request();\n });\n}\n","import { type PointerEvent, useCallback, useRef, type WheelEvent } from 'react';\nimport type { ViewTransform } from '../instrument/types';\n\nexport interface UsePanZoomOptions {\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The opening `view.zoom` always stays reachable, widening these past\n * whatever is passed here if it would otherwise exclude it. */\n minZoom?: number;\n maxZoom?: number;\n}\n\nexport interface PanZoomHandlers {\n onWheel: (e: WheelEvent<HTMLElement>) => void;\n onPointerDown: (e: PointerEvent<HTMLElement>) => void;\n onPointerMove: (e: PointerEvent<HTMLElement>) => void;\n onPointerUp: (e: PointerEvent<HTMLElement>) => void;\n isDragging: () => boolean;\n}\n\ninterface DragState {\n pointerId: number;\n startScreenX: number;\n startScreenY: number;\n startPan: { x: number; y: number };\n moved: boolean;\n}\n\nconst DRAG_THRESHOLD = 3;\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n\nexport function usePanZoom({\n view,\n onViewChange,\n minZoom = 0.1,\n maxZoom = 32,\n}: UsePanZoomOptions): PanZoomHandlers {\n const dragRef = useRef<DragState | null>(null);\n const viewRef = useRef(view);\n viewRef.current = view;\n // Captured once, from the view the canvas opened at — not the current view,\n // which would let a prior zoom-out shrink the range and trap the opening\n // view unreachable behind it.\n const initialZoomRef = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);\n\n const onWheel = useCallback(\n (e: WheelEvent<HTMLElement>) => {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n const cursorX = e.clientX - rect.left;\n const cursorY = e.clientY - rect.top;\n const v = viewRef.current;\n const initialZoom = initialZoomRef.current;\n const effectiveMin = initialZoom == null ? minZoom : Math.min(minZoom, initialZoom);\n const effectiveMax = initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom);\n const factor = Math.exp(-e.deltaY * 0.001);\n const rawZoom = isPositiveFinite(v.zoom) ? v.zoom : 1;\n const nextZoom = Math.min(effectiveMax, Math.max(effectiveMin, rawZoom * factor));\n const ratio = nextZoom / rawZoom;\n const nextPan = {\n x: cursorX - (cursorX - v.pan.x) * ratio,\n y: cursorY - (cursorY - v.pan.y) * ratio,\n };\n onViewChange({ zoom: nextZoom, pan: nextPan });\n },\n [onViewChange, minZoom, maxZoom],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLElement>) => {\n if (e.button !== 0) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragRef.current = {\n pointerId: e.pointerId,\n startScreenX: e.clientX,\n startScreenY: e.clientY,\n startPan: { ...viewRef.current.pan },\n moved: false,\n };\n }, []);\n\n const onPointerMove = useCallback(\n (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n const dx = e.clientX - drag.startScreenX;\n const dy = e.clientY - drag.startScreenY;\n if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n drag.moved = true;\n onViewChange({\n zoom: viewRef.current.zoom,\n pan: { x: drag.startPan.x + dx, y: drag.startPan.y + dy },\n });\n },\n [onViewChange],\n );\n\n const onPointerUp = useCallback((e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n dragRef.current = null;\n }, []);\n\n const isDragging = useCallback(() => dragRef.current?.moved === true, []);\n\n return { onWheel, onPointerDown, onPointerMove, onPointerUp, isDragging };\n}\n","import { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { CanvasStackContext } from './CanvasStackContext';\nimport { screenToWorld } from './canvasCoords';\nimport { type CanvasLayerDescriptor, useLayerScheduler } from './useLayerScheduler';\nimport { usePanZoom } from './usePanZoom';\n\n/** Props for `<CanvasStack>`. */\nexport interface CanvasStackProps {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n minZoom?: number;\n maxZoom?: number;\n width?: number | string;\n height?: number | string;\n className?: string;\n onHitTest?: (worldPos: Point) => void;\n children?: ReactNode;\n}\n\n/** Stacks one `<canvas>` per layer and drives them from a shared view, so a\n * layer that changes rarely is not redrawn with one that changes every frame.\n * Handles sizing, device pixel ratio, and pan/zoom. */\nexport function CanvasStack({\n layers,\n view,\n onViewChange,\n minZoom,\n maxZoom,\n width = '100%',\n height = '100%',\n className,\n onHitTest,\n children,\n}: CanvasStackProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const canvasMap = useRef<Map<string, HTMLCanvasElement>>(new Map());\n const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });\n\n const setCanvasRef = (id: string, el: HTMLCanvasElement | null): void => {\n if (el) canvasMap.current.set(id, el);\n else canvasMap.current.delete(id);\n };\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => {\n const rect = el.getBoundingClientRect();\n const dpr = window.devicePixelRatio ?? 1;\n setSize((prev) => {\n if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {\n return prev;\n }\n return { width: rect.width, height: rect.height, dpr };\n });\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const handlers = usePanZoom({ view, onViewChange, minZoom, maxZoom });\n useLayerScheduler({ layers, view, canvasRefs: canvasMap, size, host: containerRef });\n\n const ctxValue = useMemo(() => ({ view }), [view]);\n\n const containerStyle: CSSProperties = { width, height };\n const canvasPx = {\n width: Math.max(0, Math.round(size.width * size.dpr)),\n height: Math.max(0, Math.round(size.height * size.dpr)),\n };\n const canvasCss: CSSProperties = {\n width: size.width,\n height: size.height,\n };\n\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n const wasDragging = handlers.isDragging();\n handlers.onPointerUp(e);\n if (!wasDragging && onHitTest && containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n onHitTest(screenToWorld(screen, view));\n }\n };\n\n return (\n <CanvasStackContext.Provider value={ctxValue}>\n <div\n ref={containerRef}\n className={className ? `lk-canvas-stack ${className}` : 'lk-canvas-stack'}\n style={containerStyle}\n onWheel={handlers.onWheel}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlePointerUp}\n >\n {layers.map((layer) => (\n <canvas\n key={layer.id}\n ref={(el) => setCanvasRef(layer.id, el)}\n className=\"lk-canvas-stack__canvas\"\n width={canvasPx.width}\n height={canvasPx.height}\n style={{ ...canvasCss, display: layer.visible ? 'block' : 'none' }}\n />\n ))}\n <div className=\"lk-canvas-stack__overlay\">{children}</div>\n </div>\n </CanvasStackContext.Provider>\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { DragHandleGlyph } from './chunk-PQJ5B2U2.js';
1
+ import { n2 } from './chunk-RGT4EJIB.js';
2
2
  import { useState, useRef } from 'react';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4
 
@@ -63,7 +63,7 @@ function LayerList({ layers, visibility, onReorder, onToggle, className }) {
63
63
  onPointerDown: (e) => startDrag(e, i),
64
64
  onPointerMove: moveDrag,
65
65
  onPointerUp: endDrag,
66
- children: /* @__PURE__ */ jsx(DragHandleGlyph, { size: 13 })
66
+ children: /* @__PURE__ */ jsx(n2, { size: 13 })
67
67
  }
68
68
  ),
69
69
  /* @__PURE__ */ jsx(
@@ -90,5 +90,5 @@ function LayerList({ layers, visibility, onReorder, onToggle, className }) {
90
90
  }
91
91
 
92
92
  export { LayerList };
93
- //# sourceMappingURL=chunk-V7PRSIRQ.js.map
94
- //# sourceMappingURL=chunk-V7PRSIRQ.js.map
93
+ //# sourceMappingURL=chunk-BMW4TDP5.js.map
94
+ //# sourceMappingURL=chunk-BMW4TDP5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/layers/LayerList.tsx"],"names":["n"],"mappings":"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","file":"chunk-BMW4TDP5.js","sourcesContent":["import { type PointerEvent, useRef, useState } from 'react';\nimport type { LayerDescriptor } from '../instrument/types';\nimport { DragHandleGlyph } from '../passthrough/weasel-ui';\n\n/** Props for `<LayerList>`. */\nexport interface LayerListProps {\n layers: LayerDescriptor[];\n visibility: Record<string, boolean>;\n onReorder: (newOrder: LayerDescriptor[]) => void;\n onToggle: (id: string, visible: boolean) => void;\n className?: string;\n}\n\ninterface DragState {\n pointerId: number;\n fromIndex: number;\n startY: number;\n /** Row height plus row gap, measured when the drag starts. */\n pitch: number;\n}\n\n/** A reorderable list of layers with per-layer visibility toggles. Layers\n * marked `alwaysOn` are pinned and cannot be reordered or hidden. */\nexport function LayerList({ layers, visibility, onReorder, onToggle, className }: LayerListProps) {\n const reorderable = layers.filter((l) => !l.alwaysOn);\n const pinned = layers.filter((l) => l.alwaysOn);\n const [dragIndex, setDragIndex] = useState<number | null>(null);\n const dragRef = useRef<DragState | null>(null);\n\n if (layers.length === 0) {\n return (\n <div className={className ? `lk-layer-list ${className}` : 'lk-layer-list'}>\n <div className=\"lk-layer-list__empty\">No layers</div>\n </div>\n );\n }\n\n const startDrag = (e: PointerEvent<HTMLElement>, index: number) => {\n e.currentTarget.setPointerCapture(e.pointerId);\n // Measured at grab time rather than hardcoded: a restyle that changes row\n // height or gap would otherwise silently skew every drag distance.\n const row = e.currentTarget.closest('.lk-layer-list__row');\n const list = row?.parentElement;\n const gap = list ? Number.parseFloat(getComputedStyle(list).rowGap) || 0 : 0;\n const pitch = row ? row.getBoundingClientRect().height + gap : 0;\n dragRef.current = {\n pointerId: e.pointerId,\n fromIndex: index,\n startY: e.clientY,\n pitch: pitch > 0 ? pitch : 1,\n };\n setDragIndex(index);\n };\n\n const moveDrag = (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n const delta = Math.round((e.clientY - drag.startY) / drag.pitch);\n const target = Math.min(reorderable.length - 1, Math.max(0, drag.fromIndex + delta));\n setDragIndex(target);\n };\n\n const endDrag = (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n if (dragIndex !== null && dragIndex !== drag.fromIndex) {\n const next = [...reorderable];\n const [moved] = next.splice(drag.fromIndex, 1);\n if (moved) next.splice(dragIndex, 0, moved);\n onReorder([...next, ...pinned]);\n }\n dragRef.current = null;\n setDragIndex(null);\n };\n\n return (\n <div className={className ? `lk-layer-list ${className}` : 'lk-layer-list'}>\n {reorderable.map((layer, i) => {\n const isDragging = dragIndex === i;\n return (\n <div\n key={layer.id}\n className={\n isDragging ? 'lk-layer-list__row lk-layer-list__row--dragging' : 'lk-layer-list__row'\n }\n >\n <button\n type=\"button\"\n className=\"lk-layer-list__handle\"\n aria-label={`Reorder ${layer.label}`}\n onPointerDown={(e) => startDrag(e, i)}\n onPointerMove={moveDrag}\n onPointerUp={endDrag}\n >\n <DragHandleGlyph size={13} />\n </button>\n <input\n className=\"lk-layer-list__check\"\n type=\"checkbox\"\n checked={visibility[layer.id] !== false}\n onChange={(e) => onToggle(layer.id, e.target.checked)}\n aria-label={`Toggle ${layer.label}`}\n />\n <span className=\"lk-layer-list__label\">{layer.label}</span>\n </div>\n );\n })}\n {pinned.map((layer) => (\n <div key={layer.id} className=\"lk-layer-list__row lk-layer-list__row--pinned\">\n <span className=\"lk-layer-list__lock\" role=\"img\" aria-label=\"Always on\">\n 🔒\n </span>\n <span className=\"lk-layer-list__label\">{layer.label}</span>\n </div>\n ))}\n </div>\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { v, f2 } from './chunk-TLGRYALP.js';
2
1
  import { CanvasStackContext } from './chunk-CPUJ3QXL.js';
3
- import { useVisibleRaf } from './chunk-Z6HJ5FEM.js';
2
+ import { _, f } from './chunk-RGT4EJIB.js';
3
+ import { useVisibleRaf } from './chunk-QCICIHEO.js';
4
4
  import { useState, useRef, useEffect, useContext, useCallback } from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
@@ -81,8 +81,8 @@ function ScaleIndicator({
81
81
  ] });
82
82
  }
83
83
  var toTrack = (zoom) => Math.log2(zoom);
84
- var fromTrack = (v2) => 2 ** v2;
85
- var clamp = (v2, lo, hi) => Math.max(lo, Math.min(hi, v2));
84
+ var fromTrack = (v) => 2 ** v;
85
+ var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
86
86
  function ZoomControl({
87
87
  zoom,
88
88
  onZoomChange,
@@ -98,7 +98,7 @@ function ZoomControl({
98
98
  };
99
99
  return /* @__PURE__ */ jsxs("div", { className: `lk-zoom${className ? ` ${className}` : ""}`, children: [
100
100
  /* @__PURE__ */ jsx(
101
- v,
101
+ _,
102
102
  {
103
103
  className: "lk-zoom__slider",
104
104
  ariaLabel: "Zoom",
@@ -112,7 +112,7 @@ function ZoomControl({
112
112
  }
113
113
  ),
114
114
  /* @__PURE__ */ jsx(
115
- f2,
115
+ f,
116
116
  {
117
117
  className: "lk-zoom__field",
118
118
  "aria-label": "Zoom",
@@ -262,5 +262,5 @@ Toolbar.Button = Button;
262
262
  Toolbar.Spacer = Spacer;
263
263
 
264
264
  export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl };
265
- //# sourceMappingURL=chunk-O7NVSCLN.js.map
266
- //# sourceMappingURL=chunk-O7NVSCLN.js.map
265
+ //# sourceMappingURL=chunk-JDROYQM3.js.map
266
+ //# sourceMappingURL=chunk-JDROYQM3.js.map