@weasel-js/labkit 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +41 -4
  2. package/dist/_dts/{CanvasStackContext-CqkxkFJW.d.ts → CanvasStackContext-CMMo180l.d.ts} +1 -1
  3. package/dist/_dts/{PrefsForm.d-DDHFANkc.d.ts → PrefsForm.d-DPy9I8It.d.ts} +4 -0
  4. package/dist/_dts/Select.d-ZTiwzYyT.d.ts +479 -0
  5. package/dist/_dts/{frac-8R6UmlvN.d.ts → frac-B4hFJMiN.d.ts} +54 -6
  6. package/dist/_dts/{index-retnAut7.d.ts → index-8LiKe3A-.d.ts} +77 -10
  7. package/dist/_dts/{index-B8uu2ba7.d.ts → index-DlKolEIZ.d.ts} +20 -8
  8. package/dist/_dts/{types-Ca2LCnPq.d.ts → types-Db-3NNk1.d.ts} +28 -4
  9. package/dist/_dts/{usePanZoom-nS798rOF.d.ts → usePanZoom-SSTZe410.d.ts} +4 -47
  10. package/dist/_dts/{useTrialState-jcx_TdU6.d.ts → useTrialState-pnAE-UBD.d.ts} +1 -1
  11. package/dist/canvas/index.d.ts +5 -5
  12. package/dist/canvas/index.js +1 -1
  13. package/dist/chrome/index.d.ts +4 -4
  14. package/dist/chrome/index.js +7 -7
  15. package/dist/chunk-6BUQ77ZV.js +18 -0
  16. package/dist/chunk-6BUQ77ZV.js.map +1 -0
  17. package/dist/{chunk-KJALCDWE.js → chunk-753Y6HE6.js} +9 -9
  18. package/dist/chunk-753Y6HE6.js.map +1 -0
  19. package/dist/{chunk-6ZDGOZQV.js → chunk-A2ACAGW6.js} +72 -20
  20. package/dist/chunk-A2ACAGW6.js.map +1 -0
  21. package/dist/{chunk-NS64DXMN.js → chunk-CKUKF72R.js} +44 -21
  22. package/dist/chunk-CKUKF72R.js.map +1 -0
  23. package/dist/{chunk-MUKOW3TC.js → chunk-D35PFTS7.js} +4 -4
  24. package/dist/{chunk-MUKOW3TC.js.map → chunk-D35PFTS7.js.map} +1 -1
  25. package/dist/{chunk-UU3NJO6N.js → chunk-EMXAIRUJ.js} +3 -3
  26. package/dist/{chunk-UU3NJO6N.js.map → chunk-EMXAIRUJ.js.map} +1 -1
  27. package/dist/{chunk-ZPH5WTWF.js → chunk-ERFMC6WU.js} +142 -66
  28. package/dist/chunk-ERFMC6WU.js.map +1 -0
  29. package/dist/chunk-FKLT3ITC.js +590 -0
  30. package/dist/chunk-FKLT3ITC.js.map +1 -0
  31. package/dist/{chunk-QLSV2N3G.js → chunk-IJJUK4FU.js} +25 -13
  32. package/dist/chunk-IJJUK4FU.js.map +1 -0
  33. package/dist/{chunk-EKIICY6X.js → chunk-KJCUERQF.js} +37 -25
  34. package/dist/chunk-KJCUERQF.js.map +1 -0
  35. package/dist/chunk-LASCBWW7.js +13456 -0
  36. package/dist/chunk-LASCBWW7.js.map +1 -0
  37. package/dist/{chunk-67SJLMC7.js → chunk-LRI3MBGR.js} +45 -12
  38. package/dist/chunk-LRI3MBGR.js.map +1 -0
  39. package/dist/chunk-REOBGYMC.js +150 -0
  40. package/dist/chunk-REOBGYMC.js.map +1 -0
  41. package/dist/{chunk-PGETSEDK.js → chunk-TT5C5S6R.js} +11 -90
  42. package/dist/chunk-TT5C5S6R.js.map +1 -0
  43. package/dist/{chunk-NDRYLVOW.js → chunk-Z76KEZAX.js} +2 -2
  44. package/dist/chunk-Z76KEZAX.js.map +1 -0
  45. package/dist/config/index.d.ts +62 -19
  46. package/dist/config/index.js +6 -4
  47. package/dist/controls/index.d.ts +3 -3
  48. package/dist/controls/index.js +4 -4
  49. package/dist/dragdrop/index.d.ts +3 -3
  50. package/dist/index.d.ts +230 -62
  51. package/dist/index.js +1367 -1698
  52. package/dist/index.js.map +1 -1
  53. package/dist/layers/index.d.ts +4 -4
  54. package/dist/layers/index.js +2 -2
  55. package/dist/loupe/index.d.ts +67 -16
  56. package/dist/loupe/index.js +1 -1
  57. package/dist/passthrough/weasel-ui.d.ts +57 -230
  58. package/dist/passthrough/weasel-ui.js +1 -1
  59. package/dist/primitives/index.d.ts +3 -1
  60. package/dist/primitives/index.js +3 -3
  61. package/dist/state/index.d.ts +5 -5
  62. package/dist/state/index.js +5 -3
  63. package/dist/state/index.js.map +1 -1
  64. package/dist/styles.css +266 -57
  65. package/dist/surface/index.js +1 -1
  66. package/dist/ui/layers/index.js +1 -1
  67. package/dist/undo/index.d.ts +3 -3
  68. package/package.json +9 -9
  69. package/src/annotations/AnnotationOverlay.tsx +3 -0
  70. package/src/annotations/Annotations.less +4 -0
  71. package/src/annotations/Annotations.overlay.test.tsx +20 -0
  72. package/src/annotations/svgNodes.ts +1 -0
  73. package/src/annotations/toolMap.test.ts +9 -5
  74. package/src/annotations/toolMap.ts +3 -0
  75. package/src/canvas/CanvasStack.stories.tsx +1 -1
  76. package/src/canvas/index.ts +0 -9
  77. package/src/canvas/usePanZoom.test.ts +28 -0
  78. package/src/canvas/usePanZoom.ts +11 -4
  79. package/src/chrome/ChromeRegions.stories.tsx +1 -1
  80. package/src/chrome/LabChrome.tsx +21 -5
  81. package/src/chrome/builtins.test.ts +1 -0
  82. package/src/chrome/builtins.tsx +1 -0
  83. package/src/chrome/index.ts +1 -0
  84. package/src/chrome/labTypes.ts +3 -3
  85. package/src/chrome/regions/PaletteRegion.test.tsx +18 -0
  86. package/src/chrome/regions/PaletteRegion.tsx +6 -10
  87. package/src/chrome/regions/SidebarRegion.stories.tsx +44 -0
  88. package/src/chrome/regions/TitleBarRegion.tsx +1 -1
  89. package/src/chrome/regions/ToolbarRegion.tsx +11 -7
  90. package/src/chrome/types.ts +11 -2
  91. package/src/config/auto.test.ts +12 -0
  92. package/src/config/auto.ts +15 -0
  93. package/src/config/autoConfig.test.ts +107 -0
  94. package/src/config/autoConfig.ts +153 -0
  95. package/src/config/builder.test.ts +38 -0
  96. package/src/config/builder.ts +55 -11
  97. package/src/config/index.ts +3 -0
  98. package/src/config/path.ts +7 -2
  99. package/src/config/resolve.test.ts +25 -0
  100. package/src/config/resolve.ts +17 -1
  101. package/src/config/types.ts +32 -2
  102. package/src/config/useResolvedConfig.ts +26 -0
  103. package/src/controls/AutoControls.stories.tsx +88 -0
  104. package/src/controls/ControlPanel.less +23 -0
  105. package/src/controls/ControlPanel.stories.tsx +83 -1
  106. package/src/controls/ControlPanel.test.tsx +457 -4
  107. package/src/controls/ControlPanel.tsx +534 -73
  108. package/src/index.test.ts +0 -2
  109. package/src/index.ts +33 -11
  110. package/src/instrument/serializers.ts +29 -1
  111. package/src/lab/Lab.chrome.test.tsx +16 -0
  112. package/src/lab/Lab.stories.tsx +1 -1
  113. package/src/lab/Lab.surface.test.tsx +7 -2
  114. package/src/lab/Lab.test.tsx +79 -1
  115. package/src/lab/Lab.tsx +124 -16
  116. package/src/lab/LabContext.ts +8 -0
  117. package/src/lab/LabFit.stories.tsx +4 -4
  118. package/src/lab/LabFullChrome.stories.tsx +1 -1
  119. package/src/lab/LabHeader.tsx +0 -1
  120. package/src/lab/LabRoot.test.tsx +56 -0
  121. package/src/lab/LabRoot.tsx +47 -0
  122. package/src/lab/LabShell.less +24 -3
  123. package/src/lab/LabShell.stories.tsx +50 -1
  124. package/src/lab/LabShell.tsx +18 -27
  125. package/src/lab/LabSwitcher.less +10 -10
  126. package/src/lab/LabSwitcher.test.tsx +14 -9
  127. package/src/lab/LabSwitcher.tsx +8 -4
  128. package/src/lab/Workspace.less +1 -1
  129. package/src/lab/Workspace.stories.tsx +1 -1
  130. package/src/lab/Workspace.surface.test.tsx +1 -1
  131. package/src/lab/index.ts +2 -0
  132. package/src/layers/LayerList.less +1 -1
  133. package/src/layers/LayerList.stories.tsx +2 -2
  134. package/src/loupe/AGENTS.md +16 -4
  135. package/src/loupe/LoupeGestures.tsx +67 -0
  136. package/src/loupe/TrialLoupe.tsx +43 -28
  137. package/src/loupe/index.ts +4 -0
  138. package/src/loupe/loupeActions.ts +98 -0
  139. package/src/loupe/useLoupe.test.tsx +59 -2
  140. package/src/loupe/useLoupe.ts +28 -48
  141. package/src/passthrough/weasel-ui.ts +3 -3
  142. package/src/primitives/FloatingPanel.stories.tsx +1 -1
  143. package/src/primitives/FpsMeter.less +6 -1
  144. package/src/primitives/FpsMeter.stories.tsx +1 -1
  145. package/src/primitives/FpsMeter.test.tsx +12 -4
  146. package/src/primitives/FpsMeter.tsx +6 -1
  147. package/src/primitives/JobProgress.stories.tsx +2 -2
  148. package/src/primitives/Legend.stories.tsx +1 -1
  149. package/src/primitives/ScaleIndicator.stories.tsx +1 -1
  150. package/src/primitives/Sidebar.less +7 -0
  151. package/src/primitives/Sidebar.stories.tsx +1 -1
  152. package/src/primitives/Split.test.tsx +25 -0
  153. package/src/primitives/Split.tsx +36 -20
  154. package/src/primitives/StatusBar.less +6 -0
  155. package/src/primitives/StatusBar.stories.tsx +1 -1
  156. package/src/primitives/Toolbar.stories.tsx +1 -1
  157. package/src/specimen/Specimen.less +95 -0
  158. package/src/specimen/Specimen.stories.tsx +13 -0
  159. package/src/specimen/Specimen.test.tsx +13 -0
  160. package/src/specimen/Specimen.tsx +888 -0
  161. package/src/state/Persistence.stories.tsx +4 -4
  162. package/src/state/store.test.ts +65 -0
  163. package/src/state/store.ts +32 -8
  164. package/src/state/types.ts +31 -2
  165. package/src/state/useTrialState.test.tsx +85 -0
  166. package/src/state/useTrialState.ts +9 -1
  167. package/src/state/view.test.ts +4 -4
  168. package/src/styles.less +1 -0
  169. package/src/surface/index.ts +1 -1
  170. package/src/surface/useSurfaceTile.test.tsx +1 -1
  171. package/src/surface/useTiledSurface.test.tsx +65 -10
  172. package/src/surface/useTiledSurface.ts +23 -11
  173. package/src/theme/Interstellar.stories.tsx +2 -2
  174. package/src/theme/interstellar.test.ts +16 -5
  175. package/src/theme/interstellar.theme.json +180 -0
  176. package/src/theme/interstellar.ts +8 -5
  177. package/src/tools/labTool.ts +3 -3
  178. package/src/trial/Trial.annotations.test.tsx +13 -4
  179. package/src/trial/Trial.canvas.test.tsx +36 -0
  180. package/src/trial/Trial.config.test.tsx +75 -2
  181. package/src/trial/Trial.less +4 -0
  182. package/src/trial/Trial.stories.tsx +4 -1
  183. package/src/trial/Trial.test.tsx +3 -0
  184. package/src/trial/Trial.tsx +21 -14
  185. package/src/trial/TrialChrome.tsx +17 -3
  186. package/src/trial/trialOps.test.ts +101 -1
  187. package/src/trial/trialOps.ts +62 -4
  188. package/dist/_dts/ToggleBar.d-DbHoWKIA.d.ts +0 -116
  189. package/dist/chunk-67SJLMC7.js.map +0 -1
  190. package/dist/chunk-6ZDGOZQV.js.map +0 -1
  191. package/dist/chunk-E44SU6XS.js +0 -50
  192. package/dist/chunk-E44SU6XS.js.map +0 -1
  193. package/dist/chunk-EKIICY6X.js.map +0 -1
  194. package/dist/chunk-KJALCDWE.js.map +0 -1
  195. package/dist/chunk-NDRYLVOW.js.map +0 -1
  196. package/dist/chunk-NS64DXMN.js.map +0 -1
  197. package/dist/chunk-PGETSEDK.js.map +0 -1
  198. package/dist/chunk-QLSV2N3G.js.map +0 -1
  199. package/dist/chunk-S2SHZRD7.js +0 -7681
  200. package/dist/chunk-S2SHZRD7.js.map +0 -1
  201. package/dist/chunk-TQBBYTAF.js +0 -280
  202. package/dist/chunk-TQBBYTAF.js.map +0 -1
  203. package/dist/chunk-ZPH5WTWF.js.map +0 -1
  204. package/src/canvas/useOrbit.test.ts +0 -167
  205. package/src/canvas/useOrbit.ts +0 -156
  206. package/src/theme/interstellar.tokens.json +0 -61
@@ -11,6 +11,8 @@ const STRATEGIES = { strip: stripStrategy as never };
11
11
  export interface SplitProps {
12
12
  /** The sidebar pane's contents. */
13
13
  sidebar: ReactNode;
14
+ /** The edge the sidebar sits on. Read once, when the strip mounts. Default `'start'`. */
15
+ side?: 'start' | 'end';
14
16
  /** The content pane's contents. */
15
17
  children: ReactNode;
16
18
  /** Names the sidebar pane, and through it the seam. Default `'Sidebar'`. */
@@ -51,6 +53,7 @@ export interface SplitProps {
51
53
  export function Split({
52
54
  sidebar,
53
55
  children,
56
+ side = 'start',
54
57
  label = 'Sidebar',
55
58
  className,
56
59
  sidebarClassName,
@@ -72,28 +75,37 @@ export function Split({
72
75
  createNode({
73
76
  kind: 'zone',
74
77
  id: ZONE_ID,
75
- container: { strategyId: 'strip', config: { axis: 'x', resizable: true } },
76
- }),
77
- );
78
- store.registerNode(
79
- createNode({
80
- kind: 'sidebar',
81
- id: SIDEBAR_ID,
82
- parentId: ZONE_ID,
83
- meta: { title: label },
84
- placement: { size: { w: width ?? defaultWidth } },
85
- hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } },
86
- }),
87
- );
88
- store.registerNode(
89
- createNode({
90
- kind: 'content',
91
- id: CONTENT_ID,
92
- parentId: ZONE_ID,
93
- meta: { title: 'Content' },
94
- hints: { minSize: { w: contentMinWidth, h: 0 } },
78
+ // A strip's seam resizes the pane before it, which on the end side is the
79
+ // content; 'neighbor' has the seam size the sidebar after it too.
80
+ container: {
81
+ strategyId: 'strip',
82
+ config: {
83
+ axis: 'x',
84
+ resizable: true,
85
+ ...(side === 'end' ? { resizeMode: 'neighbor' } : {}),
86
+ },
87
+ },
95
88
  }),
96
89
  );
90
+ const sidebarNode = createNode({
91
+ kind: 'sidebar',
92
+ id: SIDEBAR_ID,
93
+ parentId: ZONE_ID,
94
+ meta: { title: label },
95
+ placement: { size: { w: width ?? defaultWidth } },
96
+ hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } },
97
+ });
98
+ const contentNode = createNode({
99
+ kind: 'content',
100
+ id: CONTENT_ID,
101
+ parentId: ZONE_ID,
102
+ meta: { title: 'Content' },
103
+ hints: { minSize: { w: contentMinWidth, h: 0 } },
104
+ });
105
+ // A strip lays its children out in registration order.
106
+ for (const node of side === 'end' ? [contentNode, sidebarNode] : [sidebarNode, contentNode]) {
107
+ store.registerNode(node);
108
+ }
97
109
  store.showNode(SIDEBAR_ID);
98
110
  store.showNode(CONTENT_ID);
99
111
  storeRef.current = store;
@@ -127,6 +139,10 @@ export function Split({
127
139
  useEffect(
128
140
  () =>
129
141
  store.events.on('node.placementChanged', () => {
142
+ // A neighbor drag pins the content's width too; unpinned, it goes on filling the strip.
143
+ if ((store.getPlacement(CONTENT_ID)?.size as { w?: number } | undefined)?.w !== undefined) {
144
+ store.patchPlacement(CONTENT_ID, { size: {} });
145
+ }
130
146
  const next = (store.getPlacement(SIDEBAR_ID)?.size as { w?: number } | undefined)?.w;
131
147
  if (typeof next !== 'number' || next === widthRef.current) return;
132
148
  widthRef.current = next;
@@ -1,6 +1,10 @@
1
1
  .lk-status-bar {
2
2
  display: flex;
3
3
  align-items: center;
4
+ /* One line, always. A bar that grows a second line takes it from the canvas
5
+ above it, and a readout that changes width would do that on and off as it
6
+ ticks. Too narrow for its contents clips them instead. */
7
+ overflow: hidden;
4
8
  gap: var(--wzl-space-md);
5
9
  padding: var(--wzl-space-xs) var(--wzl-space-sm);
6
10
  background: var(--wzl-surface-raised);
@@ -13,6 +17,8 @@
13
17
  .lk-status-bar-section {
14
18
  display: inline-flex;
15
19
  align-items: center;
20
+ white-space: nowrap;
21
+ min-width: 0;
16
22
  gap: var(--wzl-space-xs);
17
23
  padding: 0 var(--wzl-space-xs);
18
24
  border-right: 1px solid var(--wzl-line-subtle);
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
1
+ import type { Meta, StoryObj } from '@weasel-js/forge';
2
2
  import { StatusBar } from './StatusBar';
3
3
 
4
4
  const meta: Meta<typeof StatusBar> = {
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite';
1
+ import type { Meta, StoryObj } from '@weasel-js/forge';
2
2
  import { Toolbar } from './Toolbar';
3
3
 
4
4
  const meta: Meta<typeof Toolbar> = {
@@ -0,0 +1,95 @@
1
+ .lk-specimen {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--wzl-space-lg);
5
+ padding: var(--wzl-space-lg);
6
+ background: var(--wzl-surface);
7
+ color: var(--wzl-fg);
8
+ font-family: var(--wzl-font-ui);
9
+ font-size: var(--wzl-font-size);
10
+ }
11
+
12
+ .lk-specimen__section {
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: var(--wzl-space-sm);
16
+ }
17
+
18
+ .lk-specimen__heading {
19
+ margin: 0;
20
+ padding-block-end: var(--wzl-space-xs);
21
+ border-bottom: var(--wzl-border-w) solid var(--wzl-line-subtle);
22
+ color: var(--wzl-fg-muted);
23
+ font-family: var(--wzl-font-display);
24
+ font-size: var(--wzl-font-size-sm);
25
+ font-weight: var(--wzl-font-weight-normal);
26
+ letter-spacing: 0.08em;
27
+ text-transform: uppercase;
28
+ }
29
+
30
+ .lk-specimen__grid {
31
+ display: grid;
32
+ grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
33
+ gap: var(--wzl-space-md);
34
+ align-items: start;
35
+ }
36
+
37
+ .lk-specimen__cell {
38
+ display: flex;
39
+ flex-direction: column;
40
+ gap: var(--wzl-space-xs);
41
+ min-width: 0;
42
+ }
43
+
44
+ .lk-specimen__label {
45
+ color: var(--wzl-fg-subtle);
46
+ font-family: var(--wzl-font-mono);
47
+ font-size: var(--wzl-font-size-xs);
48
+ }
49
+
50
+ .lk-specimen__row {
51
+ display: flex;
52
+ flex-wrap: wrap;
53
+ align-items: center;
54
+ gap: var(--wzl-space-sm);
55
+ }
56
+
57
+ .lk-specimen__cell--wide {
58
+ grid-column: 1 / -1;
59
+ }
60
+
61
+ .lk-specimen__box {
62
+ position: relative;
63
+ display: flex;
64
+ height: 160px;
65
+ overflow: hidden;
66
+ border: var(--wzl-border-w) solid var(--wzl-line-subtle);
67
+ border-radius: var(--wzl-radius-sm);
68
+ }
69
+
70
+ .lk-specimen__box-main {
71
+ flex: 1;
72
+ min-width: 0;
73
+ padding: var(--wzl-space-sm);
74
+ }
75
+
76
+ .lk-specimen__pad {
77
+ padding: var(--wzl-space-xs) var(--wzl-space-sm);
78
+ }
79
+
80
+ .lk-specimen__pane {
81
+ flex: none;
82
+ width: var(--lk-specimen-pane-w);
83
+ padding: var(--wzl-space-sm);
84
+ }
85
+
86
+ .lk-specimen__timeline {
87
+ height: 180px;
88
+ }
89
+
90
+ .lk-specimen__floating-host {
91
+ position: relative;
92
+ height: 160px;
93
+ border: var(--wzl-border-w) solid var(--wzl-line-subtle);
94
+ border-radius: var(--wzl-radius-sm);
95
+ }
@@ -0,0 +1,13 @@
1
+ import type { Meta, StoryObj } from '@weasel-js/forge';
2
+ import { Specimen } from './Specimen';
3
+
4
+ const meta: Meta<typeof Specimen> = {
5
+ title: 'labkit/Specimen',
6
+ component: Specimen,
7
+ parameters: { layout: 'fullscreen' },
8
+ };
9
+ export default meta;
10
+
11
+ type Story = StoryObj<typeof Specimen>;
12
+
13
+ export const Everything: Story = {};
@@ -0,0 +1,13 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { SPECIMEN_SECTIONS, Specimen } from './Specimen';
4
+
5
+ describe('<Specimen>', () => {
6
+ it('renders every section as a named region', () => {
7
+ render(<Specimen />);
8
+ expect(SPECIMEN_SECTIONS.length).toBeGreaterThan(0);
9
+ for (const title of SPECIMEN_SECTIONS) {
10
+ expect(screen.getByRole('region', { name: title })).toBeInTheDocument();
11
+ }
12
+ });
13
+ });