@weasel-js/labkit 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_dts/{CanvasStackContext-Wo6OwIVM.d.ts → CanvasStackContext-D2jnIwfk.d.ts} +1 -1
- package/dist/_dts/{LayerList.d-BoELAMsM.d.ts → LayerList.d-DiuEArKq.d.ts} +2 -2
- package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +79 -0
- package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +141 -0
- package/dist/_dts/{Select.d-Cr8-zoup.d.ts → Select.d-Bensr_MT.d.ts} +11 -1
- package/dist/_dts/{Stage-DWBBi8IU.d.ts → Stage-CCWfQQWM.d.ts} +58 -18
- package/dist/_dts/index-B2Yj5aA0.d.ts +274 -0
- package/dist/_dts/{index-CKyX0ME_.d.ts → index-CsYqUHD3.d.ts} +2 -2
- package/dist/_dts/{types-DTuViBvc.d.ts → types-CRPSGFAp.d.ts} +13 -4
- package/dist/_dts/{types-B7yBTTF9.d.ts → types-CSm9jgol.d.ts} +2 -2
- package/dist/_dts/{useTrialState-CMaV6UD4.d.ts → useTrialState-CTZPgeZ7.d.ts} +1 -1
- package/dist/canvas/index.d.ts +6 -6
- package/dist/canvas/index.js +2 -2
- package/dist/chrome/index.d.ts +5 -5
- package/dist/chrome/index.js +8 -8
- package/dist/{chunk-QGMOA2YE.js → chunk-275JRRVD.js} +67 -70
- package/dist/chunk-275JRRVD.js.map +1 -0
- package/dist/{chunk-KHK5FGER.js → chunk-4LJSC7MB.js} +8 -10
- package/dist/chunk-4LJSC7MB.js.map +1 -0
- package/dist/{chunk-SLAQPUI4.js → chunk-7BO7HNGF.js} +5 -5
- package/dist/{chunk-SLAQPUI4.js.map → chunk-7BO7HNGF.js.map} +1 -1
- package/dist/chunk-CZZPXUOU.js +3 -0
- package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
- package/dist/{chunk-6FLXL3I7.js → chunk-FMK7UQ6V.js} +19 -4
- package/dist/chunk-FMK7UQ6V.js.map +1 -0
- package/dist/{chunk-O6FFFOHS.js → chunk-FZ7YFQN7.js} +16 -8
- package/dist/chunk-FZ7YFQN7.js.map +1 -0
- package/dist/{chunk-GHGO52SO.js → chunk-GOZLNM4L.js} +5 -5
- package/dist/{chunk-GHGO52SO.js.map → chunk-GOZLNM4L.js.map} +1 -1
- package/dist/{chunk-4TT3PNPR.js → chunk-I5DUQ5HM.js} +33 -36
- package/dist/chunk-I5DUQ5HM.js.map +1 -0
- package/dist/{chunk-NEXR37YJ.js → chunk-J7OWWTCW.js} +4 -5
- package/dist/chunk-J7OWWTCW.js.map +1 -0
- package/dist/{chunk-IRTGUQ5O.js → chunk-KMJ7RWD3.js} +16 -6
- package/dist/chunk-KMJ7RWD3.js.map +1 -0
- package/dist/{chunk-S4NCI32V.js → chunk-M7HP3FTK.js} +4 -4
- package/dist/{chunk-S4NCI32V.js.map → chunk-M7HP3FTK.js.map} +1 -1
- package/dist/chunk-MIM5R4ZT.js +14972 -0
- package/dist/chunk-MIM5R4ZT.js.map +1 -0
- package/dist/{chunk-ASOK76ZH.js → chunk-T5IBSPAM.js} +59 -26
- package/dist/chunk-T5IBSPAM.js.map +1 -0
- package/dist/{chunk-DWMSB4CA.js → chunk-UNAZSLWE.js} +82 -16
- package/dist/chunk-UNAZSLWE.js.map +1 -0
- package/dist/{chunk-TJ77A4A3.js → chunk-Y23G2VZL.js} +5 -9
- package/dist/chunk-Y23G2VZL.js.map +1 -0
- package/dist/{chunk-HKV7LRHY.js → chunk-YT75VYRD.js} +4 -4
- package/dist/{chunk-HKV7LRHY.js.map → chunk-YT75VYRD.js.map} +1 -1
- package/dist/{chunk-CGHF6RZV.js → chunk-ZIFPHIWZ.js} +9 -7
- package/dist/chunk-ZIFPHIWZ.js.map +1 -0
- package/dist/config/index.d.ts +16 -9
- package/dist/config/index.js +4 -4
- package/dist/controls/index.d.ts +2 -2
- package/dist/controls/index.js +5 -5
- package/dist/dragdrop/index.d.ts +3 -3
- package/dist/index.d.ts +263 -24
- package/dist/index.js +376 -237
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +4 -4
- package/dist/layers/index.js +2 -2
- package/dist/loupe/index.d.ts +4 -4
- package/dist/loupe/index.js +2 -2
- package/dist/overview/index.d.ts +2 -2
- package/dist/overview/index.js +9 -8
- package/dist/overview/index.js.map +1 -1
- package/dist/passthrough/weasel-ui.d.ts +208 -38
- package/dist/passthrough/weasel-ui.js +3 -3
- package/dist/primitives/index.d.ts +3 -178
- package/dist/primitives/index.js +6 -6
- package/dist/state/index.d.ts +5 -5
- package/dist/state/index.js +4 -4
- package/dist/styles.css +91 -83
- package/dist/undo/index.d.ts +3 -3
- package/package.json +13 -12
- package/src/annotations/AnnotationOverlay.tsx +2 -2
- package/src/annotations/Annotations.less +0 -10
- package/src/annotations/MarkList.tsx +4 -8
- package/src/annotations/paint.test.ts +3 -14
- package/src/annotations/paint.ts +3 -19
- package/src/annotations/svgNodes.test.ts +6 -9
- package/src/annotations/svgNodes.ts +3 -3
- package/src/canvas/AGENTS.md +1 -0
- package/src/canvas/CameraInput.tsx +44 -33
- package/src/canvas/CanvasStack.tsx +6 -1
- package/src/canvas/LinkedCursor.less +1 -1
- package/src/canvas/Stage.test.tsx +33 -4
- package/src/canvas/Stage.tsx +6 -1
- package/src/canvas/cameraRegistry.test.ts +55 -0
- package/src/canvas/cameraRegistry.ts +86 -0
- package/src/canvas/cameraZoom.test.ts +46 -0
- package/src/canvas/cameraZoom.ts +24 -0
- package/src/canvas/index.ts +14 -2
- package/src/canvas/sharedScope.test.tsx +94 -0
- package/src/chrome/ChromeRegions.stories.tsx +1 -0
- package/src/chrome/regions/PaletteRegion.less +0 -7
- package/src/chrome/regions/SidebarRegion.less +12 -2
- package/src/config/builder.test.ts +2 -1
- package/src/config/builder.ts +12 -5
- package/src/config/fromConfigField.test.ts +14 -0
- package/src/config/fromConfigField.ts +18 -4
- package/src/config/path.ts +2 -5
- package/src/config/resolve.ts +4 -0
- package/src/config/types.ts +13 -9
- package/src/controls/ControlPanel.less +1 -1
- package/src/controls/ControlPanel.stories.tsx +3 -2
- package/src/controls/ControlPanel.test.tsx +64 -11
- package/src/controls/ControlPanel.tsx +52 -2
- package/src/index.ts +15 -1
- package/src/lab/Lab.tsx +83 -72
- package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
- package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
- package/src/lab/LabFullChrome.stories.tsx +1 -0
- package/src/lab/LabHeader.test.tsx +24 -14
- package/src/lab/LabHeader.tsx +11 -12
- package/src/lab/LabShell.less +8 -17
- package/src/lab/LabSwitcher.less +6 -6
- package/src/lab/LabZoom.test.tsx +223 -0
- package/src/lab/LabZoom.tsx +170 -0
- package/src/lab/index.ts +1 -0
- package/src/loupe/LoupeGestures.tsx +1 -1
- package/src/overview/TrialOverview.tsx +7 -5
- package/src/passthrough/weasel-ui.test.ts +2 -0
- package/src/passthrough/weasel-ui.ts +16 -4
- package/src/primitives/FloatingPanel.test.tsx +11 -0
- package/src/primitives/FloatingPanel.tsx +2 -5
- package/src/primitives/JobProgress.less +1 -1
- package/src/primitives/Legend.stories.tsx +1 -0
- package/src/primitives/Readout.browser.test.tsx +137 -0
- package/src/primitives/Readout.less +12 -0
- package/src/primitives/Readout.stories.tsx +58 -0
- package/src/primitives/Readout.test.tsx +93 -0
- package/src/primitives/Readout.tsx +56 -0
- package/src/primitives/index.ts +2 -0
- package/src/specimen/Specimen.stories.tsx +1 -0
- package/src/specimen/Specimen.tsx +2 -2
- package/src/state/Persistence.browser.test.tsx +47 -0
- package/src/state/store.test.ts +5 -1
- package/src/state/usePersistedState.test.tsx +1 -1
- package/src/styles.less +1 -0
- package/src/theme/Interstellar.stories.tsx +3 -1
- package/src/theme/base.less +21 -47
- package/src/theme/interstellar.test.ts +1 -1
- package/src/theme/interstellar.theme.json +10 -3
- package/src/trial/Trial.less +0 -13
- package/src/trial/Trial.tsx +12 -6
- package/src/trial/TrialChrome.tsx +21 -3
- package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
- package/dist/_dts/PropertyField.d-D0ndfIIt.d.ts +0 -404
- package/dist/chunk-4TT3PNPR.js.map +0 -1
- package/dist/chunk-6FLXL3I7.js.map +0 -1
- package/dist/chunk-ASOK76ZH.js.map +0 -1
- package/dist/chunk-CGHF6RZV.js.map +0 -1
- package/dist/chunk-DWMSB4CA.js.map +0 -1
- package/dist/chunk-IRTGUQ5O.js.map +0 -1
- package/dist/chunk-KHK5FGER.js.map +0 -1
- package/dist/chunk-NEXR37YJ.js.map +0 -1
- package/dist/chunk-O6FFFOHS.js.map +0 -1
- package/dist/chunk-QGMOA2YE.js.map +0 -1
- package/dist/chunk-SBXNQW4G.js +0 -3
- package/dist/chunk-TJ77A4A3.js.map +0 -1
- package/dist/chunk-TYN6MLXX.js +0 -13864
- package/dist/chunk-TYN6MLXX.js.map +0 -1
- package/src/state/Persistence.stories.tsx +0 -75
package/src/theme/base.less
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// The Oswald and Inter faces come from @weasel-js/theme/faces.css, imported at
|
|
2
2
|
// the top of styles.less.
|
|
3
3
|
|
|
4
|
+
// weasel-ui's native range skin, read for `:extend` below and emitted only
|
|
5
|
+
// through it.
|
|
6
|
+
@import (reference, less) '../../../ui/src/components/range.module.css';
|
|
7
|
+
|
|
4
8
|
// Resets and global element defaults.
|
|
5
9
|
.lk-root {
|
|
6
10
|
font-family: var(--wzl-font-ui);
|
|
@@ -21,7 +25,10 @@
|
|
|
21
25
|
// Deliberate overrides of a weasel-ui component go the other way — see the
|
|
22
26
|
// `.lk-root` prefix convention below.
|
|
23
27
|
:where(.lk-root) {
|
|
24
|
-
|
|
28
|
+
// Only a button with no class or a labkit one. Specificity cannot keep this
|
|
29
|
+
// off a weasel-ui button: whatever its module leaves unset — a height, a
|
|
30
|
+
// backdrop blur — the default fills in.
|
|
31
|
+
:where(button:not([class]), button[class^='lk-'], button[class*=' lk-']) {
|
|
25
32
|
font: inherit;
|
|
26
33
|
color: inherit;
|
|
27
34
|
background: var(--wzl-surface-raised);
|
|
@@ -33,63 +40,32 @@
|
|
|
33
40
|
backdrop-filter: blur(var(--wzl-glass-blur));
|
|
34
41
|
-webkit-backdrop-filter: blur(var(--wzl-glass-blur));
|
|
35
42
|
|
|
36
|
-
&:hover {
|
|
43
|
+
&:where(:hover) {
|
|
37
44
|
border-color: var(--wzl-accent);
|
|
38
45
|
color: var(--wzl-accent-fg);
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
&:focus-visible {
|
|
48
|
+
&:where(:focus-visible) {
|
|
42
49
|
outline: 2px solid var(--wzl-focus-ring);
|
|
43
50
|
outline-offset: 1px;
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
&:disabled {
|
|
53
|
+
&:where(:disabled) {
|
|
47
54
|
color: var(--wzl-fg-subtle);
|
|
48
55
|
cursor: not-allowed;
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
58
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
:where(input[type="range"]) {
|
|
56
|
-
appearance: none;
|
|
57
|
-
-webkit-appearance: none;
|
|
58
|
-
height: 12px;
|
|
59
|
-
background: transparent;
|
|
60
|
-
cursor: pointer;
|
|
61
|
-
|
|
62
|
-
&::-webkit-slider-runnable-track {
|
|
63
|
-
height: var(--wzl-slider-track-h);
|
|
64
|
-
border-radius: var(--wzl-radius-sm);
|
|
65
|
-
background: color-mix(in srgb, var(--wzl-accent) var(--wzl-slider-track-mix), transparent);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
&::-moz-range-track {
|
|
69
|
-
height: var(--wzl-slider-track-h);
|
|
70
|
-
border-radius: var(--wzl-radius-sm);
|
|
71
|
-
background: color-mix(in srgb, var(--wzl-accent) var(--wzl-slider-track-mix), transparent);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
&::-webkit-slider-thumb {
|
|
75
|
-
appearance: none;
|
|
76
|
-
-webkit-appearance: none;
|
|
77
|
-
width: var(--wzl-slider-thumb-size);
|
|
78
|
-
height: var(--wzl-slider-thumb-size);
|
|
79
|
-
border: none;
|
|
80
|
-
border-radius: 50%;
|
|
81
|
-
background: color-mix(in srgb, var(--wzl-accent) var(--wzl-slider-thumb-mix), transparent);
|
|
82
|
-
margin-top: calc((var(--wzl-slider-track-h) - var(--wzl-slider-thumb-size)) / 2);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
&::-moz-range-thumb {
|
|
86
|
-
width: var(--wzl-slider-thumb-size);
|
|
87
|
-
height: var(--wzl-slider-thumb-size);
|
|
88
|
-
border: none;
|
|
89
|
-
border-radius: 50%;
|
|
90
|
-
background: color-mix(in srgb, var(--wzl-accent) var(--wzl-slider-thumb-mix), transparent);
|
|
91
|
-
}
|
|
59
|
+
// The browser sets these in its own `monospace`, which no font token reaches.
|
|
60
|
+
:where(code, kbd, samp, pre) {
|
|
61
|
+
font-family: var(--wzl-font-mono);
|
|
92
62
|
}
|
|
63
|
+
|
|
64
|
+
// A consumer's bare range wears weasel-ui's range skin, extended from its one
|
|
65
|
+
// definition rather than copied. The skin keeps its pseudo-classes inside
|
|
66
|
+
// :where(), so nothing this emits outranks a single class and a weasel-ui
|
|
67
|
+
// component's own module class still wins.
|
|
68
|
+
:where(input[type="range"]):extend(.range all) {}
|
|
93
69
|
}
|
|
94
70
|
|
|
95
71
|
// The `.lk-root` prefix convention: a labkit class handed to a weasel-ui
|
|
@@ -151,9 +127,7 @@
|
|
|
151
127
|
}
|
|
152
128
|
|
|
153
129
|
// Headline / display text uses Oswald light at tighter line-height.
|
|
154
|
-
.lk-lab h1,
|
|
155
|
-
.lk-lab h2,
|
|
156
|
-
.lk-lab h3 {
|
|
130
|
+
:where(.lk-lab) :where(h1, h2, h3) {
|
|
157
131
|
font-family: var(--wzl-font-display);
|
|
158
132
|
font-weight: var(--wzl-font-weight-light);
|
|
159
133
|
letter-spacing: 0.01em;
|
|
@@ -18,7 +18,7 @@ describe('interstellarTheme', () => {
|
|
|
18
18
|
|
|
19
19
|
// Values carried over verbatim from the retired Less.
|
|
20
20
|
expect(dark['--wzl-surface']).toBe('#0a0a14');
|
|
21
|
-
expect(dark['--wzl-accent']).toBe('#
|
|
21
|
+
expect(dark['--wzl-accent']).toBe('#4f46e5');
|
|
22
22
|
// Light mode is weasel's own: interstellar restyles the dark only.
|
|
23
23
|
const weasel = resolveTheme(weaselTheme, { mode: 'light' });
|
|
24
24
|
expect(light['--wzl-surface']).toBe(weasel['--wzl-surface']);
|
|
@@ -81,21 +81,28 @@
|
|
|
81
81
|
"accent": {
|
|
82
82
|
"by": "mode",
|
|
83
83
|
"dark": {
|
|
84
|
-
"value": "#
|
|
84
|
+
"value": "#4f46e5",
|
|
85
85
|
"type": "color"
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
88
|
"accent-hover": {
|
|
89
89
|
"by": "mode",
|
|
90
90
|
"dark": {
|
|
91
|
-
"value": "#
|
|
91
|
+
"value": "#6d5dfc",
|
|
92
|
+
"type": "color"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"accent-strong": {
|
|
96
|
+
"by": "mode",
|
|
97
|
+
"dark": {
|
|
98
|
+
"value": "#7474fe",
|
|
92
99
|
"type": "color"
|
|
93
100
|
}
|
|
94
101
|
},
|
|
95
102
|
"focus-ring": {
|
|
96
103
|
"by": "mode",
|
|
97
104
|
"dark": {
|
|
98
|
-
"value": "rgba(
|
|
105
|
+
"value": "rgba(116, 116, 254, 0.5)",
|
|
99
106
|
"type": "color"
|
|
100
107
|
}
|
|
101
108
|
},
|
package/src/trial/Trial.less
CHANGED
|
@@ -109,19 +109,6 @@
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
.lk-toolbar__zoom-label {
|
|
113
|
-
font-size: var(--wzl-font-size-sm);
|
|
114
|
-
color: var(--wzl-fg-muted);
|
|
115
|
-
padding: 0 var(--wzl-space-sm);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.lk-sidebar__placeholder {
|
|
119
|
-
padding: var(--wzl-space-sm);
|
|
120
|
-
color: var(--wzl-fg-muted);
|
|
121
|
-
font-size: var(--wzl-font-size-sm);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
112
|
.lk-trial__titlebar {
|
|
126
113
|
display: flex;
|
|
127
114
|
align-items: center;
|
package/src/trial/Trial.tsx
CHANGED
|
@@ -6,9 +6,10 @@ import { AnnotationTargets } from '../annotations/AnnotationTargets';
|
|
|
6
6
|
import { AnnotationPreloadContext } from '../annotations/preload';
|
|
7
7
|
import { annotationsFromJSON } from '../annotations/store';
|
|
8
8
|
import type { AnnotationStorage, AnnotationTargetInfo } from '../annotations/types';
|
|
9
|
-
import {
|
|
9
|
+
import type { CameraView } from '../canvas/CameraInput';
|
|
10
10
|
import { CameraWheelContext, type CameraWheelSlot } from '../canvas/CameraWheelContext';
|
|
11
11
|
import { CanvasStack } from '../canvas/CanvasStack';
|
|
12
|
+
import { CameraPublishContext, CameraRegistryContext } from '../canvas/cameraRegistry';
|
|
12
13
|
import { fitStage, Stage } from '../canvas/Stage';
|
|
13
14
|
import type { CanvasLayerDescriptor } from '../canvas/useLayerScheduler';
|
|
14
15
|
import { applyCamera, type ViewportSize } from '../canvas/worldSpec';
|
|
@@ -136,6 +137,12 @@ function TrialRuntime({
|
|
|
136
137
|
suppress,
|
|
137
138
|
}: TrialRuntimeProps) {
|
|
138
139
|
const wheelSlot = useRef<CameraWheelSlot['current']>(null);
|
|
140
|
+
const cameras = useContext(CameraRegistryContext);
|
|
141
|
+
const trialId = record.id;
|
|
142
|
+
const publishCamera = useMemo(
|
|
143
|
+
() => (cameras ? (camera: CameraView) => cameras.register(trialId, camera) : null),
|
|
144
|
+
[cameras, trialId],
|
|
145
|
+
);
|
|
139
146
|
const [pointer] = useState(createPointerStore);
|
|
140
147
|
const canvasContainerRef = useRef<HTMLDivElement | null>(null);
|
|
141
148
|
const loupeHostRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -593,14 +600,13 @@ function TrialRuntime({
|
|
|
593
600
|
/>
|
|
594
601
|
) : null;
|
|
595
602
|
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
// its own.
|
|
603
|
+
// The trial's root registries, isolated from the trial beside it. Each
|
|
604
|
+
// camera inside mounts an input scope under them; chrome here reaches the
|
|
605
|
+
// one last used. The pointer store is the trial's, shared by all of them.
|
|
600
606
|
const scopedBody = (
|
|
601
607
|
<WeaselProvider isolate>
|
|
602
608
|
<PointerContextProvider store={pointer}>
|
|
603
|
-
<
|
|
609
|
+
<CameraPublishContext.Provider value={publishCamera}>{body}</CameraPublishContext.Provider>
|
|
604
610
|
</PointerContextProvider>
|
|
605
611
|
</WeaselProvider>
|
|
606
612
|
);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type KeyboardEvent,
|
|
3
|
+
type ReactNode,
|
|
4
|
+
useContext,
|
|
5
|
+
useMemo,
|
|
6
|
+
useSyncExternalStore,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import { useStore } from 'zustand/react';
|
|
9
|
+
import { CameraRegistryContext } from '../canvas/cameraRegistry';
|
|
10
|
+
import { zoomCameraTo } from '../canvas/cameraZoom';
|
|
3
11
|
import { builtinContributions } from '../chrome/builtins';
|
|
4
12
|
import { mergeContributions, suppressContributions } from '../chrome/merge';
|
|
5
13
|
import { PaletteRegion } from '../chrome/regions/PaletteRegion';
|
|
@@ -68,6 +76,7 @@ const NO_OP = (): void => {};
|
|
|
68
76
|
/** One frozen empty map, so a trial that has folded nothing keeps a stable
|
|
69
77
|
* context identity across renders. */
|
|
70
78
|
const NO_SECTIONS: Readonly<Record<string, boolean>> = Object.freeze({});
|
|
79
|
+
const noSubscribe = (): (() => void) => NO_OP;
|
|
71
80
|
|
|
72
81
|
/** The frame around a running instrument. Builds one chrome context, assembles
|
|
73
82
|
* the contributions the instrument, the runtime and the lab declare, and hands
|
|
@@ -123,10 +132,18 @@ export function TrialChrome({
|
|
|
123
132
|
const title = record.title ?? instrument.title ?? instrument.name;
|
|
124
133
|
const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
|
|
125
134
|
|
|
135
|
+
// The trial's own camera, where it has one: zoom goes through it, about the
|
|
136
|
+
// middle of the view and inside the instrument's range, as the lab's does.
|
|
137
|
+
const cameras = useContext(CameraRegistryContext);
|
|
138
|
+
const camera = useSyncExternalStore(
|
|
139
|
+
cameras?.subscribe ?? noSubscribe,
|
|
140
|
+
() => cameras?.get(trialId) ?? null,
|
|
141
|
+
);
|
|
142
|
+
|
|
126
143
|
const ctx = useMemo<TrialChromeContext>(() => {
|
|
127
144
|
const setZoom = (z: number): void => {
|
|
128
|
-
if (
|
|
129
|
-
updateTrialView(trialId, withZoom(view2d, z));
|
|
145
|
+
if (camera) zoomCameraTo(camera, z);
|
|
146
|
+
else if (view2d) updateTrialView(trialId, withZoom(view2d, z));
|
|
130
147
|
};
|
|
131
148
|
return {
|
|
132
149
|
trialId,
|
|
@@ -203,6 +220,7 @@ export function TrialChrome({
|
|
|
203
220
|
setTrialTitle,
|
|
204
221
|
setTrialSectionCollapsed,
|
|
205
222
|
collapsedSections,
|
|
223
|
+
camera,
|
|
206
224
|
]);
|
|
207
225
|
|
|
208
226
|
const contributions = useMemo(
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Stance } from '@weasel-js/theme';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { ToolPrefLeaf } from '@weasel-js/core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* What a surface holds, and which of its peers it is. Every surface that takes
|
|
7
|
-
* these takes both, and the theme decides how each looks.
|
|
8
|
-
*/
|
|
9
|
-
interface StanceProps {
|
|
10
|
-
/** The class of content the surface holds. Omitted, it draws as it always has. */
|
|
11
|
-
stance?: Stance;
|
|
12
|
-
/**
|
|
13
|
-
* Which of its peers this is: an index into the theme's tone list, wrapping,
|
|
14
|
-
* or a color given directly. Independent of `stance`, and allowed without one.
|
|
15
|
-
*/
|
|
16
|
-
tone?: number | string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** What a {@link PrefRenderer} is given for the leaf it is rendering. */
|
|
20
|
-
interface PrefRenderContext {
|
|
21
|
-
/** Dotted path of the leaf within the schema root. */
|
|
22
|
-
path: string;
|
|
23
|
-
/** The schema node. App renderers narrow this to their own kind shape. */
|
|
24
|
-
pref: ToolPrefLeaf;
|
|
25
|
-
/** Current value — `values` at `path`, falling back to `pref.default`. */
|
|
26
|
-
value: unknown;
|
|
27
|
-
setValue: (value: unknown) => void;
|
|
28
|
-
/** Whether this leaf is currently auto — not pinned, computed by the owner. */
|
|
29
|
-
auto: boolean;
|
|
30
|
-
/** Toggle this leaf's auto state. */
|
|
31
|
-
setAuto: (next: boolean) => void;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Renders the control cell for one preference leaf. Returning `null`
|
|
35
|
-
* collapses the row.
|
|
36
|
-
*/
|
|
37
|
-
type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;
|
|
38
|
-
|
|
39
|
-
export type { PrefRenderer as P, StanceProps as S, PrefRenderContext as a };
|