@weasel-js/labkit 1.4.0-pre.1 → 1.4.1

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 (120) hide show
  1. package/dist/_dts/{CanvasStackContext-LnCfqNBA.d.ts → CanvasStackContext-BIRUVVGH.d.ts} +1 -1
  2. package/dist/_dts/PrefsForm.d-CgxUequc.d.ts +20 -0
  3. package/dist/_dts/{frac-C-2c72Ij.d.ts → frac-X7mWgd7y.d.ts} +10 -4
  4. package/dist/_dts/{index-BDVzvRzQ.d.ts → index-FEa1MudK.d.ts} +8 -2
  5. package/dist/_dts/{types-DYMaEvM5.d.ts → types-ChVJJHvk.d.ts} +3 -0
  6. package/dist/_dts/{types-D6s4b7if.d.ts → types-lg4TSCb2.d.ts} +3 -1
  7. package/dist/_dts/{useTrialState-gmMvZqPc.d.ts → useTrialState-Cdm13fvl.d.ts} +2 -1
  8. package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +5041 -0
  9. package/dist/canvas/index.d.ts +16 -16
  10. package/dist/canvas/index.js +2 -2
  11. package/dist/chrome/index.d.ts +6 -6
  12. package/dist/chrome/index.js +5 -5
  13. package/dist/chunk-2YILQ7Y5.js +33 -0
  14. package/dist/chunk-2YILQ7Y5.js.map +1 -0
  15. package/dist/{chunk-TO2FUOKF.js → chunk-53AZ2O2N.js} +16 -13
  16. package/dist/chunk-53AZ2O2N.js.map +1 -0
  17. package/dist/{chunk-QB5SM4BM.js → chunk-7TRFMIWX.js} +55 -41
  18. package/dist/chunk-7TRFMIWX.js.map +1 -0
  19. package/dist/{chunk-6OEYTYML.js → chunk-BMQWLKOL.js} +15 -15
  20. package/dist/chunk-BMQWLKOL.js.map +1 -0
  21. package/dist/{chunk-M75ZU6ZZ.js → chunk-D7QIPGEB.js} +3 -3
  22. package/dist/{chunk-M75ZU6ZZ.js.map → chunk-D7QIPGEB.js.map} +1 -1
  23. package/dist/{chunk-L5QJOOLV.js → chunk-DG2IFMLA.js} +1309 -273
  24. package/dist/chunk-DG2IFMLA.js.map +1 -0
  25. package/dist/{chunk-LN6JDUGB.js → chunk-HXXTULDN.js} +2 -2
  26. package/dist/{chunk-LN6JDUGB.js.map → chunk-HXXTULDN.js.map} +1 -1
  27. package/dist/{chunk-RBGKL7NF.js → chunk-J6SBFZYT.js} +1807 -1814
  28. package/dist/chunk-J6SBFZYT.js.map +1 -0
  29. package/dist/{chunk-XJ6N32QP.js → chunk-LJSIUFYD.js} +14 -30
  30. package/dist/chunk-LJSIUFYD.js.map +1 -0
  31. package/dist/{chunk-AE5CNVRU.js → chunk-MIT3ISW4.js} +37 -31
  32. package/dist/chunk-MIT3ISW4.js.map +1 -0
  33. package/dist/{chunk-HHGVISVZ.js → chunk-MSR7EVS6.js} +7 -5
  34. package/dist/chunk-MSR7EVS6.js.map +1 -0
  35. package/dist/{chunk-ESIQNQ6K.js → chunk-OFCBEZMU.js} +12 -6
  36. package/dist/chunk-OFCBEZMU.js.map +1 -0
  37. package/dist/{chunk-HMFODCOX.js → chunk-PP7ZWAMV.js} +83 -75
  38. package/dist/chunk-PP7ZWAMV.js.map +1 -0
  39. package/dist/{chunk-E2UQVZ44.js → chunk-RLOXQZW3.js} +3 -3
  40. package/dist/{chunk-E2UQVZ44.js.map → chunk-RLOXQZW3.js.map} +1 -1
  41. package/dist/controls/index.d.ts +4 -3
  42. package/dist/controls/index.js +3 -3
  43. package/dist/dragdrop/index.d.ts +5 -5
  44. package/dist/dragdrop/index.js +2 -2
  45. package/dist/index.d.ts +57 -77
  46. package/dist/index.js +308 -161
  47. package/dist/index.js.map +1 -1
  48. package/dist/job/index.js +1 -1
  49. package/dist/layers/index.d.ts +6 -6
  50. package/dist/layers/index.js +3 -3
  51. package/dist/loupe/index.d.ts +7 -13
  52. package/dist/loupe/index.js +2 -2
  53. package/dist/passthrough/weasel-canvas.d.ts +3 -343
  54. package/dist/passthrough/weasel-canvas.js +1 -1
  55. package/dist/passthrough/weasel-ui.d.ts +141 -2866
  56. package/dist/passthrough/weasel-ui.js +2 -2
  57. package/dist/primitives/index.js +4 -4
  58. package/dist/state/index.d.ts +3 -3
  59. package/dist/state/index.js +4 -2
  60. package/dist/state/index.js.map +1 -1
  61. package/dist/styles.css +74 -5
  62. package/dist/surface/index.d.ts +17 -2
  63. package/dist/surface/index.js +3 -2
  64. package/dist/ui/layers/index.js +2 -2
  65. package/dist/undo/index.d.ts +6 -5
  66. package/package.json +8 -8
  67. package/src/annotations/AnnotationOverlay.tsx +10 -6
  68. package/src/annotations/Annotations.less +6 -0
  69. package/src/annotations/Annotations.overlay.test.tsx +113 -0
  70. package/src/annotations/MarkList.tsx +3 -2
  71. package/src/canvas/CanvasStack.tsx +8 -13
  72. package/src/canvas/useOrbit.test.ts +93 -1
  73. package/src/canvas/useOrbit.ts +41 -34
  74. package/src/canvas/usePanZoom.test.ts +102 -1
  75. package/src/canvas/usePanZoom.ts +54 -36
  76. package/src/config/builder.test.ts +5 -0
  77. package/src/config/builder.ts +6 -0
  78. package/src/config/types.ts +1 -0
  79. package/src/controls/ControlPanel.test.tsx +23 -0
  80. package/src/controls/ControlPanel.tsx +3 -0
  81. package/src/job/useJob.ts +1 -1
  82. package/src/lab/Lab.surface.test.tsx +8 -3
  83. package/src/lab/LabHeader.test.tsx +12 -0
  84. package/src/lab/LabHeader.tsx +16 -6
  85. package/src/lab/Workspace.tsx +1 -1
  86. package/src/layers/LayerList.test.tsx +72 -1
  87. package/src/layers/LayerList.tsx +40 -32
  88. package/src/passthrough/weasel-ui.test.ts +9 -0
  89. package/src/passthrough/weasel-ui.ts +4 -0
  90. package/src/primitives/FloatingPanel.test.tsx +82 -0
  91. package/src/primitives/FloatingPanel.tsx +59 -41
  92. package/src/primitives/ZoomControl.tsx +2 -0
  93. package/src/state/store.ts +10 -0
  94. package/src/state/types.ts +3 -0
  95. package/src/surface/AGENTS.md +11 -1
  96. package/src/surface/index.ts +7 -1
  97. package/src/surface/useSurfaceTile.ts +20 -2
  98. package/src/surface/useTiledSurface.ts +4 -1
  99. package/src/theme/Interstellar.stories.tsx +4 -3
  100. package/src/theme/base.less +39 -1
  101. package/src/trial/Trial.less +27 -5
  102. package/src/trial/TrialBody.test.tsx +67 -0
  103. package/src/trial/TrialBody.tsx +155 -0
  104. package/src/trial/TrialChrome.tsx +18 -10
  105. package/src/trial/index.ts +2 -0
  106. package/dist/_dts/DrawCommand-B3bskUsC.d.ts +0 -564
  107. package/dist/_dts/PrefsForm-BkUJZx0A.d.ts +0 -204
  108. package/dist/_dts/fitViewToBounds-dZ2UDB6e.d.ts +0 -21
  109. package/dist/_dts/shapeKinds-Cx_rxwsa.d.ts +0 -87
  110. package/dist/_dts/types-C-gh9Ap-.d.ts +0 -695
  111. package/dist/chunk-6OEYTYML.js.map +0 -1
  112. package/dist/chunk-AE5CNVRU.js.map +0 -1
  113. package/dist/chunk-ESIQNQ6K.js.map +0 -1
  114. package/dist/chunk-HHGVISVZ.js.map +0 -1
  115. package/dist/chunk-HMFODCOX.js.map +0 -1
  116. package/dist/chunk-L5QJOOLV.js.map +0 -1
  117. package/dist/chunk-QB5SM4BM.js.map +0 -1
  118. package/dist/chunk-RBGKL7NF.js.map +0 -1
  119. package/dist/chunk-TO2FUOKF.js.map +0 -1
  120. package/dist/chunk-XJ6N32QP.js.map +0 -1
@@ -0,0 +1,155 @@
1
+ import { type ReactNode, useEffect, useMemo, useRef } from 'react';
2
+ import { asNodeId, createNode, Store, stripStrategy } from 'windease';
3
+ import { type ChromeMap, Container, Provider, StrategyRegistryProvider } from 'windease/react';
4
+
5
+ const ZONE_ID = asNodeId('lk-trial-body');
6
+ const SIDEBAR_ID = asNodeId('lk-trial-sidebar');
7
+ const CONTENT_ID = asNodeId('lk-trial-content');
8
+ const STRATEGIES = { strip: stripStrategy as never };
9
+
10
+ /** Props for `<TrialBody>`. */
11
+ export interface TrialBodyProps {
12
+ /** The sidebar region's sections. */
13
+ sidebar: ReactNode;
14
+ /** The instrument's own output. */
15
+ children: ReactNode;
16
+ /** Extra class on the content pane — `Trial` marks a canvas instrument's
17
+ * well flush. */
18
+ contentClassName?: string;
19
+ /** The sidebar's current extent in pixels. Omit for an unpersisted lab: the
20
+ * seam still works, its result just does not outlive the mount. */
21
+ width?: number;
22
+ /** Where the sidebar starts before anyone drags it. */
23
+ defaultWidth?: number;
24
+ minWidth?: number;
25
+ maxWidth?: number;
26
+ /** How little the instrument may be squeezed to. Reported as the seam's
27
+ * reachable maximum, so the drag stops there rather than clamping silently. */
28
+ contentMinWidth?: number;
29
+ /** Fires through the drag, not on release: the pane is already there. */
30
+ onWidthChange?: (width: number) => void;
31
+ /**
32
+ * Fixed extent. Omit in an app — the strip measures its own box. Supply it
33
+ * where nothing measures, notably jsdom, or both panes lay out at zero.
34
+ */
35
+ viewport?: { w: number; h: number };
36
+ }
37
+
38
+ /**
39
+ * A trial's sidebar and content as a two-pane strip with a draggable seam.
40
+ *
41
+ * The seam is `stripStrategy`'s own resize affordance, so it arrives as a
42
+ * `role="separator"` carrying the reachable range, operable by pointer and by
43
+ * arrows / Home / End, and clamped against the content pane's floor rather
44
+ * than against the sidebar's alone.
45
+ */
46
+ export function TrialBody({
47
+ sidebar,
48
+ children,
49
+ contentClassName,
50
+ width,
51
+ defaultWidth = 320,
52
+ minWidth = 140,
53
+ maxWidth = 720,
54
+ contentMinWidth = 160,
55
+ onWidthChange,
56
+ viewport,
57
+ }: TrialBodyProps) {
58
+ // The cross-axis half of every size hint below is inert: a horizontal strip
59
+ // stretches its panes to the container's height and never reads `h`.
60
+ const storeRef = useRef<Store | null>(null);
61
+ if (storeRef.current === null) {
62
+ const store = new Store();
63
+ store.registerNode(
64
+ createNode({
65
+ kind: 'zone',
66
+ id: ZONE_ID,
67
+ container: { strategyId: 'strip', config: { axis: 'x', resizable: true } },
68
+ }),
69
+ );
70
+ store.registerNode(
71
+ createNode({
72
+ kind: 'sidebar',
73
+ id: SIDEBAR_ID,
74
+ parentId: ZONE_ID,
75
+ meta: { title: 'Sidebar' },
76
+ placement: { size: { w: width ?? defaultWidth } },
77
+ hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } },
78
+ }),
79
+ );
80
+ store.registerNode(
81
+ createNode({
82
+ kind: 'content',
83
+ id: CONTENT_ID,
84
+ parentId: ZONE_ID,
85
+ meta: { title: 'Content' },
86
+ hints: { minSize: { w: contentMinWidth, h: 0 } },
87
+ }),
88
+ );
89
+ store.showNode(SIDEBAR_ID);
90
+ store.showNode(CONTENT_ID);
91
+ storeRef.current = store;
92
+ }
93
+ const store = storeRef.current;
94
+
95
+ // What the store last held, so the placement event can tell a drag from the
96
+ // echo of our own write and a controlled `width` does not fight the seam.
97
+ const widthRef = useRef(width ?? defaultWidth);
98
+
99
+ useEffect(() => {
100
+ store.setHints(SIDEBAR_ID, {
101
+ minSize: { w: minWidth, h: 0 },
102
+ maxSize: { w: maxWidth, h: 0 },
103
+ });
104
+ store.setHints(CONTENT_ID, { minSize: { w: contentMinWidth, h: 0 } });
105
+ }, [store, minWidth, maxWidth, contentMinWidth]);
106
+
107
+ useEffect(() => {
108
+ if (width === undefined || width === widthRef.current) return;
109
+ widthRef.current = width;
110
+ store.patchPlacement(SIDEBAR_ID, { size: { w: width } });
111
+ }, [store, width]);
112
+
113
+ const onWidthChangeRef = useRef(onWidthChange);
114
+ onWidthChangeRef.current = onWidthChange;
115
+ useEffect(
116
+ () =>
117
+ store.events.on('node.placementChanged', () => {
118
+ const next = (store.getPlacement(SIDEBAR_ID)?.size as { w?: number } | undefined)?.w;
119
+ if (typeof next !== 'number' || next === widthRef.current) return;
120
+ widthRef.current = next;
121
+ onWidthChangeRef.current?.(next);
122
+ }),
123
+ [store],
124
+ );
125
+
126
+ const chrome = useMemo<ChromeMap>(
127
+ () => ({
128
+ sidebar: () => <div className="lk-trial__sidebar">{sidebar}</div>,
129
+ content: () => (
130
+ <div
131
+ className={
132
+ contentClassName ? `lk-trial__content ${contentClassName}` : 'lk-trial__content'
133
+ }
134
+ >
135
+ {children}
136
+ </div>
137
+ ),
138
+ }),
139
+ [sidebar, children, contentClassName],
140
+ );
141
+
142
+ return (
143
+ <Provider store={store}>
144
+ <StrategyRegistryProvider strategies={STRATEGIES}>
145
+ <Container
146
+ parentId={ZONE_ID}
147
+ chrome={chrome}
148
+ className="lk-trial__panes windease-zone"
149
+ affordances
150
+ viewport={viewport}
151
+ />
152
+ </StrategyRegistryProvider>
153
+ </Provider>
154
+ );
155
+ }
@@ -17,6 +17,7 @@ import { JobProgress } from '../primitives/JobProgress';
17
17
  import { LabStoreContext } from '../state/context';
18
18
  import type { TrialRecord } from '../state/types';
19
19
  import { as2DView } from '../state/view';
20
+ import { TrialBody } from './TrialBody';
20
21
  import { TrialTitleBar } from './TrialTitleBar';
21
22
  import { UndockedSections } from './UndockedSections';
22
23
 
@@ -83,6 +84,7 @@ export function TrialChrome({
83
84
  const storeCtx = useContext(LabStoreContext);
84
85
  if (!storeCtx) throw new Error('[labkit] TrialChrome requires <LabStoreProvider>');
85
86
  const updateTrialView = useStore(storeCtx.store, (s) => s.updateTrialView);
87
+ const updateTrialSidebarWidth = useStore(storeCtx.store, (s) => s.updateTrialSidebarWidth);
86
88
  const updateTrialConfig = useStore(storeCtx.store, (s) => s.updateTrialConfig);
87
89
  const updateTrialState = useStore(storeCtx.store, (s) => s.updateTrialState);
88
90
  const undockPanelAction = useStore(storeCtx.store, (s) => s.undockPanel);
@@ -213,18 +215,24 @@ export function TrialChrome({
213
215
  </div>
214
216
  <div className="lk-trial__body">
215
217
  <PaletteRegion contributions={inRegion('palette')} ctx={ctx} />
216
- <div className="lk-trial__sidebar">
217
- <SidebarRegion contributions={inRegion('sidebar')} ctx={ctx} />
218
- <UndockedSections
219
- trialId={trialId}
220
- sections={inRegion('sidebar').filter((c) => undockedIds.includes(c.id))}
221
- onDock={ctx.dockPanel}
222
- />
223
- </div>
224
- <div className={`lk-trial__content${instrument.canvas ? ' lk-trial__content--flush' : ''}`}>
218
+ <TrialBody
219
+ width={record.sidebarWidth}
220
+ onWidthChange={(w) => updateTrialSidebarWidth(trialId, w)}
221
+ contentClassName={instrument.canvas ? 'lk-trial__content--flush' : undefined}
222
+ sidebar={
223
+ <>
224
+ <SidebarRegion contributions={inRegion('sidebar')} ctx={ctx} />
225
+ <UndockedSections
226
+ trialId={trialId}
227
+ sections={inRegion('sidebar').filter((c) => undockedIds.includes(c.id))}
228
+ onDock={ctx.dockPanel}
229
+ />
230
+ </>
231
+ }
232
+ >
225
233
  {children}
226
234
  <ViewportRegion contributions={inRegion('viewport')} ctx={ctx} />
227
- </div>
235
+ </TrialBody>
228
236
  </div>
229
237
  <div className="lk-trial__status">
230
238
  {job ? <JobProgress job={job} /> : null}
@@ -1,5 +1,7 @@
1
1
  export type { TrialProps } from './Trial';
2
2
  export { Trial } from './Trial';
3
+ export type { TrialBodyProps } from './TrialBody';
4
+ export { TrialBody } from './TrialBody';
3
5
  export type { TrialChromeProps, UndoBindings } from './TrialChrome';
4
6
  export { TrialChrome } from './TrialChrome';
5
7
  export {