@weasel-js/labkit 1.7.0 → 1.7.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.
- package/README.md +3 -3
- package/dist/_dts/{CanvasStackContext-D2jnIwfk.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
- package/dist/_dts/{Stage-CCWfQQWM.d.ts → Stage-D6t7o0pF.d.ts} +3 -2
- package/dist/_dts/{index-CsYqUHD3.d.ts → index-BTmaRy6a.d.ts} +10 -6
- package/dist/_dts/{types-CSm9jgol.d.ts → index-DCMA4Fy1.d.ts} +59 -113
- package/dist/_dts/{types-CRPSGFAp.d.ts → types-BUBSIZuV.d.ts} +8 -7
- package/dist/_dts/{useTrialState-CTZPgeZ7.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
- package/dist/canvas/index.d.ts +8 -6
- package/dist/canvas/index.js +6 -6
- package/dist/chrome/index.d.ts +7 -5
- package/dist/chrome/index.js +10 -9
- package/dist/chunk-2ES4W47N.js +8 -0
- package/dist/chunk-2ES4W47N.js.map +1 -0
- package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
- package/dist/chunk-2N7UBSS2.js.map +1 -0
- package/dist/{chunk-275JRRVD.js → chunk-E23Q6A3Y.js} +232 -37
- package/dist/chunk-E23Q6A3Y.js.map +1 -0
- package/dist/{chunk-GOZLNM4L.js → chunk-E6NARGU7.js} +5 -5
- package/dist/{chunk-GOZLNM4L.js.map → chunk-E6NARGU7.js.map} +1 -1
- package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
- package/dist/chunk-EESJUSYR.js.map +1 -0
- package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
- package/dist/chunk-EFXRM6XQ.js.map +1 -0
- package/dist/chunk-F4ACIK7Z.js +210 -0
- package/dist/chunk-F4ACIK7Z.js.map +1 -0
- package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
- package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
- package/dist/{chunk-YT75VYRD.js → chunk-IBVRMHW5.js} +5 -5
- package/dist/{chunk-YT75VYRD.js.map → chunk-IBVRMHW5.js.map} +1 -1
- package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
- package/dist/chunk-PMLZP7RT.js.map +1 -0
- package/dist/{chunk-Y23G2VZL.js → chunk-READTDQX.js} +2 -2
- package/dist/chunk-READTDQX.js.map +1 -0
- package/dist/{chunk-I5DUQ5HM.js → chunk-RODIY7HI.js} +75 -72
- package/dist/chunk-RODIY7HI.js.map +1 -0
- package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
- package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
- package/dist/{chunk-ZIFPHIWZ.js → chunk-T6DLGEJB.js} +12 -14
- package/dist/chunk-T6DLGEJB.js.map +1 -0
- package/dist/chunk-U6UQVGFP.js +15583 -0
- package/dist/chunk-U6UQVGFP.js.map +1 -0
- package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
- package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
- package/dist/{chunk-UNAZSLWE.js → chunk-VYVGVBGY.js} +17 -20
- package/dist/chunk-VYVGVBGY.js.map +1 -0
- package/dist/chunk-WFALF2X2.js +302 -0
- package/dist/chunk-WFALF2X2.js.map +1 -0
- package/dist/{chunk-KMJ7RWD3.js → chunk-WLMDTI2Q.js} +3 -3
- package/dist/{chunk-KMJ7RWD3.js.map → chunk-WLMDTI2Q.js.map} +1 -1
- package/dist/{chunk-T5IBSPAM.js → chunk-WWJDPNZZ.js} +43 -33
- package/dist/chunk-WWJDPNZZ.js.map +1 -0
- package/dist/{chunk-J7OWWTCW.js → chunk-XE5HJOPL.js} +5 -6
- package/dist/chunk-XE5HJOPL.js.map +1 -0
- package/dist/{chunk-7BO7HNGF.js → chunk-XRX5S5NT.js} +8 -61
- package/dist/chunk-XRX5S5NT.js.map +1 -0
- package/dist/chunk-XVUKDSYV.js +38 -0
- package/dist/chunk-XVUKDSYV.js.map +1 -0
- package/dist/{chunk-FMK7UQ6V.js → chunk-XZDCEMEL.js} +64 -47
- package/dist/chunk-XZDCEMEL.js.map +1 -0
- package/dist/{chunk-FZ7YFQN7.js → chunk-YCFKW5RX.js} +3 -3
- package/dist/chunk-YCFKW5RX.js.map +1 -0
- package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
- package/dist/chunk-ZQIHJXP4.js.map +1 -0
- package/dist/config/index.d.ts +18 -10
- package/dist/config/index.js +4 -4
- package/dist/controls/index.d.ts +58 -9
- package/dist/controls/index.js +7 -5
- package/dist/dragdrop/index.d.ts +23 -3
- package/dist/dragdrop/index.js +4 -3
- package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
- package/dist/index.d.ts +61 -715
- package/dist/index.js +456 -432
- package/dist/index.js.map +1 -1
- package/dist/job/index.d.ts +8 -0
- package/dist/job/index.js +1 -1
- package/dist/layers/index.d.ts +6 -5
- package/dist/layers/index.js +3 -2
- package/dist/loupe/index.d.ts +100 -30
- package/dist/loupe/index.js +585 -6
- package/dist/loupe/index.js.map +1 -1
- package/dist/overview/index.d.ts +4 -2
- package/dist/overview/index.js +15 -14
- package/dist/overview/index.js.map +1 -1
- package/dist/passthrough/weasel-canvas.d.ts +2 -0
- package/dist/passthrough/weasel-ui.d.ts +2 -2871
- package/dist/passthrough/weasel-ui.js +3 -2
- package/dist/primitives/index.d.ts +213 -3
- package/dist/primitives/index.js +8 -7
- package/dist/state/index.d.ts +7 -5
- package/dist/state/index.js +6 -6
- package/dist/styles.css +284 -51
- package/dist/surface/index.d.ts +10 -2
- package/dist/surface/index.js +1 -1
- package/dist/undo/index.d.ts +5 -3
- package/package.json +11 -11
- package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
- package/src/annotations/AnnotationOverlay.tsx +50 -31
- package/src/annotations/Annotations.overlay.test.tsx +31 -0
- package/src/annotations/capture.browser.test.ts +47 -0
- package/src/annotations/capture.ts +14 -7
- package/src/annotations/drawOne.ts +2 -2
- package/src/annotations/frac.test.ts +44 -1
- package/src/annotations/frac.ts +46 -18
- package/src/annotations/index.ts +1 -0
- package/src/annotations/paint.test.ts +74 -33
- package/src/annotations/paint.ts +70 -32
- package/src/annotations/store.test.ts +212 -2
- package/src/annotations/store.ts +130 -27
- package/src/annotations/svgNodes.test.ts +22 -10
- package/src/annotations/svgNodes.ts +3 -3
- package/src/annotations/types.ts +29 -10
- package/src/canvas/CameraInput.test.tsx +30 -0
- package/src/canvas/CameraInput.tsx +16 -15
- package/src/canvas/CanvasStack.tsx +5 -5
- package/src/canvas/CanvasStackContext.ts +4 -1
- package/src/canvas/Stage.test.tsx +34 -25
- package/src/canvas/Stage.tsx +3 -3
- package/src/canvas/cameraRegistry.ts +1 -0
- package/src/canvas/worldSpec.ts +3 -1
- package/src/chrome/builtins.test.ts +7 -6
- package/src/chrome/builtins.tsx +5 -1
- package/src/chrome/index.ts +1 -1
- package/src/chrome/labRegions.test.tsx +37 -26
- package/src/chrome/merge.test.ts +5 -0
- package/src/chrome/merge.ts +4 -2
- package/src/chrome/regions/PaletteRegion.test.tsx +4 -5
- package/src/chrome/regions/PaletteRegion.tsx +3 -4
- package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
- package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
- package/src/chrome/regions/ViewportRegion.less +6 -0
- package/src/chrome/regions/ViewportRegion.tsx +10 -4
- package/src/chrome/types.ts +4 -2
- package/src/config/auto.ts +1 -0
- package/src/config/builder.ts +6 -0
- package/src/config/types.ts +2 -1
- package/src/controls/ControlMatrix.less +245 -0
- package/src/controls/ControlMatrix.stories.less +13 -0
- package/src/controls/ControlMatrix.stories.tsx +135 -0
- package/src/controls/ControlMatrix.test.tsx +206 -0
- package/src/controls/ControlMatrix.tsx +446 -0
- package/src/controls/ControlPanel.test.tsx +37 -3
- package/src/controls/ControlPanel.tsx +16 -5
- package/src/controls/index.ts +6 -0
- package/src/dragdrop/DragDropRuntime.tsx +22 -13
- package/src/dragdrop/DragGhost.tsx +3 -0
- package/src/dragdrop/Palette.tsx +2 -0
- package/src/dragdrop/dragDrop.test.tsx +34 -33
- package/src/index.test.ts +5 -0
- package/src/index.ts +7 -1
- package/src/instrument/types.ts +0 -6
- package/src/job/useJob.ts +14 -9
- package/src/lab/Lab.chrome.test.tsx +15 -10
- package/src/lab/Lab.nebula.test.tsx +5 -5
- package/src/lab/Lab.surface.test.tsx +30 -21
- package/src/lab/Lab.test.tsx +75 -74
- package/src/lab/Lab.tsx +5 -1
- package/src/lab/Lab.undock.test.tsx +15 -10
- package/src/lab/LabHeader.test.tsx +15 -14
- package/src/lab/LabPalette.test.tsx +12 -7
- package/src/lab/LabShell.less +1 -1
- package/src/lab/LabSwitcher.browser.test.tsx +27 -0
- package/src/lab/LabSwitcher.less +2 -0
- package/src/lab/LabZoom.test.tsx +55 -44
- package/src/lab/LabZoom.tsx +4 -4
- package/src/lab/Workspace.surface.test.tsx +16 -13
- package/src/lab/Workspace.test.tsx +32 -27
- package/src/lab/Workspace.tsx +48 -52
- package/src/loupe/AGENTS.md +28 -15
- package/src/loupe/CanvasLoupe.tsx +2 -3
- package/src/loupe/DomLoupe.tsx +1 -7
- package/src/loupe/Loupe.less +16 -0
- package/src/loupe/TrialLoupe.tsx +120 -57
- package/src/loupe/index.ts +1 -6
- package/src/loupe/types.test.ts +3 -3
- package/src/loupe/types.ts +24 -27
- package/src/loupe/useLoupe.test.tsx +29 -4
- package/src/loupe/useLoupe.ts +20 -17
- package/src/overview/OverviewMarks.test.tsx +9 -8
- package/src/overview/OverviewMarks.tsx +12 -4
- package/src/overview/TrialOverview.test.tsx +18 -17
- package/src/overview/TrialOverview.tsx +3 -3
- package/src/passthrough/weasel-ui.test.ts +1 -1
- package/src/passthrough/weasel-ui.ts +1 -1
- package/src/primitives/FloatingPanel.tsx +7 -3
- package/src/primitives/FpsMeter.less +1 -2
- package/src/primitives/JobProgress.less +1 -1
- package/src/primitives/Readout.test.tsx +2 -2
- package/src/primitives/ScaleIndicator.less +1 -1
- package/src/primitives/Split.tsx +69 -41
- package/src/primitives/StatusBar.less +1 -1
- package/src/primitives/Toolbar.tsx +3 -3
- package/src/primitives/ZoomControl.less +1 -2
- package/src/specimen/Specimen.less +1 -0
- package/src/specimen/Specimen.tsx +0 -1
- package/src/state/undock.ts +3 -0
- package/src/state/useOpenOnce.ts +20 -16
- package/src/state/view.ts +1 -0
- package/src/styles.less +3 -0
- package/src/surface/index.ts +1 -1
- package/src/surface/useTiledSurface.test.tsx +14 -0
- package/src/surface/useTiledSurface.ts +11 -3
- package/src/trial/Trial.annotations.persist.test.tsx +20 -9
- package/src/trial/Trial.annotations.test.tsx +105 -27
- package/src/trial/Trial.canvas.test.tsx +21 -17
- package/src/trial/Trial.config.test.tsx +34 -27
- package/src/trial/Trial.less +0 -16
- package/src/trial/Trial.loupe.test.tsx +51 -25
- package/src/trial/Trial.targets.test.tsx +9 -8
- package/src/trial/Trial.test.tsx +51 -46
- package/src/trial/Trial.trialId.test.tsx +7 -6
- package/src/trial/Trial.tsx +74 -62
- package/src/trial/TrialChrome.tsx +6 -3
- package/src/trial/index.ts +2 -0
- package/src/trial/loupeSwitch.ts +15 -0
- package/dist/_dts/LayerList.d-DiuEArKq.d.ts +0 -83
- package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +0 -79
- package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +0 -141
- package/dist/_dts/Select.d-Bensr_MT.d.ts +0 -579
- package/dist/_dts/index-B2Yj5aA0.d.ts +0 -274
- package/dist/chunk-275JRRVD.js.map +0 -1
- package/dist/chunk-4LJSC7MB.js +0 -143
- package/dist/chunk-4LJSC7MB.js.map +0 -1
- package/dist/chunk-7BO7HNGF.js.map +0 -1
- package/dist/chunk-CQLQPQ4P.js.map +0 -1
- package/dist/chunk-FMK7UQ6V.js.map +0 -1
- package/dist/chunk-FZ7YFQN7.js.map +0 -1
- package/dist/chunk-HXXTULDN.js.map +0 -1
- package/dist/chunk-I5DUQ5HM.js.map +0 -1
- package/dist/chunk-IJJUK4FU.js.map +0 -1
- package/dist/chunk-J7OWWTCW.js.map +0 -1
- package/dist/chunk-M7HP3FTK.js +0 -549
- package/dist/chunk-M7HP3FTK.js.map +0 -1
- package/dist/chunk-MIM5R4ZT.js +0 -14972
- package/dist/chunk-MIM5R4ZT.js.map +0 -1
- package/dist/chunk-RWNDDKOH.js.map +0 -1
- package/dist/chunk-T5IBSPAM.js.map +0 -1
- package/dist/chunk-UNAZSLWE.js.map +0 -1
- package/dist/chunk-WPLAANH4.js.map +0 -1
- package/dist/chunk-Y23G2VZL.js.map +0 -1
- package/dist/chunk-ZIFPHIWZ.js.map +0 -1
- package/src/primitives/useRovingTabIndex.test.ts +0 -48
- package/src/primitives/useRovingTabIndex.ts +0 -88
package/src/lab/Lab.test.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { act, fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
|
2
|
+
import { renderSettled } from '@weasel-js/react/testing/renderSettled';
|
|
2
3
|
import { type ReactNode, useEffect } from 'react';
|
|
3
4
|
import { describe, expect, it } from 'vitest';
|
|
4
5
|
import type { Instrument } from '../instrument/types';
|
|
@@ -32,9 +33,9 @@ function CaptureLab({ children }: { children?: ReactNode }) {
|
|
|
32
33
|
);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
function mountLab(props: Partial<Record<keyof LabProps, unknown>> = {}) {
|
|
36
|
+
async function mountLab(props: Partial<Record<keyof LabProps, unknown>> = {}) {
|
|
36
37
|
labRef = null;
|
|
37
|
-
return
|
|
38
|
+
return renderSettled(
|
|
38
39
|
<Lab {...({ instruments: [stub, stubB], defaultInstrument: 'Stub', ...props } as LabProps)}>
|
|
39
40
|
<CaptureLab />
|
|
40
41
|
</Lab>,
|
|
@@ -42,86 +43,86 @@ function mountLab(props: Partial<Record<keyof LabProps, unknown>> = {}) {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
describe('<Lab>', () => {
|
|
45
|
-
it('renders one trial by default', () => {
|
|
46
|
-
mountLab();
|
|
46
|
+
it('renders one trial by default', async () => {
|
|
47
|
+
await mountLab();
|
|
47
48
|
expect(screen.getAllByRole('region', { name: /trial/i })).toHaveLength(1);
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
it('addTrial adds a second trial', () => {
|
|
51
|
-
mountLab();
|
|
52
|
-
act(() => labRef?.addTrial('Stub'));
|
|
51
|
+
it('addTrial adds a second trial', async () => {
|
|
52
|
+
await mountLab();
|
|
53
|
+
await act(async () => labRef?.addTrial('Stub'));
|
|
53
54
|
expect(screen.getAllByRole('region', { name: /trial/i })).toHaveLength(2);
|
|
54
55
|
});
|
|
55
56
|
|
|
56
|
-
it('addTrial opens each trial on the config it was given', () => {
|
|
57
|
-
mountLab();
|
|
58
|
-
act(() => labRef?.addTrial('Stub', { config: { count: 7 } }));
|
|
57
|
+
it('addTrial opens each trial on the config it was given', async () => {
|
|
58
|
+
await mountLab();
|
|
59
|
+
await act(async () => labRef?.addTrial('Stub', { config: { count: 7 } }));
|
|
59
60
|
expect(labRef?.trials.map((t) => (t.config as { count: number }).count)).toEqual([0, 7]);
|
|
60
61
|
expect(labRef?.trials.map((t) => (t.state as { value: number }).value)).toEqual([0, 7]);
|
|
61
62
|
});
|
|
62
63
|
|
|
63
|
-
it('closeTrial removes one when more than one exists', () => {
|
|
64
|
-
mountLab();
|
|
65
|
-
act(() => labRef?.addTrial('Stub'));
|
|
64
|
+
it('closeTrial removes one when more than one exists', async () => {
|
|
65
|
+
await mountLab();
|
|
66
|
+
await act(async () => labRef?.addTrial('Stub'));
|
|
66
67
|
const first = labRef?.trials[0];
|
|
67
|
-
act(() => labRef?.closeTrial(first?.id ?? ''));
|
|
68
|
+
await act(async () => labRef?.closeTrial(first?.id ?? ''));
|
|
68
69
|
expect(screen.getAllByRole('region', { name: /trial/i })).toHaveLength(1);
|
|
69
70
|
});
|
|
70
71
|
|
|
71
|
-
it('closeTrial is a no-op on the last trial', () => {
|
|
72
|
-
mountLab();
|
|
72
|
+
it('closeTrial is a no-op on the last trial', async () => {
|
|
73
|
+
await mountLab();
|
|
73
74
|
const only = labRef?.trials[0];
|
|
74
|
-
act(() => labRef?.closeTrial(only?.id ?? ''));
|
|
75
|
+
await act(async () => labRef?.closeTrial(only?.id ?? ''));
|
|
75
76
|
expect(screen.getAllByRole('region', { name: /trial/i })).toHaveLength(1);
|
|
76
77
|
});
|
|
77
78
|
|
|
78
|
-
it('cloneTrial inserts immediately after source', () => {
|
|
79
|
-
mountLab();
|
|
80
|
-
act(() => labRef?.addTrial('StubB'));
|
|
79
|
+
it('cloneTrial inserts immediately after source', async () => {
|
|
80
|
+
await mountLab();
|
|
81
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
81
82
|
const ws0 = labRef?.trials[0];
|
|
82
83
|
const ws1 = labRef?.trials[1];
|
|
83
|
-
act(() => labRef?.cloneTrial(ws0?.id ?? ''));
|
|
84
|
+
await act(async () => labRef?.cloneTrial(ws0?.id ?? ''));
|
|
84
85
|
const ids = labRef?.trials.map((w) => w.id) ?? [];
|
|
85
86
|
expect(ids).toHaveLength(3);
|
|
86
87
|
expect(ids[0]).toBe(ws0?.id);
|
|
87
88
|
expect(ids[2]).toBe(ws1?.id);
|
|
88
89
|
});
|
|
89
90
|
|
|
90
|
-
it('resetTrial restores defaults', () => {
|
|
91
|
-
mountLab();
|
|
91
|
+
it('resetTrial restores defaults', async () => {
|
|
92
|
+
await mountLab();
|
|
92
93
|
const ws = labRef?.trials[0];
|
|
93
94
|
if (!ws) throw new Error('no trial');
|
|
94
|
-
act(() => labRef?.resetTrial(ws.id));
|
|
95
|
+
await act(async () => labRef?.resetTrial(ws.id));
|
|
95
96
|
const reset = labRef?.trials[0];
|
|
96
97
|
expect(reset?.config).toEqual({ count: 0 });
|
|
97
98
|
expect(reset?.state).toEqual({ value: 0 });
|
|
98
99
|
});
|
|
99
100
|
|
|
100
|
-
it('mode="light" stamps light on the lab root', () => {
|
|
101
|
-
const { container } = mountLab({ mode: 'light' });
|
|
101
|
+
it('mode="light" stamps light on the lab root', async () => {
|
|
102
|
+
const { container } = await mountLab({ mode: 'light' });
|
|
102
103
|
expect(container.querySelector('.lk-lab')?.getAttribute('data-wzl-mode')).toBe('light');
|
|
103
104
|
});
|
|
104
105
|
|
|
105
|
-
it('mode="dark" stamps dark on the lab root', () => {
|
|
106
|
-
const { container } = mountLab({ mode: 'dark' });
|
|
106
|
+
it('mode="dark" stamps dark on the lab root', async () => {
|
|
107
|
+
const { container } = await mountLab({ mode: 'dark' });
|
|
107
108
|
expect(container.querySelector('.lk-lab')?.getAttribute('data-wzl-mode')).toBe('dark');
|
|
108
109
|
});
|
|
109
110
|
|
|
110
|
-
it('mode="auto" resolves to a concrete mode', () => {
|
|
111
|
-
const { container } = mountLab({ mode: 'auto' });
|
|
111
|
+
it('mode="auto" resolves to a concrete mode', async () => {
|
|
112
|
+
const { container } = await mountLab({ mode: 'auto' });
|
|
112
113
|
expect(container.querySelector('.lk-lab')?.getAttribute('data-wzl-mode')).toMatch(
|
|
113
114
|
/^(light|dark)$/,
|
|
114
115
|
);
|
|
115
116
|
});
|
|
116
117
|
|
|
117
|
-
it('applies the interstellar theme in every mode', () => {
|
|
118
|
-
const { container } = mountLab({ mode: 'light' });
|
|
118
|
+
it('applies the interstellar theme in every mode', async () => {
|
|
119
|
+
const { container } = await mountLab({ mode: 'light' });
|
|
119
120
|
expect(container.querySelector('.lk-lab')?.getAttribute('data-wzl-theme')).toBe('interstellar');
|
|
120
121
|
});
|
|
121
122
|
|
|
122
|
-
it('setMode updates the stamped mode at runtime', () => {
|
|
123
|
-
const { container } = mountLab({ mode: 'auto' });
|
|
124
|
-
act(() => labRef?.setMode('light'));
|
|
123
|
+
it('setMode updates the stamped mode at runtime', async () => {
|
|
124
|
+
const { container } = await mountLab({ mode: 'auto' });
|
|
125
|
+
await act(async () => labRef?.setMode('light'));
|
|
125
126
|
expect(container.querySelector('.lk-lab')?.getAttribute('data-wzl-mode')).toBe('light');
|
|
126
127
|
});
|
|
127
128
|
|
|
@@ -152,13 +153,13 @@ describe('<Lab>', () => {
|
|
|
152
153
|
};
|
|
153
154
|
const storage = () => createMemoryAdapter(backing);
|
|
154
155
|
|
|
155
|
-
const first =
|
|
156
|
+
const first = await renderSettled(
|
|
156
157
|
<Lab instruments={[mapped]} defaultInstrument="Mapped" storage={storage()} storageKey="s" />,
|
|
157
158
|
);
|
|
158
159
|
await waitFor(() => expect(JSON.stringify([...backing.values()])).toContain('"seen":["a"]'));
|
|
159
160
|
first.unmount();
|
|
160
161
|
|
|
161
|
-
mountLab({
|
|
162
|
+
await mountLab({
|
|
162
163
|
instruments: [mapped],
|
|
163
164
|
defaultInstrument: 'Mapped',
|
|
164
165
|
storage: storage(),
|
|
@@ -172,7 +173,7 @@ describe('<Lab>', () => {
|
|
|
172
173
|
});
|
|
173
174
|
|
|
174
175
|
describe('instruments that change while mounted', () => {
|
|
175
|
-
it('fills an open trial’s config before its replaced instrument renders', () => {
|
|
176
|
+
it('fills an open trial’s config before its replaced instrument renders', async () => {
|
|
176
177
|
const v1: Instrument = {
|
|
177
178
|
name: 'Grow',
|
|
178
179
|
defaultConfig: () => ({ size: 1 }),
|
|
@@ -188,7 +189,7 @@ describe('instruments that change while mounted', () => {
|
|
|
188
189
|
return null;
|
|
189
190
|
},
|
|
190
191
|
};
|
|
191
|
-
const view =
|
|
192
|
+
const view = await renderSettled(
|
|
192
193
|
<Lab instruments={[v1]} defaultInstrument="Grow">
|
|
193
194
|
<CaptureLab />
|
|
194
195
|
</Lab>,
|
|
@@ -203,9 +204,9 @@ describe('instruments that change while mounted', () => {
|
|
|
203
204
|
expect(seenByV2.every((c) => c.color === 'red')).toBe(true);
|
|
204
205
|
});
|
|
205
206
|
|
|
206
|
-
it('opens a trial of an instrument added after mount', () => {
|
|
207
|
+
it('opens a trial of an instrument added after mount', async () => {
|
|
207
208
|
const later: Instrument = { ...stub, name: 'Later' };
|
|
208
|
-
const view =
|
|
209
|
+
const view = await renderSettled(
|
|
209
210
|
<Lab instruments={[stub]} defaultInstrument="Stub">
|
|
210
211
|
<CaptureLab />
|
|
211
212
|
</Lab>,
|
|
@@ -215,12 +216,12 @@ describe('instruments that change while mounted', () => {
|
|
|
215
216
|
<CaptureLab />
|
|
216
217
|
</Lab>,
|
|
217
218
|
);
|
|
218
|
-
act(() => labRef?.addTrial('Later'));
|
|
219
|
+
await act(async () => labRef?.addTrial('Later'));
|
|
219
220
|
expect(labRef?.trials.map((t) => t.instrumentName)).toEqual(['Stub', 'Later']);
|
|
220
221
|
expect(screen.queryByText(/Unknown instrument/)).toBeNull();
|
|
221
222
|
});
|
|
222
223
|
|
|
223
|
-
it('keeps a trial’s content mounted across an instrument swap', () => {
|
|
224
|
+
it('keeps a trial’s content mounted across an instrument swap', async () => {
|
|
224
225
|
let mounts = 0;
|
|
225
226
|
function Probe() {
|
|
226
227
|
useEffect(() => {
|
|
@@ -235,7 +236,7 @@ describe('instruments that change while mounted', () => {
|
|
|
235
236
|
render: () => <Probe />,
|
|
236
237
|
};
|
|
237
238
|
const v2: Instrument = { ...v1, defaultConfig: () => ({ extra: 1 }) };
|
|
238
|
-
const view =
|
|
239
|
+
const view = await renderSettled(<Lab instruments={[v1]} defaultInstrument="Keep" />);
|
|
239
240
|
view.rerender(<Lab instruments={[v2]} defaultInstrument="Keep" />);
|
|
240
241
|
expect(mounts).toBe(1);
|
|
241
242
|
});
|
|
@@ -249,72 +250,72 @@ describe('focused trial', () => {
|
|
|
249
250
|
render: () => <iframe title="story frame" />,
|
|
250
251
|
};
|
|
251
252
|
|
|
252
|
-
it('is the only trial until another opens, then the one that opened', () => {
|
|
253
|
-
mountLab();
|
|
253
|
+
it('is the only trial until another opens, then the one that opened', async () => {
|
|
254
|
+
await mountLab();
|
|
254
255
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id);
|
|
255
|
-
act(() => labRef?.addTrial('StubB'));
|
|
256
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
256
257
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[1]?.id);
|
|
257
|
-
act(() => labRef?.cloneTrial(labRef?.trials[0]?.id ?? ''));
|
|
258
|
+
await act(async () => labRef?.cloneTrial(labRef?.trials[0]?.id ?? ''));
|
|
258
259
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[1]?.id);
|
|
259
260
|
expect(labRef?.trials.map((t) => t.instrumentName)).toEqual(['Stub', 'Stub', 'StubB']);
|
|
260
261
|
});
|
|
261
262
|
|
|
262
|
-
it('moves to a trial a pointer goes down in', () => {
|
|
263
|
-
mountLab();
|
|
264
|
-
act(() => labRef?.addTrial('StubB'));
|
|
263
|
+
it('moves to a trial a pointer goes down in', async () => {
|
|
264
|
+
await mountLab();
|
|
265
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
265
266
|
fireEvent.pointerDown(within(regions()[0] as HTMLElement).getByTestId('stub-content'));
|
|
266
267
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id);
|
|
267
268
|
});
|
|
268
269
|
|
|
269
|
-
it('moves to a trial focus moves into', () => {
|
|
270
|
-
mountLab();
|
|
271
|
-
act(() => labRef?.addTrial('StubB'));
|
|
272
|
-
act(() => (regions()[0] as HTMLElement).focus());
|
|
270
|
+
it('moves to a trial focus moves into', async () => {
|
|
271
|
+
await mountLab();
|
|
272
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
273
|
+
await act(async () => (regions()[0] as HTMLElement).focus());
|
|
273
274
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id);
|
|
274
275
|
});
|
|
275
276
|
|
|
276
277
|
it('moves to a trial whose frame takes focus, which fires nothing in the lab’s document', async () => {
|
|
277
|
-
mountLab({ instruments: [framed, stubB], defaultInstrument: 'Framed' });
|
|
278
|
-
act(() => labRef?.addTrial('StubB'));
|
|
279
|
-
act(() => screen.getByTitle('story frame').focus());
|
|
278
|
+
await mountLab({ instruments: [framed, stubB], defaultInstrument: 'Framed' });
|
|
279
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
280
|
+
await act(async () => screen.getByTitle('story frame').focus());
|
|
280
281
|
fireEvent.blur(window);
|
|
281
282
|
await waitFor(() => expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id));
|
|
282
283
|
});
|
|
283
284
|
|
|
284
|
-
it('falls back to the first trial when the focused one closes', () => {
|
|
285
|
-
mountLab();
|
|
286
|
-
act(() => labRef?.addTrial('StubB'));
|
|
287
|
-
act(() => labRef?.closeTrial(labRef?.trials[1]?.id ?? ''));
|
|
285
|
+
it('falls back to the first trial when the focused one closes', async () => {
|
|
286
|
+
await mountLab();
|
|
287
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
288
|
+
await act(async () => labRef?.closeTrial(labRef?.trials[1]?.id ?? ''));
|
|
288
289
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id);
|
|
289
290
|
});
|
|
290
291
|
|
|
291
|
-
it('is marked on its trial only when there is more than one', () => {
|
|
292
|
-
mountLab();
|
|
292
|
+
it('is marked on its trial only when there is more than one', async () => {
|
|
293
|
+
await mountLab();
|
|
293
294
|
expect(regions()[0]).not.toHaveAttribute('data-focused');
|
|
294
|
-
act(() => labRef?.addTrial('StubB'));
|
|
295
|
+
await act(async () => labRef?.addTrial('StubB'));
|
|
295
296
|
expect(regions()[1]).toHaveAttribute('data-focused', 'true');
|
|
296
297
|
expect(regions()[0]).not.toHaveAttribute('data-focused');
|
|
297
298
|
});
|
|
298
299
|
});
|
|
299
300
|
|
|
300
301
|
describe('swapTrial', () => {
|
|
301
|
-
it('runs another instrument in the trial’s place, and keeps focus on that place', () => {
|
|
302
|
-
mountLab();
|
|
303
|
-
act(() => labRef?.addTrial('Stub'));
|
|
302
|
+
it('runs another instrument in the trial’s place, and keeps focus on that place', async () => {
|
|
303
|
+
await mountLab();
|
|
304
|
+
await act(async () => labRef?.addTrial('Stub'));
|
|
304
305
|
const second = labRef?.trials[1]?.id;
|
|
305
|
-
act(() => labRef?.focusTrial(labRef?.trials[0]?.id ?? ''));
|
|
306
|
-
act(() => labRef?.swapTrial(labRef?.trials[0]?.id ?? '', 'StubB'));
|
|
306
|
+
await act(async () => labRef?.focusTrial(labRef?.trials[0]?.id ?? ''));
|
|
307
|
+
await act(async () => labRef?.swapTrial(labRef?.trials[0]?.id ?? '', 'StubB'));
|
|
307
308
|
expect(labRef?.trials.map((t) => t.instrumentName)).toEqual(['StubB', 'Stub']);
|
|
308
309
|
expect(labRef?.trials[1]?.id).toBe(second);
|
|
309
310
|
expect(labRef?.focusedTrialId).toBe(labRef?.trials[0]?.id);
|
|
310
311
|
expect(screen.getByTestId('stub-b-content')).toBeInTheDocument();
|
|
311
312
|
});
|
|
312
313
|
|
|
313
|
-
it('leaves focus where it was when the swapped trial did not have it', () => {
|
|
314
|
-
mountLab();
|
|
315
|
-
act(() => labRef?.addTrial('Stub'));
|
|
314
|
+
it('leaves focus where it was when the swapped trial did not have it', async () => {
|
|
315
|
+
await mountLab();
|
|
316
|
+
await act(async () => labRef?.addTrial('Stub'));
|
|
316
317
|
const focused = labRef?.focusedTrialId;
|
|
317
|
-
act(() => labRef?.swapTrial(labRef?.trials[0]?.id ?? '', 'StubB'));
|
|
318
|
+
await act(async () => labRef?.swapTrial(labRef?.trials[0]?.id ?? '', 'StubB'));
|
|
318
319
|
expect(labRef?.focusedTrialId).toBe(focused);
|
|
319
320
|
});
|
|
320
321
|
});
|
package/src/lab/Lab.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type ReactNode,
|
|
6
6
|
useCallback,
|
|
7
7
|
useEffect,
|
|
8
|
+
useInsertionEffect,
|
|
8
9
|
useLayoutEffect,
|
|
9
10
|
useMemo,
|
|
10
11
|
useRef,
|
|
@@ -418,7 +419,10 @@ function LabRuntime({
|
|
|
418
419
|
}, []);
|
|
419
420
|
|
|
420
421
|
const ownSurface = useTiledSurface({ onFrame });
|
|
421
|
-
|
|
422
|
+
// Not `useLatest`: `onFrame` reads it, and is needed before the surface exists.
|
|
423
|
+
useInsertionEffect(() => {
|
|
424
|
+
surfaceRef.current = ownSurface;
|
|
425
|
+
}, [ownSurface]);
|
|
422
426
|
const [labBody, setLabBody] = useState<HTMLDivElement | null>(null);
|
|
423
427
|
const attachOwnSurface = ownSurface.containerRef;
|
|
424
428
|
const labBodyRef = useCallback(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screen } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { renderSettled } from '@weasel-js/react/testing/renderSettled';
|
|
3
4
|
import { describe, expect, it } from 'vitest';
|
|
4
5
|
import type { TrialContribution } from '../chrome/types';
|
|
5
6
|
import type { Instrument } from '../instrument/types';
|
|
@@ -34,19 +35,21 @@ const pinned: TrialContribution = {
|
|
|
34
35
|
item: { title: 'Pinned', undockable: false, body: <p>stay</p> },
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
function renderLab() {
|
|
38
|
-
return
|
|
38
|
+
async function renderLab() {
|
|
39
|
+
return renderSettled(
|
|
40
|
+
<Lab title="T" instruments={[bare]} defaultInstrument="Bare" chrome={[notes]} />,
|
|
41
|
+
);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
describe('undocking a sidebar section', () => {
|
|
42
|
-
it('starts docked inside the trial sidebar', () => {
|
|
43
|
-
const { container } = renderLab();
|
|
45
|
+
it('starts docked inside the trial sidebar', async () => {
|
|
46
|
+
const { container } = await renderLab();
|
|
44
47
|
const sidebar = container.querySelector('.lk-trial__sidebar');
|
|
45
48
|
expect(sidebar).toContainElement(screen.getByTestId('notes-body'));
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
it('moves the section out of the sidebar and into a workspace panel', async () => {
|
|
49
|
-
const { container } = renderLab();
|
|
52
|
+
const { container } = await renderLab();
|
|
50
53
|
await userEvent.click(screen.getByRole('button', { name: 'Undock Notes' }));
|
|
51
54
|
|
|
52
55
|
expect(container.querySelector('.lk-trial__sidebar')).not.toContainElement(
|
|
@@ -57,7 +60,7 @@ describe('undocking a sidebar section', () => {
|
|
|
57
60
|
});
|
|
58
61
|
|
|
59
62
|
it('docks it back', async () => {
|
|
60
|
-
const { container } = renderLab();
|
|
63
|
+
const { container } = await renderLab();
|
|
61
64
|
await userEvent.click(screen.getByRole('button', { name: 'Undock Notes' }));
|
|
62
65
|
await userEvent.click(screen.getByRole('button', { name: 'Dock Notes' }));
|
|
63
66
|
|
|
@@ -68,7 +71,7 @@ describe('undocking a sidebar section', () => {
|
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
it('sends a section declaring undockAs floating to the floating layer', async () => {
|
|
71
|
-
const { container } =
|
|
74
|
+
const { container } = await renderSettled(
|
|
72
75
|
<Lab title="T" instruments={[bare]} defaultInstrument="Bare" chrome={[floater]} />,
|
|
73
76
|
);
|
|
74
77
|
await userEvent.click(screen.getByRole('button', { name: 'Undock Floater' }));
|
|
@@ -78,8 +81,10 @@ describe('undocking a sidebar section', () => {
|
|
|
78
81
|
expect(container.querySelector('.lk-panel-tile--floating')).not.toBeNull();
|
|
79
82
|
});
|
|
80
83
|
|
|
81
|
-
it('offers no tear-out control on a section that opts out', () => {
|
|
82
|
-
|
|
84
|
+
it('offers no tear-out control on a section that opts out', async () => {
|
|
85
|
+
await renderSettled(
|
|
86
|
+
<Lab title="T" instruments={[bare]} defaultInstrument="Bare" chrome={[pinned]} />,
|
|
87
|
+
);
|
|
83
88
|
expect(screen.queryByRole('button', { name: 'Undock Pinned' })).toBeNull();
|
|
84
89
|
});
|
|
85
90
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { screen } from '@testing-library/react';
|
|
2
|
+
import { renderSettled } from '@weasel-js/react/testing/renderSettled';
|
|
2
3
|
import { describe, expect, it } from 'vitest';
|
|
3
4
|
import type { Instrument } from '../instrument/types';
|
|
4
5
|
import { Lab } from './Lab';
|
|
@@ -12,13 +13,13 @@ const Stub: Instrument = {
|
|
|
12
13
|
const Other: Instrument = { ...Stub, name: 'Other' };
|
|
13
14
|
|
|
14
15
|
describe('<LabHeader>', () => {
|
|
15
|
-
it('offers an add-trial button when the lab has one instrument', () => {
|
|
16
|
-
|
|
16
|
+
it('offers an add-trial button when the lab has one instrument', async () => {
|
|
17
|
+
await renderSettled(<Lab instruments={[Stub]} defaultInstrument="Stub" />);
|
|
17
18
|
expect(screen.getByRole('button', { name: /add trial/i })).toBeInTheDocument();
|
|
18
19
|
});
|
|
19
20
|
|
|
20
|
-
it('offers a menu instead when the lab has several', () => {
|
|
21
|
-
|
|
21
|
+
it('offers a menu instead when the lab has several', async () => {
|
|
22
|
+
await renderSettled(<Lab instruments={[Stub, Other]} defaultInstrument="Stub" />);
|
|
22
23
|
// Which instrument to add is now a choice, so the button opens a list.
|
|
23
24
|
expect(screen.getByRole('button', { name: 'Add trial' })).toHaveAttribute('aria-haspopup');
|
|
24
25
|
});
|
|
@@ -26,7 +27,7 @@ describe('<LabHeader>', () => {
|
|
|
26
27
|
it('adds a trial of the instrument chosen from the menu', async () => {
|
|
27
28
|
const { default: userEvent } = await import('@testing-library/user-event');
|
|
28
29
|
const user = userEvent.setup();
|
|
29
|
-
|
|
30
|
+
await renderSettled(<Lab instruments={[Stub, Other]} defaultInstrument="Stub" />);
|
|
30
31
|
expect(screen.queryAllByLabelText(/^Trial Other$/)).toHaveLength(0);
|
|
31
32
|
await user.click(screen.getByRole('button', { name: 'Add trial' }));
|
|
32
33
|
await user.click(screen.getByRole('menuitem', { name: 'Other' }));
|
|
@@ -37,7 +38,7 @@ describe('<LabHeader>', () => {
|
|
|
37
38
|
const { default: userEvent } = await import('@testing-library/user-event');
|
|
38
39
|
const user = userEvent.setup();
|
|
39
40
|
const titled: Instrument = { ...Other, title: 'Other / Titled' };
|
|
40
|
-
|
|
41
|
+
await renderSettled(<Lab instruments={[Stub, titled]} defaultInstrument="Stub" />);
|
|
41
42
|
await user.click(screen.getByRole('button', { name: 'Add trial' }));
|
|
42
43
|
expect(screen.getByRole('menuitem', { name: 'Stub' })).toBeInTheDocument();
|
|
43
44
|
await user.click(screen.getByRole('menuitem', { name: 'Other / Titled' }));
|
|
@@ -47,27 +48,27 @@ describe('<LabHeader>', () => {
|
|
|
47
48
|
it('adds a trial when the button is used', async () => {
|
|
48
49
|
const { default: userEvent } = await import('@testing-library/user-event');
|
|
49
50
|
const user = userEvent.setup();
|
|
50
|
-
|
|
51
|
+
await renderSettled(<Lab instruments={[Stub]} defaultInstrument="Stub" />);
|
|
51
52
|
expect(screen.getAllByLabelText(/^Trial Stub$/)).toHaveLength(1);
|
|
52
53
|
await user.click(screen.getByRole('button', { name: /add trial/i }));
|
|
53
54
|
expect(screen.getAllByLabelText(/^Trial Stub$/)).toHaveLength(2);
|
|
54
55
|
});
|
|
55
56
|
|
|
56
|
-
it('leaves the add-trial control out when the lab says so', () => {
|
|
57
|
-
const { unmount } =
|
|
57
|
+
it('leaves the add-trial control out when the lab says so', async () => {
|
|
58
|
+
const { unmount } = await renderSettled(
|
|
58
59
|
<Lab instruments={[Stub, Other]} defaultInstrument="Stub" addTrial={false} />,
|
|
59
60
|
);
|
|
60
61
|
expect(screen.queryByRole('button', { name: /add trial/i })).toBeNull();
|
|
61
62
|
expect(screen.getByRole('button', { name: /^Theme: Auto/ })).toBeInTheDocument();
|
|
62
63
|
unmount();
|
|
63
|
-
|
|
64
|
+
await renderSettled(<Lab instruments={[Stub]} defaultInstrument="Stub" addTrial={false} />);
|
|
64
65
|
expect(screen.queryByRole('button', { name: /add trial/i })).toBeNull();
|
|
65
66
|
});
|
|
66
67
|
|
|
67
68
|
it('rotates the color mode from one button', async () => {
|
|
68
69
|
const { default: userEvent } = await import('@testing-library/user-event');
|
|
69
70
|
const user = userEvent.setup();
|
|
70
|
-
|
|
71
|
+
await renderSettled(<Lab instruments={[Stub]} defaultInstrument="Stub" />);
|
|
71
72
|
expect(screen.queryByRole('radiogroup')).toBeNull();
|
|
72
73
|
for (const [now, next] of [
|
|
73
74
|
['Auto', 'Light'],
|
|
@@ -82,8 +83,8 @@ describe('<LabHeader>', () => {
|
|
|
82
83
|
expect(screen.getByRole('button', { name: /^Theme: Auto/ })).toBeInTheDocument();
|
|
83
84
|
});
|
|
84
85
|
|
|
85
|
-
it('puts the theme switch after the header content a consumer passes', () => {
|
|
86
|
-
|
|
86
|
+
it('puts the theme switch after the header content a consumer passes', async () => {
|
|
87
|
+
await renderSettled(
|
|
87
88
|
<Lab instruments={[Stub]} defaultInstrument="Stub">
|
|
88
89
|
<button type="button">Consumer</button>
|
|
89
90
|
</Lab>,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { fireEvent,
|
|
1
|
+
import { fireEvent, screen } from '@testing-library/react';
|
|
2
|
+
import { renderSettled } from '@weasel-js/react/testing/renderSettled';
|
|
2
3
|
import { describe, expect, it } from 'vitest';
|
|
3
4
|
import type { Instrument } from '../instrument/types';
|
|
4
5
|
import { Lab } from './Lab';
|
|
@@ -16,19 +17,23 @@ const tools = [
|
|
|
16
17
|
];
|
|
17
18
|
|
|
18
19
|
describe('the lab palette', () => {
|
|
19
|
-
it('does not render when the lab declares no tools', () => {
|
|
20
|
-
|
|
20
|
+
it('does not render when the lab declares no tools', async () => {
|
|
21
|
+
await renderSettled(<Lab title="T" instruments={[bare]} defaultInstrument="Bare" />);
|
|
21
22
|
expect(screen.queryByRole('toolbar', { name: 'Tools' })).toBeNull();
|
|
22
23
|
});
|
|
23
24
|
|
|
24
|
-
it('renders one button per declared tool', () => {
|
|
25
|
-
|
|
25
|
+
it('renders one button per declared tool', async () => {
|
|
26
|
+
await renderSettled(
|
|
27
|
+
<Lab title="T" instruments={[bare]} defaultInstrument="Bare" tools={tools} />,
|
|
28
|
+
);
|
|
26
29
|
expect(screen.getByRole('button', { name: 'Pick' })).toBeInTheDocument();
|
|
27
30
|
expect(screen.getByRole('button', { name: 'Pan' })).toBeInTheDocument();
|
|
28
31
|
});
|
|
29
32
|
|
|
30
|
-
it('marks the chosen tool current after a click', () => {
|
|
31
|
-
|
|
33
|
+
it('marks the chosen tool current after a click', async () => {
|
|
34
|
+
await renderSettled(
|
|
35
|
+
<Lab title="T" instruments={[bare]} defaultInstrument="Bare" tools={tools} />,
|
|
36
|
+
);
|
|
32
37
|
fireEvent.click(screen.getByRole('button', { name: 'Pan' }));
|
|
33
38
|
expect(screen.getByRole('button', { name: 'Pan' })).toHaveAttribute('aria-current', 'true');
|
|
34
39
|
});
|
package/src/lab/LabShell.less
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import '@weasel-js/theme/tokens.css';
|
|
2
|
+
import '../styles.less';
|
|
3
|
+
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { afterEach, expect, test } from 'vitest';
|
|
5
|
+
import { LabShell } from './LabShell';
|
|
6
|
+
|
|
7
|
+
// The menu sits under the shell's title, so what it inherits from the title is
|
|
8
|
+
// cascade, which only a real browser computes.
|
|
9
|
+
|
|
10
|
+
afterEach(cleanup);
|
|
11
|
+
|
|
12
|
+
const PAGES = [
|
|
13
|
+
{ href: '/corpus', label: 'Wall' },
|
|
14
|
+
{ href: '/stats', label: 'Dashboard' },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
test('only the open page is bold in the shell title menu', () => {
|
|
18
|
+
render(
|
|
19
|
+
<LabShell title="corpus" pages={PAGES} path="/corpus">
|
|
20
|
+
<p>body</p>
|
|
21
|
+
</LabShell>,
|
|
22
|
+
);
|
|
23
|
+
fireEvent.click(screen.getByRole('button', { name: /corpus/ }));
|
|
24
|
+
const weight = (name: string) =>
|
|
25
|
+
Number(getComputedStyle(screen.getByRole('menuitem', { name })).fontWeight);
|
|
26
|
+
expect(weight('Wall')).toBeGreaterThan(weight('Dashboard'));
|
|
27
|
+
});
|
package/src/lab/LabSwitcher.less
CHANGED
|
@@ -59,6 +59,8 @@
|
|
|
59
59
|
display: flex;
|
|
60
60
|
flex-direction: column;
|
|
61
61
|
padding: var(--wzl-space-xs);
|
|
62
|
+
// A host's title class lands on the wrapper, so the menu would inherit its weight.
|
|
63
|
+
font-weight: var(--wzl-font-weight-normal);
|
|
62
64
|
// `--wzl-surface-raised` is translucent by design -- it is for panels that
|
|
63
65
|
// blur what sits behind them. A menu has to be read, so it takes the opaque
|
|
64
66
|
// surface, the way `FloatingPanel` does.
|