@weasel-js/labkit 1.4.3 → 1.5.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 (229) hide show
  1. package/README.md +13 -2
  2. package/dist/_dts/{CanvasStackContext-Dde8_1my.d.ts → CanvasStackContext-CqkxkFJW.d.ts} +1 -1
  3. package/dist/_dts/ToggleBar.d-DbHoWKIA.d.ts +116 -0
  4. package/dist/_dts/{frac-B5mB8LsJ.d.ts → frac-8R6UmlvN.d.ts} +256 -33
  5. package/dist/_dts/index-B8uu2ba7.d.ts +237 -0
  6. package/dist/_dts/{index-DelFfeV0.d.ts → index-retnAut7.d.ts} +45 -12
  7. package/dist/_dts/{types-B9_zrHmb.d.ts → types-Ca2LCnPq.d.ts} +65 -2
  8. package/dist/_dts/usePanZoom-nS798rOF.d.ts +160 -0
  9. package/dist/_dts/useTrialState-jcx_TdU6.d.ts +212 -0
  10. package/dist/canvas/index.d.ts +17 -128
  11. package/dist/canvas/index.js +4 -2
  12. package/dist/chrome/index.d.ts +4 -92
  13. package/dist/chrome/index.js +9 -5
  14. package/dist/chunk-67SJLMC7.js +704 -0
  15. package/dist/chunk-67SJLMC7.js.map +1 -0
  16. package/dist/chunk-6ZDGOZQV.js +310 -0
  17. package/dist/chunk-6ZDGOZQV.js.map +1 -0
  18. package/dist/{chunk-QAGAHJKZ.js → chunk-EKIICY6X.js} +111 -25
  19. package/dist/chunk-EKIICY6X.js.map +1 -0
  20. package/dist/{chunk-CTRKTLYZ.js → chunk-H6ZAOWNE.js} +11 -11
  21. package/dist/chunk-H6ZAOWNE.js.map +1 -0
  22. package/dist/{chunk-2RQPGOQF.js → chunk-KJALCDWE.js} +9 -7
  23. package/dist/chunk-KJALCDWE.js.map +1 -0
  24. package/dist/{chunk-ISCOFAUO.js → chunk-MUKOW3TC.js} +3 -3
  25. package/dist/{chunk-ISCOFAUO.js.map → chunk-MUKOW3TC.js.map} +1 -1
  26. package/dist/chunk-NDRYLVOW.js +15 -0
  27. package/dist/chunk-NDRYLVOW.js.map +1 -0
  28. package/dist/{chunk-C42T6DJT.js → chunk-NS64DXMN.js} +226 -159
  29. package/dist/chunk-NS64DXMN.js.map +1 -0
  30. package/dist/{chunk-I6JCVE24.js → chunk-PGETSEDK.js} +135 -13
  31. package/dist/chunk-PGETSEDK.js.map +1 -0
  32. package/dist/{chunk-FQMJUVHJ.js → chunk-QLSV2N3G.js} +32 -37
  33. package/dist/chunk-QLSV2N3G.js.map +1 -0
  34. package/dist/chunk-RWNDDKOH.js +682 -0
  35. package/dist/chunk-RWNDDKOH.js.map +1 -0
  36. package/dist/chunk-S2SHZRD7.js +7681 -0
  37. package/dist/chunk-S2SHZRD7.js.map +1 -0
  38. package/dist/{chunk-ASWKLRKJ.js → chunk-TQBBYTAF.js} +19 -82
  39. package/dist/chunk-TQBBYTAF.js.map +1 -0
  40. package/dist/chunk-UU3NJO6N.js +72 -0
  41. package/dist/chunk-UU3NJO6N.js.map +1 -0
  42. package/dist/chunk-WIG6XHJ7.js +35 -0
  43. package/dist/chunk-WIG6XHJ7.js.map +1 -0
  44. package/dist/{chunk-TJ7QY3OC.js → chunk-ZPH5WTWF.js} +21 -15
  45. package/dist/chunk-ZPH5WTWF.js.map +1 -0
  46. package/dist/config/index.d.ts +232 -0
  47. package/dist/config/index.js +6 -0
  48. package/dist/config/index.js.map +1 -0
  49. package/dist/controls/index.d.ts +2 -3
  50. package/dist/controls/index.js +3 -2
  51. package/dist/dragdrop/index.d.ts +2 -4
  52. package/dist/index.d.ts +123 -348
  53. package/dist/index.js +794 -837
  54. package/dist/index.js.map +1 -1
  55. package/dist/layers/index.d.ts +3 -5
  56. package/dist/layers/index.js +2 -2
  57. package/dist/loupe/index.d.ts +6 -8
  58. package/dist/loupe/index.js +2 -2
  59. package/dist/passthrough/weasel-ui.d.ts +169 -117
  60. package/dist/passthrough/weasel-ui.js +1 -1
  61. package/dist/primitives/index.d.ts +53 -6
  62. package/dist/primitives/index.js +6 -4
  63. package/dist/state/index.d.ts +12 -7
  64. package/dist/state/index.js +16 -13
  65. package/dist/state/index.js.map +1 -1
  66. package/dist/styles.css +163 -62
  67. package/dist/surface/index.d.ts +44 -7
  68. package/dist/surface/index.js +2 -1
  69. package/dist/ui/layers/index.js +1 -1
  70. package/dist/undo/index.d.ts +2 -4
  71. package/package.json +15 -8
  72. package/src/annotations/AnnotationOverlay.tsx +53 -5
  73. package/src/annotations/Annotations.overlay.test.tsx +85 -6
  74. package/src/annotations/drawOne.test.ts +1 -1
  75. package/src/annotations/drawOne.ts +2 -2
  76. package/src/annotations/frac.test.ts +4 -4
  77. package/src/annotations/frac.ts +3 -2
  78. package/src/annotations/index.ts +1 -1
  79. package/src/annotations/paint.test.ts +2 -2
  80. package/src/annotations/paint.ts +1 -1
  81. package/src/annotations/preload.ts +6 -0
  82. package/src/annotations/store.test.ts +18 -0
  83. package/src/annotations/store.ts +7 -6
  84. package/src/annotations/svgNodes.test.ts +2 -2
  85. package/src/annotations/svgNodes.ts +1 -2
  86. package/src/annotations/toolMap.ts +3 -3
  87. package/src/annotations/types.ts +6 -3
  88. package/src/canvas/CameraWheelContext.ts +12 -0
  89. package/src/canvas/CanvasStack.test.tsx +25 -0
  90. package/src/canvas/CanvasStack.tsx +31 -4
  91. package/src/canvas/Stage.less +18 -0
  92. package/src/canvas/Stage.test.tsx +186 -0
  93. package/src/canvas/Stage.tsx +134 -0
  94. package/src/canvas/camera.test.ts +17 -2
  95. package/src/canvas/camera.ts +9 -9
  96. package/src/canvas/index.ts +4 -0
  97. package/src/canvas/usePanZoom.ts +10 -5
  98. package/src/chrome/ChromeRegions.stories.tsx +0 -3
  99. package/src/chrome/LabChrome.tsx +114 -0
  100. package/src/chrome/builtins.tsx +20 -31
  101. package/src/chrome/index.ts +15 -0
  102. package/src/chrome/labRegions.test.tsx +208 -0
  103. package/src/chrome/labTypes.ts +50 -0
  104. package/src/chrome/merge.ts +7 -9
  105. package/src/chrome/regions/PaletteRegion.test.tsx +6 -4
  106. package/src/chrome/regions/PaletteRegion.tsx +21 -9
  107. package/src/chrome/regions/SidebarRegion.tsx +25 -13
  108. package/src/chrome/regions/StatusRegion.tsx +15 -8
  109. package/src/chrome/regions/ToolbarRegion.tsx +30 -16
  110. package/src/chrome/types.ts +47 -20
  111. package/src/config/builder.test.ts +4 -0
  112. package/src/config/builder.ts +16 -10
  113. package/src/config/declarationEmit.fixture.ts +11 -0
  114. package/src/config/declarationEmit.test.ts +51 -0
  115. package/src/config/entry.test.ts +46 -0
  116. package/src/config/index.ts +13 -1
  117. package/src/config/nodeClasses.test.ts +18 -0
  118. package/src/config/types.ts +3 -1
  119. package/src/controls/ControlPanel.test.tsx +16 -0
  120. package/src/controls/ControlPanel.tsx +5 -2
  121. package/src/fake-indexeddb-auto.d.ts +5 -0
  122. package/src/index.test.ts +7 -0
  123. package/src/index.ts +39 -6
  124. package/src/instrument/serializers.test.ts +22 -0
  125. package/src/instrument/serializers.ts +11 -0
  126. package/src/instrument/types.ts +25 -1
  127. package/src/lab/Lab.less +4 -13
  128. package/src/lab/Lab.persist.test.tsx +147 -0
  129. package/src/lab/Lab.stories.tsx +0 -2
  130. package/src/lab/Lab.surface.test.tsx +66 -3
  131. package/src/lab/Lab.test.tsx +91 -17
  132. package/src/lab/Lab.tsx +337 -124
  133. package/src/lab/LabFit.stories.less +18 -0
  134. package/src/lab/LabFit.stories.tsx +219 -0
  135. package/src/lab/LabFullChrome.stories.tsx +0 -3
  136. package/src/lab/LabHeader.test.tsx +40 -9
  137. package/src/lab/LabHeader.tsx +7 -13
  138. package/src/lab/LabPalette.tsx +13 -26
  139. package/src/lab/LabShell.less +49 -12
  140. package/src/lab/LabShell.tsx +14 -2
  141. package/src/lab/LabSwitcher.less +92 -0
  142. package/src/lab/LabSwitcher.test.tsx +96 -0
  143. package/src/lab/LabSwitcher.tsx +112 -0
  144. package/src/lab/Workspace.surface.test.tsx +2 -1
  145. package/src/lab/fitCheck.test.ts +57 -0
  146. package/src/lab/fitCheck.ts +125 -0
  147. package/src/lab/index.ts +2 -0
  148. package/src/loupe/AGENTS.md +1 -1
  149. package/src/loupe/Loupe.less +1 -1
  150. package/src/loupe/canvasLens.ts +1 -1
  151. package/src/loupe/types.ts +1 -1
  152. package/src/loupe/useLoupe.test.tsx +1 -1
  153. package/src/loupe/useLoupe.ts +1 -1
  154. package/src/passthrough/weasel-ui.ts +9 -0
  155. package/src/primitives/FloatingPanel.stories.tsx +13 -1
  156. package/src/primitives/FloatingPanel.test.tsx +47 -16
  157. package/src/primitives/FloatingPanel.tsx +11 -25
  158. package/src/primitives/Split.less +14 -0
  159. package/src/primitives/Split.test.tsx +108 -0
  160. package/src/primitives/Split.tsx +159 -0
  161. package/src/primitives/ZoomControl.tsx +5 -2
  162. package/src/primitives/index.ts +2 -0
  163. package/src/state/Persistence.stories.tsx +75 -0
  164. package/src/state/Persistence.tsx +33 -0
  165. package/src/state/SingletonExperiment.test.tsx +47 -53
  166. package/src/state/SingletonExperiment.tsx +24 -13
  167. package/src/state/adapterContract.ts +116 -0
  168. package/src/state/adapters.test.ts +113 -61
  169. package/src/state/adapters.ts +328 -69
  170. package/src/state/document.test.ts +71 -96
  171. package/src/state/document.ts +66 -52
  172. package/src/state/helpers.test.ts +20 -0
  173. package/src/state/helpers.ts +16 -0
  174. package/src/state/index.ts +8 -0
  175. package/src/state/labRecords.test.ts +105 -0
  176. package/src/state/labRecords.ts +160 -0
  177. package/src/state/openLabStore.test.ts +658 -0
  178. package/src/state/openLabStore.ts +403 -0
  179. package/src/state/records.test.ts +234 -0
  180. package/src/state/records.ts +219 -0
  181. package/src/state/store.test.ts +104 -635
  182. package/src/state/store.ts +117 -158
  183. package/src/state/toolSlot.test.ts +1 -1
  184. package/src/state/types.ts +39 -15
  185. package/src/state/useOpenOnce.ts +68 -0
  186. package/src/state/usePersistedState.test.tsx +125 -0
  187. package/src/state/usePersistedState.ts +66 -0
  188. package/src/state/useTrialState.test.tsx +2 -3
  189. package/src/state/view.test.ts +49 -15
  190. package/src/state/view.ts +18 -1
  191. package/src/styles.less +3 -0
  192. package/src/surface/AGENTS.md +39 -7
  193. package/src/surface/SurfaceContext.ts +26 -3
  194. package/src/surface/index.ts +2 -0
  195. package/src/surface/useSurfaceTile.test.tsx +2 -1
  196. package/src/surface/useSurfaceTile.ts +6 -5
  197. package/src/surface/useTiledSurface.test.tsx +175 -0
  198. package/src/surface/useTiledSurface.ts +54 -5
  199. package/src/theme/Interstellar.stories.tsx +7 -7
  200. package/src/theme/base.less +4 -4
  201. package/src/theme/interstellar.test.ts +1 -1
  202. package/src/theme/interstellar.tokens.json +2 -2
  203. package/src/tools/labTool.ts +11 -0
  204. package/src/trial/Trial.annotations.persist.test.tsx +100 -58
  205. package/src/trial/Trial.annotations.test.tsx +47 -4
  206. package/src/trial/Trial.job.test.tsx +3 -3
  207. package/src/trial/Trial.less +1 -26
  208. package/src/trial/Trial.stories.tsx +1 -2
  209. package/src/trial/Trial.test.tsx +28 -4
  210. package/src/trial/Trial.trialId.test.tsx +23 -1
  211. package/src/trial/Trial.tsx +118 -38
  212. package/src/trial/TrialBody.tsx +17 -141
  213. package/src/trial/TrialChrome.tsx +7 -4
  214. package/src/trial/trialOps.ts +7 -4
  215. package/dist/_dts/types-BP2OCcpg.d.ts +0 -155
  216. package/dist/_dts/types-x92Kfeme.d.ts +0 -62
  217. package/dist/_dts/useTrialState-D6Vb3T-g.d.ts +0 -99
  218. package/dist/chunk-2RQPGOQF.js.map +0 -1
  219. package/dist/chunk-5TROQVQ2.js +0 -547
  220. package/dist/chunk-5TROQVQ2.js.map +0 -1
  221. package/dist/chunk-ASWKLRKJ.js.map +0 -1
  222. package/dist/chunk-C42T6DJT.js.map +0 -1
  223. package/dist/chunk-CTRKTLYZ.js.map +0 -1
  224. package/dist/chunk-FQMJUVHJ.js.map +0 -1
  225. package/dist/chunk-I6JCVE24.js.map +0 -1
  226. package/dist/chunk-MHAGC6VD.js +0 -7320
  227. package/dist/chunk-MHAGC6VD.js.map +0 -1
  228. package/dist/chunk-QAGAHJKZ.js.map +0 -1
  229. package/dist/chunk-TJ7QY3OC.js.map +0 -1
@@ -0,0 +1,237 @@
1
+ import { d as ControlRenderer, c as ConfigRule } from './types-Ca2LCnPq.js';
2
+ import { K as Instrument, aq as TrialChromeContext, N as TrialContribution, T as TrialRecord, q as InstrumentList, e as SavedSnapshot, o as LabMode, ao as ToolSlotContext, a2 as ContributionBase, ap as ToolbarItem, an as ToolItem, ah as SidebarSection, ak as StatusReadout, H as TrialTool, ad as RegionContribution, ai as SidebarSlotContext } from './frac-8R6UmlvN.js';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import * as react from 'react';
5
+ import { ReactNode } from 'react';
6
+
7
+ /**
8
+ * The contributions a trial gets from what its instrument declared. This is
9
+ * the whole "declaring a capability provides the chrome" rule — it replaces
10
+ * the presence checks that used to be spread across the runtime.
11
+ */
12
+ declare function builtinContributions(instrument: Instrument, ctx: TrialChromeContext, controls?: Record<string, ControlRenderer>): TrialContribution[];
13
+
14
+ /** What a trial opens on beyond its instrument's own defaults. */
15
+ interface AddTrialOptions<TC = Record<string, unknown>> {
16
+ /** Overlaid on `defaultConfig()` before `initialState` reads it, so a trial
17
+ * opened on a subject is running that subject from its first frame. Keys
18
+ * whose value is `undefined` are left to the default. */
19
+ config?: Partial<TC>;
20
+ }
21
+ /** Append a new trial running `instrumentName`, at that instrument's default
22
+ * config — with `options.config` written over it — and the initial state
23
+ * that config produces. */
24
+ declare function addTrial(trials: TrialRecord[], instruments: InstrumentList, instrumentName: string, options?: AddTrialOptions): TrialRecord[];
25
+ /** Insert a deep copy of a trial directly after it. The copy starts with
26
+ * an empty undo history — the original's is not shared. */
27
+ declare function cloneTrial(trials: TrialRecord[], id: string): TrialRecord[];
28
+ /** Remove a trial, unless it is the last one — a lab always has at least
29
+ * one. */
30
+ declare function closeTrial(trials: TrialRecord[], id: string): TrialRecord[];
31
+ /** Return a trial to what it opened on — its instrument's defaults under the
32
+ * seed `addTrial` was given — keeping its id and its place in the list. */
33
+ declare function resetTrial(trials: TrialRecord[], id: string, instruments: InstrumentList): TrialRecord[];
34
+ /**
35
+ * Reorder to match `ids`. Ids the list doesn't mention keep their relative
36
+ * order at the end, and ids it names that no longer exist are dropped — a
37
+ * reorder that raced a close should not resurrect the closed trial.
38
+ */
39
+ declare function reorderTrials(trials: TrialRecord[], ids: readonly string[]): TrialRecord[];
40
+
41
+ /** Lab-wide state and commands: the available instruments, the open
42
+ * trials and the operations over them, saved snapshots, and the color
43
+ * mode. */
44
+ interface LabContextValue {
45
+ instruments: InstrumentList;
46
+ trials: TrialRecord[];
47
+ /** Open a trial running `instrumentName`. `options.config` is written over
48
+ * that instrument's defaults, which is where a trial opened on a subject
49
+ * says which subject. */
50
+ addTrial: (instrumentName: string, options?: AddTrialOptions) => void;
51
+ cloneTrial: (id: string) => void;
52
+ closeTrial: (id: string) => void;
53
+ resetTrial: (id: string) => void;
54
+ reorderTrials: (ids: readonly string[]) => void;
55
+ savedSnapshots: SavedSnapshot[];
56
+ saveSnapshot: (trialId: string, name?: string) => void;
57
+ loadSnapshot: (trialId: string, snapshotId: string) => void;
58
+ deleteSnapshot: (snapshotId: string) => void;
59
+ mode: LabMode;
60
+ setMode: (m: LabMode) => void;
61
+ /** Lab-wide rules run over every instrument's config leaves, before
62
+ * labkit's own inference. */
63
+ configRules?: readonly ConfigRule[];
64
+ /** Lab-wide control overrides, keyed by config path or by leaf kind. */
65
+ controls?: Record<string, ControlRenderer>;
66
+ }
67
+ /** Context carrying the surrounding lab. Prefer `useLabContext`. */
68
+ declare const LabContext: react.Context<LabContextValue | null>;
69
+ /** The surrounding lab. Throws outside a `<Lab>`. */
70
+ declare function useLabContext(): LabContextValue;
71
+
72
+ /**
73
+ * A named position in the lab's own chrome — a box the shell owns, outside any
74
+ * one trial. `header` and `footer` are the shell's two bars, named as
75
+ * `<LabShell>` names them; `palette` is the tool rail down the side of the
76
+ * workspace; `sidebar` is a column of sections left of the tool rail.
77
+ */
78
+ type LabRegion = 'header' | 'palette' | 'sidebar' | 'footer';
79
+ /**
80
+ * Everything a lab-level contribution can read and command: the lab's own
81
+ * state and operations, plus the lab's tool slot — which every trial whose
82
+ * instrument declares no tools of its own reflects and writes.
83
+ */
84
+ interface LabChromeContext extends LabContextValue, ToolSlotContext {
85
+ }
86
+ /**
87
+ * A contribution to the lab's chrome. Shaped as `TrialContribution` is, and
88
+ * merged and suppressed by the same rules, but keyed to the lab's regions and
89
+ * rendered with the lab's context. Supplying `render` instead of `item` opts
90
+ * out of the region's layout.
91
+ *
92
+ * `TCtx` is what the chrome hands a handler. It defaults to `LabChromeContext`,
93
+ * which is what `<Lab>` renders its regions with; a consumer mounting the
94
+ * regions under a bare `<LabShell>` names whatever it passes as `ctx` instead.
95
+ */
96
+ type LabContribution<TCtx = LabChromeContext> = (ContributionBase & {
97
+ region: 'header';
98
+ item: ToolbarItem<TCtx>;
99
+ render?: never;
100
+ }) | (ContributionBase & {
101
+ region: 'palette';
102
+ item: ToolItem;
103
+ render?: never;
104
+ }) | (ContributionBase & {
105
+ region: 'sidebar';
106
+ item: SidebarSection;
107
+ render?: never;
108
+ }) | (ContributionBase & {
109
+ region: 'footer';
110
+ item: StatusReadout;
111
+ render?: never;
112
+ }) | (ContributionBase & {
113
+ region: LabRegion;
114
+ item?: never;
115
+ render: (ctx: TCtx) => ReactNode;
116
+ });
117
+
118
+ /** The lab's chrome context: the lab itself, plus the lab's tool slot. Throws
119
+ * outside a `<Lab>`. */
120
+ declare function useLabChromeContext(): LabChromeContext;
121
+ /** The lab's contributions for one region, in declaration order. */
122
+ declare function contributionsIn<TCtx = LabChromeContext>(contributions: readonly LabContribution<TCtx>[], region: LabRegion): LabContribution<TCtx>[];
123
+ /** The palette contributions a lab's `tools` stand for. Declaring a tool is
124
+ * shorthand for contributing a palette item that writes the lab's tool
125
+ * slot. */
126
+ declare function toolContributions(tools: readonly TrialTool[]): LabContribution[];
127
+ /** Everything the lab's chrome renders, from both of the ways a lab declares
128
+ * it. Tools and contributions share one id namespace, so a tool colliding
129
+ * with a contribution throws here rather than one of them silently losing. */
130
+ declare function labContributions(tools: readonly TrialTool[] | undefined, chrome: readonly LabContribution[] | undefined): LabContribution[];
131
+ /** Props shared by the lab's region mounts. Each takes the lab's whole
132
+ * contribution list and lays out the part addressed to it. */
133
+ interface LabRegionProps {
134
+ contributions: readonly LabContribution[];
135
+ }
136
+ /** The lab's action bar, in the shell header beside the title. */
137
+ declare function LabHeaderRegion({ contributions }: LabRegionProps): react_jsx_runtime.JSX.Element;
138
+ /** The lab's sidebar sections. Fold state is a lab-scoped persisted value, so it
139
+ * survives a reload in a stored lab and lasts the session in an unstored one. */
140
+ declare function LabSidebarRegion({ contributions }: LabRegionProps): react_jsx_runtime.JSX.Element;
141
+ /** The lab's readouts, in the shell footer below the workspace. */
142
+ declare function LabFooterRegion({ contributions }: LabRegionProps): react_jsx_runtime.JSX.Element;
143
+
144
+ /**
145
+ * Concatenate contribution bundles into one list, preserving order — order
146
+ * decides how a region lays its contributions out, so it is part of the
147
+ * result, not an accident of it.
148
+ *
149
+ * Throws on a duplicate id rather than dropping one: a contribution silently
150
+ * losing to a later bundle is the failure a registry exists to prevent.
151
+ */
152
+ declare function mergeContributions<T extends {
153
+ id: string;
154
+ }>(...bundles: readonly (readonly T[])[]): T[];
155
+ /**
156
+ * Drop contributions by id. Throws when an id is not present: a typo that
157
+ * silently suppresses nothing is the same class of bug as a duplicate id
158
+ * silently winning.
159
+ */
160
+ declare function suppressContributions<T extends {
161
+ id: string;
162
+ }>(bundle: readonly T[], ids: readonly string[]): T[];
163
+
164
+ /** Props for `<PaletteRegion>`. */
165
+ interface PaletteRegionProps<TCtx extends ToolSlotContext = TrialChromeContext> {
166
+ contributions: readonly RegionContribution<NoInfer<TCtx>>[];
167
+ ctx: TCtx;
168
+ /** Which region's items to lay out. The lab's rail names the same box
169
+ * `palette` too, so this only moves for a chrome that does not. */
170
+ region?: string;
171
+ }
172
+ /** A tool strip: a trial's, or the lab's. Selection lives in whichever tool
173
+ * slot the context carries; this region only reflects it. */
174
+ declare function PaletteRegion<TCtx extends ToolSlotContext = TrialChromeContext>({ contributions, ctx, region, }: PaletteRegionProps<TCtx>): react_jsx_runtime.JSX.Element | null;
175
+
176
+ /** Props for `<SidebarRegion>`. */
177
+ interface SidebarRegionProps<TCtx extends SidebarSlotContext = TrialChromeContext> {
178
+ contributions: readonly RegionContribution<NoInfer<TCtx>>[];
179
+ ctx: TCtx;
180
+ /** Which region's items to lay out. */
181
+ region?: string;
182
+ }
183
+ /** Lays `sidebar` contributions out as titled, collapsible sections — a
184
+ * trial's, or the lab's. A section the trial has torn out is not rendered
185
+ * here — `Trial` portals its body into the workspace instead. A context with
186
+ * no `undockPanel` offers no tear-out. */
187
+ declare function SidebarRegion<TCtx extends SidebarSlotContext = TrialChromeContext>({ contributions, ctx, region, }: SidebarRegionProps<TCtx>): react_jsx_runtime.JSX.Element | null;
188
+
189
+ /** Props for `<StatusRegion>`. */
190
+ interface StatusRegionProps<TCtx = TrialChromeContext> {
191
+ contributions: readonly RegionContribution<NoInfer<TCtx>>[];
192
+ ctx: TCtx;
193
+ /** Which region's readouts to lay out; the lab's footer is `footer`. */
194
+ region?: string;
195
+ }
196
+ /** Lays a bar's readouts out. */
197
+ declare function StatusRegion<TCtx = TrialChromeContext>({ contributions, ctx, region, }: StatusRegionProps<TCtx>): react_jsx_runtime.JSX.Element | null;
198
+
199
+ /** Which end of the title bar a `<TitleBarRegion>` lays out: `'lead'` renders
200
+ * the contributions that leave `end` unset, before the title; `'actions'`
201
+ * renders the ones that set it, after everything else. */
202
+ type TitleBarPlacement = 'lead' | 'actions';
203
+ /** Props for `<TitleBarRegion>`. */
204
+ interface TitleBarRegionProps {
205
+ contributions: readonly TrialContribution[];
206
+ ctx: TrialChromeContext;
207
+ /** Defaults to `'actions'`, where the built-ins live. */
208
+ placement?: TitleBarPlacement;
209
+ }
210
+ /** Lays a trial's `titlebar` contributions out at one end of the bar. */
211
+ declare function TitleBarRegion({ contributions, ctx, placement }: TitleBarRegionProps): react_jsx_runtime.JSX.Element | null;
212
+
213
+ /** Props for `<ToolbarRegion>`. */
214
+ interface ToolbarRegionProps<TCtx = TrialChromeContext> {
215
+ contributions: readonly RegionContribution<NoInfer<TCtx>>[];
216
+ ctx: TCtx;
217
+ /** Which region's items to lay out; the lab's action bar is `header`. */
218
+ region?: string;
219
+ /** The bar's accessible name. */
220
+ label?: string;
221
+ }
222
+ /** Lays a bar's contributions out, grouped by their `group`. */
223
+ declare function ToolbarRegion<TCtx = TrialChromeContext>({ contributions, ctx, region, label, }: ToolbarRegionProps<TCtx>): react_jsx_runtime.JSX.Element | null;
224
+
225
+ /** Props for `<ViewportRegion>`. */
226
+ interface ViewportRegionProps {
227
+ contributions: readonly TrialContribution[];
228
+ ctx: TrialChromeContext;
229
+ }
230
+ /**
231
+ * Controls acting on the view of a trial. Anchored inside the content well
232
+ * rather than in the toolbar, which acts on the trial itself.
233
+ */
234
+ declare function ViewportRegion({ contributions, ctx }: ViewportRegionProps): react_jsx_runtime.JSX.Element | null;
235
+
236
+ export { suppressContributions as B, toolContributions as C, useLabChromeContext as D, useLabContext as E, PaletteRegion as P, SidebarRegion as S, ViewportRegion as V, LabContext as b, LabFooterRegion as d, LabHeaderRegion as e, LabSidebarRegion as h, StatusRegion as k, TitleBarRegion as m, ToolbarRegion as o, addTrial as r, builtinContributions as s, cloneTrial as t, closeTrial as u, contributionsIn as v, labContributions as w, mergeContributions as x, reorderTrials as y, resetTrial as z };
237
+ export type { AddTrialOptions as A, LabContribution as L, TitleBarPlacement as T, LabChromeContext as a, LabContextValue as c, LabRegion as f, LabRegionProps as g, PaletteRegionProps as i, SidebarRegionProps as j, StatusRegionProps as l, TitleBarRegionProps as n, ToolbarRegionProps as p, ViewportRegionProps as q };
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { R as ResolvedConfig, c as ControlRenderer } from './types-B9_zrHmb.js';
4
- import { C as ConfigField } from './types-x92Kfeme.js';
3
+ import { ToolPrefNumberFormat } from '@weasel-js/core';
4
+ import { R as ResolvedConfig, a as ConfigField, d as ControlRenderer } from './types-Ca2LCnPq.js';
5
5
 
6
6
  /**
7
7
  * How much room a container gives its rows — gaps, padding, and field height,
@@ -126,6 +126,8 @@ interface SliderRowProps extends PropertyMetricProps {
126
126
  onInput?: (next: number) => void;
127
127
  /** Override how the value is rendered next to the label. Defaults to `value.toString()`. */
128
128
  format?: (value: number) => ReactNode;
129
+ /** A named display for the value: `compact` reads `2.0M`. `format` wins when both are given. */
130
+ notation?: ToolPrefNumberFormat;
129
131
  /**
130
132
  * Optional suffix rendered next to the readout. A string becomes a
131
133
  * baseline-aligned dim "word" unit (e.g. "px"); pass JSX like `<sup>°</sup>`
@@ -139,15 +141,29 @@ interface SliderRowProps extends PropertyMetricProps {
139
141
  }
140
142
  /** A bounded number edited by dragging, with a live readout whose precision
141
143
  * follows `step`. */
142
- declare function SliderRow({ label, value, min, max, step, onChange, onInput, format, unit, layout, description, span, density, align, }: SliderRowProps): react_jsx_runtime.JSX.Element;
144
+ declare function SliderRow({ label, value, min, max, step, onChange, onInput, format, notation, unit, layout, description, span, density, align, }: SliderRowProps): react_jsx_runtime.JSX.Element;
143
145
  /** Props for `<ColorRow>`. */
144
146
  interface ColorRowProps extends PropertyMetricProps {
145
147
  label: ReactNode;
146
148
  value: string;
149
+ /**
150
+ * The committed color. Given `onInput` as well, it fires once the picker
151
+ * closes; on its own it fires on every move inside it, which is what a row
152
+ * with one callback has always done.
153
+ */
147
154
  onChange: (next: string) => void;
155
+ /**
156
+ * The live color, fired continuously while the picker is open. Pass it
157
+ * alongside `onChange` when the write is expensive — cheap state here, the
158
+ * costly work there. Mirrors `<Slider>`'s `onInput` / `onChange` pair.
159
+ */
160
+ onInput?: (next: string) => void;
148
161
  /** 0..1 alpha. When provided, a translucent slider renders beneath the swatch. */
149
162
  alpha?: number;
163
+ /** The committed alpha, on the same terms as `onChange`. */
150
164
  onAlphaChange?: (next: number) => void;
165
+ /** The live alpha, on the same terms as `onInput`. */
166
+ onAlphaInput?: (next: number) => void;
151
167
  /**
152
168
  * Render the alpha track as inert (dimmed, no thumb, not-allowed cursor).
153
169
  * Use when the color's consumer drops alpha so the affordance reads dead.
@@ -160,11 +176,12 @@ interface ColorRowProps extends PropertyMetricProps {
160
176
  span?: boolean;
161
177
  }
162
178
  /** A color swatch, optionally with an alpha slider beneath it. */
163
- declare function ColorRow({ label, value, onChange, alpha, onAlphaChange, alphaDisabled, layout, description, span, density, align, }: ColorRowProps): react_jsx_runtime.JSX.Element;
179
+ declare function ColorRow({ label, value, onChange, onInput, alpha, onAlphaChange, onAlphaInput, alphaDisabled, layout, description, span, density, align, }: ColorRowProps): react_jsx_runtime.JSX.Element;
164
180
  /** Props for `<CheckboxRow>`. */
165
181
  interface CheckboxRowProps extends PropertyMetricProps {
166
182
  label: ReactNode;
167
- value: boolean;
183
+ /** Absent reads as unchecked. */
184
+ value: boolean | undefined;
168
185
  onChange: (next: boolean) => void;
169
186
  /** Label beside the box (default) or above it. */
170
187
  layout?: PropertyRowLayout;
@@ -177,7 +194,8 @@ declare function CheckboxRow({ label, value, onChange, layout, span, description
177
194
  /** Props for `<TextRow>`. */
178
195
  interface TextRowProps extends PropertyMetricProps {
179
196
  label: ReactNode;
180
- value: string;
197
+ /** Absent reads as an empty field. */
198
+ value: string | null | undefined;
181
199
  onChange: (next: string) => void;
182
200
  placeholder?: string;
183
201
  maxLength?: number;
@@ -191,8 +209,20 @@ declare function TextRow({ label, value, onChange, placeholder, maxLength, layou
191
209
  /** Props for `<NumberRow>`. */
192
210
  interface NumberRowProps extends PropertyMetricProps {
193
211
  label: ReactNode;
194
- value: number;
212
+ /** Absent reads as an empty field. */
213
+ value: number | null | undefined;
214
+ /**
215
+ * The committed value. Given `onInput` as well, it fires on blur or Enter;
216
+ * on its own it fires on every keystroke, which is what a row with one
217
+ * callback has always done.
218
+ */
195
219
  onChange: (next: number) => void;
220
+ /**
221
+ * The live value, fired per keystroke. Pass it alongside `onChange` when the
222
+ * write is expensive — cheap state here, the costly work there. Mirrors
223
+ * `<Slider>`'s `onInput` / `onChange` pair.
224
+ */
225
+ onInput?: (next: number) => void;
196
226
  min?: number;
197
227
  max?: number;
198
228
  step?: number;
@@ -210,7 +240,7 @@ interface NumberRowProps extends PropertyMetricProps {
210
240
  }
211
241
  /** A number typed directly. Reach for `<SliderRow>` when the range matters
212
242
  * more than the exact value. */
213
- declare function NumberRow({ label, value, onChange, min, max, step, placeholder, unit, layout, description, span, density, align, }: NumberRowProps): react_jsx_runtime.JSX.Element;
243
+ declare function NumberRow({ label, value, onChange, onInput, min, max, step, placeholder, unit, layout, description, span, density, align, }: NumberRowProps): react_jsx_runtime.JSX.Element;
214
244
  interface PropertyOption<T extends string> {
215
245
  value: T;
216
246
  label: ReactNode;
@@ -218,9 +248,12 @@ interface PropertyOption<T extends string> {
218
248
  /** Props for `<SelectRow>`. */
219
249
  interface SelectRowProps<T extends string> extends PropertyMetricProps {
220
250
  label: ReactNode;
221
- value: T;
251
+ /** Absent, or not one of `options`, shows a placeholder rather than the first option. */
252
+ value: T | undefined;
222
253
  options: ReadonlyArray<PropertyOption<T>>;
223
254
  onChange: (next: T) => void;
255
+ /** Shown while no option is chosen. Defaults to "Choose option…". */
256
+ placeholder?: string;
224
257
  layout?: PropertyRowLayout;
225
258
  description?: string;
226
259
  /** Take the full width of the enclosing grid — see `<PropertyRow span>`. */
@@ -228,7 +261,7 @@ interface SelectRowProps<T extends string> extends PropertyMetricProps {
228
261
  }
229
262
  /** A dropdown over a fixed set of choices. Prefer `<ToggleRow>` when there
230
263
  * are only two or three and they should all stay visible. */
231
- declare function SelectRow<T extends string>({ label, value, options, onChange, layout, description, span, density, align, }: SelectRowProps<T>): react_jsx_runtime.JSX.Element;
264
+ declare function SelectRow<T extends string>({ label, value, options, onChange, placeholder, layout, description, span, density, align, }: SelectRowProps<T>): react_jsx_runtime.JSX.Element;
232
265
  /** Props for `<ToggleRow>`. */
233
266
  interface ToggleRowProps<T extends string> extends PropertyMetricProps {
234
267
  label: ReactNode;
@@ -245,12 +278,12 @@ interface ToggleRowProps<T extends string> extends PropertyMetricProps {
245
278
  declare function ToggleRow<T extends string>({ label, value, options, onChange, layout, description, span, density, align, }: ToggleRowProps<T>): react_jsx_runtime.JSX.Element;
246
279
 
247
280
  /** How a panel packs its rows into the two-column property grid.
248
- * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colours) sit
281
+ * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colors) sit
249
282
  * two per row; the ones that need the width — text, sliders, segmented
250
283
  * toggles — span it.
251
284
  * - `'pairs'`: every row pairs. A control that needs the full width says so
252
285
  * itself, with `<PropertyRow span>`.
253
- * - `'one-up'`: one control per row, colours excepted.
286
+ * - `'one-up'`: one control per row, colors excepted.
254
287
  */
255
288
  type ControlPack = 'auto' | 'pairs' | 'one-up';
256
289
  interface ControlPanelProps<TC extends Record<string, unknown>> {
@@ -1,4 +1,4 @@
1
- import { ToolPrefLeaf, ToolPrefGroup } from '@weasel-js/core';
1
+ import { ToolPrefNumberFormat, ToolPrefLeaf, ToolPrefGroup } from '@weasel-js/core';
2
2
  import { P as PrefRenderer } from './PrefsForm.d-DDHFANkc.js';
3
3
 
4
4
  /**
@@ -24,6 +24,8 @@ interface Annotations {
24
24
  max?: number;
25
25
  step?: number;
26
26
  suffix?: string;
27
+ /** How a number's value is shown. `compact` abbreviates from a thousand up. */
28
+ format?: ToolPrefNumberFormat;
27
29
  control?: string;
28
30
  options?: readonly ConfigOption[];
29
31
  placeholder?: string;
@@ -163,4 +165,65 @@ interface ConfigSchema<TC> {
163
165
  /** The config type behind a schema: `ConfigOf<typeof sceneConfig>`. */
164
166
  type ConfigOf<S> = S extends ConfigSchema<infer TC> ? TC : never;
165
167
 
166
- export type { Annotations as A, BranchAnnotations as B, ConfigPath as C, EntryValue as E, InferConfig as I, LeafPatch as L, NodeOptions as N, ResolvedConfig as R, SectionSpec as S, ValueAtPath as V, ConfigSchema as a, ConfigNode as b, ControlRenderer as c, ConfigOption as d, ConfigShape as e, ConfigBranch as f, BranchOptions as g, ConfigEntry as h, ConfigRule as i, ConfigRuleContext as j, ConfigOf as k, NodeValue as l };
168
+ /** Which control a config field is edited with. */
169
+ type ConfigFieldType = 'slider' | 'checkbox' | 'select' | 'number' | 'text' | 'color';
170
+ /** What every config field carries: the config key it writes, the label shown
171
+ * beside it, and which control renders it. */
172
+ interface ConfigFieldBase {
173
+ key: string;
174
+ label: string;
175
+ type: ConfigFieldType;
176
+ }
177
+ /** A bounded number edited by dragging. */
178
+ interface SliderField extends ConfigFieldBase {
179
+ type: 'slider';
180
+ default: number;
181
+ min: number;
182
+ max: number;
183
+ step?: number;
184
+ }
185
+ /** A boolean. */
186
+ interface CheckboxField extends ConfigFieldBase {
187
+ type: 'checkbox';
188
+ default: boolean;
189
+ }
190
+ /** One choice in a select field. */
191
+ interface SelectOption {
192
+ value: string;
193
+ label: string;
194
+ }
195
+ /** A fixed set of labeled choices. */
196
+ interface SelectField extends ConfigFieldBase {
197
+ type: 'select';
198
+ default: string;
199
+ options: SelectOption[];
200
+ }
201
+ /** A number typed directly, optionally bounded. Use a slider field instead
202
+ * when the range matters more than the exact value. */
203
+ interface NumberField extends ConfigFieldBase {
204
+ type: 'number';
205
+ default: number;
206
+ min?: number;
207
+ max?: number;
208
+ step?: number;
209
+ }
210
+ /** A free-text string. Writes are debounced so typing does not re-run the
211
+ * instrument on every keystroke. */
212
+ interface TextField extends ConfigFieldBase {
213
+ type: 'text';
214
+ default: string;
215
+ placeholder?: string;
216
+ maxLength?: number;
217
+ /** Milliseconds to debounce live setConfig calls. Default 150 ms. Set to 0 to disable. */
218
+ debounceMs?: number;
219
+ }
220
+ /** A color, as a CSS color string. */
221
+ interface ColorField extends ConfigFieldBase {
222
+ type: 'color';
223
+ default: string;
224
+ }
225
+ /** One field of an instrument's config schema. The schema is what the control
226
+ * panel renders, and what `validateConfigSchema` checks. */
227
+ type ConfigField = SliderField | CheckboxField | SelectField | NumberField | TextField | ColorField;
228
+
229
+ export type { Annotations as A, BranchAnnotations as B, ConfigPath as C, EntryValue as E, InferConfig as I, LeafPatch as L, NodeOptions as N, ResolvedConfig as R, SectionSpec as S, TextField as T, ValueAtPath as V, ConfigField as a, ConfigSchema as b, ConfigRule as c, ControlRenderer as d, BranchOptions as e, CheckboxField as f, ColorField as g, ConfigBranch as h, ConfigEntry as i, ConfigFieldBase as j, ConfigFieldType as k, ConfigNode as l, ConfigOf as m, ConfigOption as n, ConfigRuleContext as o, ConfigShape as p, NodeValue as q, NumberField as r, SelectField as s, SelectOption as t, SliderField as u };
@@ -0,0 +1,160 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode, WheelEvent, PointerEvent as PointerEvent$1 } from 'react';
3
+ import { k as ViewTransform, a as WorldSpec, V as ViewportSize, l as Point, W as WorldFrame } from './frac-8R6UmlvN.js';
4
+ import { C as CanvasLayerDescriptor } from './CanvasStackContext-CqkxkFJW.js';
5
+
6
+ /** Props for `<CanvasStack>`. */
7
+ interface CanvasStackProps {
8
+ layers: CanvasLayerDescriptor[];
9
+ view: ViewTransform;
10
+ onViewChange: (v: ViewTransform) => void;
11
+ /** The instrument's coordinate system. Omitted, world (0,0) sits at the
12
+ * element's top-left with y running down. */
13
+ worldSpec?: WorldSpec;
14
+ minZoom?: number;
15
+ maxZoom?: number;
16
+ width?: number | string;
17
+ height?: number | string;
18
+ className?: string;
19
+ /** Fired whenever the stack is measured, so a consumer can place a view that
20
+ * only makes sense in terms of the viewport. */
21
+ onResize?: (size: ViewportSize) => void;
22
+ onHitTest?: (worldPos: Point) => void;
23
+ children?: ReactNode;
24
+ }
25
+ /** Stacks one `<canvas>` per layer and drives them from a shared view, so a
26
+ * layer that changes rarely is not redrawn with one that changes every frame.
27
+ * Handles sizing, device pixel ratio, and pan/zoom. */
28
+ declare function CanvasStack({ layers, view: viewProp, onViewChange, worldSpec, minZoom, maxZoom, width, height, className, onResize, onHitTest, children, }: CanvasStackProps): react_jsx_runtime.JSX.Element;
29
+
30
+ /** Bounds and coordinate system a {@link zoomAt} works in. */
31
+ interface ZoomAtOptions {
32
+ /** The instrument's coordinate system, resolved against the viewport.
33
+ * Omitted, `at` is measured from the element's top-left. */
34
+ frame?: WorldFrame;
35
+ min?: number;
36
+ max?: number;
37
+ }
38
+ /**
39
+ * Zoom a view by `factor` about a fixed point, so whatever world coordinate
40
+ * `at` was over stays under it.
41
+ *
42
+ * `at` is in the element's own pixels — a cursor position, or the centre of a
43
+ * lens. The clamp is applied before the pan is solved, so a zoom that hits a
44
+ * bound still anchors on the zoom it actually reached.
45
+ */
46
+ declare function zoomAt(view: ViewTransform, factor: number, at: Point, { frame, min, max }?: ZoomAtOptions): ViewTransform;
47
+ /** The view that puts a world point at the centre of a `size` viewport, at
48
+ * `zoom`. What a lens showing a region around one point renders through. */
49
+ declare function centerOn(world: Point, zoom: number, size: ViewportSize, frame?: WorldFrame): ViewTransform;
50
+
51
+ /** Project a world point into screen coordinates under a view.
52
+ *
53
+ * `frame` is the instrument's declared coordinate system, resolved against the
54
+ * viewport; omitting it gives labkit's original one — origin at the top-left,
55
+ * y downward. */
56
+ declare function worldToScreen(world: Point, view: ViewTransform, frame?: WorldFrame): Point;
57
+ /** Unproject a screen point back to world coordinates under a view. */
58
+ declare function screenToWorld(screen: Point, view: ViewTransform, frame?: WorldFrame): Point;
59
+
60
+ /** Props for `<Stage>`. */
61
+ interface StageProps {
62
+ /** The content's own size in CSS pixels, at zoom 1. */
63
+ size: ViewportSize;
64
+ view: ViewTransform;
65
+ onViewChange: (v: ViewTransform) => void;
66
+ minZoom?: number;
67
+ maxZoom?: number;
68
+ /** Fired whenever the stage's viewport is measured at a non-zero size. */
69
+ onResize?: (viewport: ViewportSize) => void;
70
+ /** Handed the viewport element, for a consumer tracking the pointer over it. */
71
+ hostRef?: {
72
+ current: HTMLDivElement | null;
73
+ };
74
+ /** Drawn over the content in viewport pixels, outside the camera. */
75
+ overlay?: ReactNode;
76
+ children?: ReactNode;
77
+ }
78
+ /**
79
+ * The camera a stage opens at: the content centered in its viewport, shrunk to
80
+ * fit if it has to be and never enlarged past its own size.
81
+ */
82
+ declare function fitStage(size: ViewportSize, viewport: ViewportSize): ViewTransform;
83
+ /**
84
+ * DOM content of a fixed size, panned and zoomed by a camera — what
85
+ * `<CanvasStack>` is for layers drawn to a canvas. The content is laid out at
86
+ * its own size and transformed, so everything inside keeps its layout and a
87
+ * measurement of any element in it reports where it is actually drawn.
88
+ */
89
+ declare function Stage({ size, view: viewProp, onViewChange, minZoom, maxZoom, onResize, hostRef, overlay, children, }: StageProps): react_jsx_runtime.JSX.Element;
90
+
91
+ /** A point in the space the instrument works in. */
92
+ interface Vec3 {
93
+ x: number;
94
+ y: number;
95
+ z: number;
96
+ }
97
+ /** An orbit camera as a trial view: where it looks from, and what it looks at.
98
+ * labkit does not turn this into a matrix — the host's renderer does. */
99
+ interface OrbitView {
100
+ yaw: number;
101
+ pitch: number;
102
+ distance: number;
103
+ target: Vec3;
104
+ }
105
+ /** Just short of the pole. At exactly ±PI/2 the azimuth is undefined and the
106
+ * camera rolls, which reads as the model jumping rather than as a limit. */
107
+ declare const PITCH_LIMIT: number;
108
+ declare function clampPitch(pitch: number): number;
109
+ declare function wrapYaw(yaw: number): number;
110
+ /** The view a drag of (dx, dy) from `start` produces. Absolute against the drag
111
+ * start, so it can be re-applied any number of times without compounding. */
112
+ declare function orbitAfterDrag(start: OrbitView, dx: number, dy: number): OrbitView;
113
+ /** Multiplicative, so one notch covers the same proportion of the distance
114
+ * whether the camera is near or far. */
115
+ declare function orbitAfterWheel(view: OrbitView, deltaY: number, minDistance: number, maxDistance: number): OrbitView;
116
+ interface UseOrbitOptions {
117
+ view: OrbitView;
118
+ onViewChange: (v: OrbitView) => void;
119
+ /** Restored on double-click. Defaults to the view the hook first saw. */
120
+ home?: OrbitView;
121
+ minDistance?: number;
122
+ maxDistance?: number;
123
+ }
124
+ interface OrbitHandlers {
125
+ onWheel: (e: WheelEvent<HTMLElement>) => void;
126
+ onPointerDown: (e: PointerEvent$1<HTMLElement>) => void;
127
+ onDoubleClick: () => void;
128
+ isDragging: () => boolean;
129
+ }
130
+ /** Pointer gestures over an orbit view: drag to turn, wheel or pinch to dolly,
131
+ * double-click to go home. The 3D peer of `usePanZoom`. */
132
+ declare function useOrbit({ view, onViewChange, home, minDistance, maxDistance, }: UseOrbitOptions): OrbitHandlers;
133
+
134
+ interface UsePanZoomOptions {
135
+ view: ViewTransform;
136
+ onViewChange: (v: ViewTransform) => void;
137
+ /** The opening `view.zoom` always stays reachable, widening these past
138
+ * whatever is passed here if it would otherwise exclude it. */
139
+ minZoom?: number;
140
+ maxZoom?: number;
141
+ /** The instrument's coordinate system, resolved against the viewport. The
142
+ * wheel anchors in this frame; omitting it anchors at the element's
143
+ * top-left, which is what labkit did before a frame could be declared. */
144
+ frame?: WorldFrame;
145
+ /** A primary-button press released without ever crossing the drag
146
+ * threshold. The pointer session owns the release, so the gesture's end is
147
+ * reported here rather than left for a consumer's own `onPointerUp`. */
148
+ onTap?: (e: PointerEvent) => void;
149
+ }
150
+ interface PanZoomHandlers {
151
+ /** Zoom about the pointer. `anchor` is the element the pointer position is
152
+ * measured against, for an event whose `currentTarget` is some other box. */
153
+ onWheel: (e: WheelEvent<HTMLElement> | globalThis.WheelEvent, anchor?: Element) => void;
154
+ onPointerDown: (e: PointerEvent$1<HTMLElement>) => void;
155
+ isDragging: () => boolean;
156
+ }
157
+ declare function usePanZoom({ view, onViewChange, minZoom, maxZoom, frame, onTap, }: UsePanZoomOptions): PanZoomHandlers;
158
+
159
+ export { CanvasStack as C, PITCH_LIMIT as P, Stage as S, centerOn as f, clampPitch as g, fitStage as h, orbitAfterWheel as i, usePanZoom as j, wrapYaw as k, orbitAfterDrag as o, screenToWorld as s, useOrbit as u, worldToScreen as w, zoomAt as z };
160
+ export type { OrbitHandlers as O, UseOrbitOptions as U, Vec3 as V, ZoomAtOptions as Z, CanvasStackProps as a, OrbitView as b, PanZoomHandlers as c, StageProps as d, UsePanZoomOptions as e };