@weasel-js/labkit 1.5.1 → 1.6.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/README.md +3 -7
- package/dist/_dts/{CanvasStackContext-CJNMS6mz.d.ts → CanvasStackContext-DQgcH1ny.d.ts} +1 -1
- package/dist/_dts/LayerList.d-2c9yup5Y.d.ts +83 -0
- package/dist/_dts/{PrefsForm.d-DPy9I8It.d.ts → PrefsRow.d-DFpPIeIC.d.ts} +16 -1
- package/dist/_dts/{Select.d-Gwr8fLpK.d.ts → Select.d-BchGMC2Y.d.ts} +129 -12
- package/dist/_dts/{frac-B4okC2lX.d.ts → frac-DTRq7Xpb.d.ts} +31 -13
- package/dist/_dts/inDialog-D5ZKGjiD.d.ts +23 -0
- package/dist/_dts/{index-CSJoj4LC.d.ts → index-B0--8PEM.d.ts} +5 -4
- package/dist/_dts/index-DINmCuLA.d.ts +453 -0
- package/dist/_dts/number.d-OeQYQoUO.d.ts +28 -0
- package/dist/_dts/{types-DzoNY1pO.d.ts → types-B7y8hX1D.d.ts} +6 -6
- package/dist/_dts/{usePanZoom-Pzf9f2jh.d.ts → usePanZoom-Bq73pwFe.d.ts} +4 -47
- package/dist/_dts/{useTrialState-uLlmaccn.d.ts → useTrialState-CP4jfuKl.d.ts} +1 -1
- package/dist/canvas/index.d.ts +6 -5
- package/dist/canvas/index.js +1 -1
- package/dist/chrome/index.d.ts +5 -4
- package/dist/chrome/index.js +7 -7
- package/dist/chunk-2RVCB2PT.js +3 -0
- package/dist/chunk-2RVCB2PT.js.map +1 -0
- package/dist/{chunk-UN4U4P63.js → chunk-3FI7Y4R4.js} +9 -9
- package/dist/chunk-3FI7Y4R4.js.map +1 -0
- package/dist/{chunk-7PFH3CNM.js → chunk-AWH3SRPW.js} +31 -5
- package/dist/chunk-AWH3SRPW.js.map +1 -0
- package/dist/{chunk-ZDHY47EV.js → chunk-BVL7Y574.js} +25 -9
- package/dist/chunk-BVL7Y574.js.map +1 -0
- package/dist/{chunk-IHUVQ3TX.js → chunk-H5VIV7MQ.js} +31 -27
- package/dist/chunk-H5VIV7MQ.js.map +1 -0
- package/dist/chunk-HFRE4QQV.js +400 -0
- package/dist/chunk-HFRE4QQV.js.map +1 -0
- package/dist/{chunk-IXTQI7JX.js → chunk-MOLIUNVH.js} +4 -4
- package/dist/{chunk-IXTQI7JX.js.map → chunk-MOLIUNVH.js.map} +1 -1
- package/dist/{chunk-CEIUBPPW.js → chunk-TT5C5S6R.js} +3 -86
- package/dist/chunk-TT5C5S6R.js.map +1 -0
- package/dist/chunk-USO6TERP.js +90 -0
- package/dist/chunk-USO6TERP.js.map +1 -0
- package/dist/{chunk-PHK4W562.js → chunk-VQ47KWD5.js} +3 -3
- package/dist/{chunk-PHK4W562.js.map → chunk-VQ47KWD5.js.map} +1 -1
- package/dist/chunk-WUJXJC5O.js +14568 -0
- package/dist/chunk-WUJXJC5O.js.map +1 -0
- package/dist/{chunk-EHGVROVV.js → chunk-ZORVNOKX.js} +6 -25
- package/dist/chunk-ZORVNOKX.js.map +1 -0
- package/dist/config/index.d.ts +53 -11
- package/dist/config/index.js +5 -5
- package/dist/controls/index.d.ts +6 -3
- package/dist/controls/index.js +4 -4
- package/dist/dragdrop/index.d.ts +4 -3
- package/dist/index.d.ts +139 -114
- package/dist/index.js +470 -479
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +6 -35
- package/dist/layers/index.js +2 -3
- package/dist/loupe/index.d.ts +6 -5
- package/dist/passthrough/weasel-ui.d.ts +421 -215
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.d.ts +2 -13
- package/dist/primitives/index.js +4 -4
- package/dist/state/index.d.ts +6 -5
- package/dist/state/index.js +5 -5
- package/dist/styles.css +410 -190
- package/dist/undo/index.d.ts +4 -3
- package/package.json +9 -13
- package/src/annotations/frac.test.ts +7 -0
- package/src/annotations/paint.test.ts +21 -0
- package/src/annotations/paint.ts +12 -0
- package/src/annotations/store.test.ts +31 -0
- package/src/annotations/types.ts +3 -2
- package/src/canvas/Stage.test.tsx +18 -0
- package/src/canvas/index.ts +0 -9
- package/src/chrome/labTypes.ts +1 -1
- package/src/chrome/regions/PaletteRegion.test.tsx +18 -0
- package/src/chrome/regions/PaletteRegion.tsx +5 -4
- package/src/chrome/regions/SidebarRegion.less +197 -0
- package/src/chrome/regions/SidebarRegion.test.tsx +20 -0
- package/src/chrome/regions/SidebarRegion.tsx +7 -2
- package/src/chrome/regions/TitleBarRegion.tsx +1 -1
- package/src/chrome/types.ts +13 -4
- package/src/config/autoConfig.ts +2 -2
- package/src/config/builder.ts +23 -5
- package/src/config/entry.test.ts +8 -0
- package/src/config/index.ts +2 -0
- package/src/config/rules.ts +2 -0
- package/src/config/sectionTree.test.ts +146 -0
- package/src/config/sectionTree.ts +124 -0
- package/src/config/types.ts +4 -4
- package/src/controls/AutoControls.stories.tsx +6 -6
- package/src/controls/ControlPanel.less +27 -0
- package/src/controls/ControlPanel.stories.tsx +95 -1
- package/src/controls/ControlPanel.test.tsx +82 -112
- package/src/controls/ControlPanel.tsx +159 -396
- package/src/controls/inDialog.test.tsx +82 -0
- package/src/controls/inDialog.tsx +46 -0
- package/src/controls/index.ts +1 -0
- package/src/index.test.ts +0 -2
- package/src/index.ts +14 -35
- package/src/instrument/types.ts +5 -2
- package/src/lab/Lab.nebula.test.tsx +31 -0
- package/src/lab/Lab.tsx +57 -18
- package/src/lab/LabBoundary.test.tsx +66 -0
- package/src/lab/LabBoundary.tsx +56 -0
- package/src/lab/LabHeader.tsx +4 -23
- package/src/lab/LabRoot.tsx +2 -3
- package/src/lab/LabShell.less +0 -1
- package/src/lab/LabShell.stories.tsx +15 -0
- package/src/lab/LabShell.test.tsx +18 -0
- package/src/lab/LabShell.tsx +14 -1
- package/src/lab/LabSwitcher.less +1 -1
- package/src/lab/LabSwitcher.test.tsx +41 -0
- package/src/lab/LabSwitcher.tsx +30 -8
- package/src/lab/index.ts +1 -0
- package/src/layers/AGENTS.md +18 -74
- package/src/layers/index.ts +4 -2
- package/src/passthrough/weasel-ui.ts +25 -10
- package/src/primitives/FpsMeter.less +6 -1
- package/src/primitives/FpsMeter.test.tsx +12 -4
- package/src/primitives/FpsMeter.tsx +6 -1
- package/src/primitives/JobProgress.stories.tsx +1 -1
- package/src/primitives/StatusBar.less +6 -0
- package/src/primitives/index.ts +0 -2
- package/src/specimen/Specimen.tsx +42 -56
- package/src/state/types.ts +8 -2
- package/src/state/view.test.ts +4 -4
- package/src/styles.less +4 -2
- package/src/theme/Interstellar.stories.tsx +8 -9
- package/src/theme/base.less +3 -20
- package/src/theme/interstellar.test.ts +6 -3
- package/src/theme/interstellar.theme.json +0 -56
- package/src/theme/interstellar.ts +2 -2
- package/src/trial/Trial.canvas.test.tsx +9 -5
- package/src/trial/Trial.config.test.tsx +1 -1
- package/src/trial/Trial.tsx +30 -8
- package/dist/_dts/index-BNdz-tNd.d.ts +0 -423
- package/dist/chunk-7PFH3CNM.js.map +0 -1
- package/dist/chunk-CEIUBPPW.js.map +0 -1
- package/dist/chunk-EH7UEQV7.js +0 -590
- package/dist/chunk-EH7UEQV7.js.map +0 -1
- package/dist/chunk-EHGVROVV.js.map +0 -1
- package/dist/chunk-IHUVQ3TX.js.map +0 -1
- package/dist/chunk-MDVTK5U3.js +0 -170
- package/dist/chunk-MDVTK5U3.js.map +0 -1
- package/dist/chunk-PJ7WEQBJ.js +0 -18
- package/dist/chunk-PJ7WEQBJ.js.map +0 -1
- package/dist/chunk-T3EC2DXD.js +0 -12628
- package/dist/chunk-T3EC2DXD.js.map +0 -1
- package/dist/chunk-UN4U4P63.js.map +0 -1
- package/dist/chunk-ZDHY47EV.js.map +0 -1
- package/dist/ui/layers/index.d.ts +0 -66
- package/dist/ui/layers/index.js +0 -3
- package/dist/ui/layers/index.js.map +0 -1
- package/src/canvas/useOrbit.test.ts +0 -167
- package/src/canvas/useOrbit.ts +0 -156
- package/src/lab/useSystemMode.ts +0 -30
- package/src/layers/LayerList.less +0 -93
- package/src/layers/LayerList.stories.tsx +0 -66
- package/src/layers/LayerList.test.tsx +0 -232
- package/src/layers/LayerList.tsx +0 -268
- package/src/primitives/Sidebar.less +0 -112
- package/src/primitives/Sidebar.stories.tsx +0 -38
- package/src/primitives/Sidebar.test.tsx +0 -74
- package/src/primitives/Sidebar.tsx +0 -35
- package/src/ui/layers/index.ts +0 -5
|
@@ -187,7 +187,11 @@ describe('<ControlPanel> schema', () => {
|
|
|
187
187
|
[],
|
|
188
188
|
);
|
|
189
189
|
render(
|
|
190
|
-
<ControlPanel
|
|
190
|
+
<ControlPanel
|
|
191
|
+
schema={schema}
|
|
192
|
+
config={{ showGrid: true, snap: false }}
|
|
193
|
+
setConfig={setConfig}
|
|
194
|
+
/>,
|
|
191
195
|
);
|
|
192
196
|
expect(screen.getByRole('checkbox', { name: 'Show grid' })).toBeInTheDocument();
|
|
193
197
|
const sw = screen.getByRole('switch', { name: 'Snap' });
|
|
@@ -478,7 +482,27 @@ describe('<ControlPanel> format', () => {
|
|
|
478
482
|
setConfig={vi.fn()}
|
|
479
483
|
/>,
|
|
480
484
|
);
|
|
481
|
-
expect(screen.getByDisplayValue('2.
|
|
485
|
+
expect(screen.getByDisplayValue('2.00M')).toBeInTheDocument();
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
describe('<ControlPanel> group descriptions', () => {
|
|
490
|
+
it('draws a named group’s describe() above its rows', () => {
|
|
491
|
+
const schema = resolveConfigSchema(
|
|
492
|
+
f.schema({
|
|
493
|
+
grid: f
|
|
494
|
+
.group({ cellSize: f.number(20) })
|
|
495
|
+
.label('Grid')
|
|
496
|
+
.describe('How the background lattice is spaced.'),
|
|
497
|
+
}),
|
|
498
|
+
[],
|
|
499
|
+
);
|
|
500
|
+
render(
|
|
501
|
+
<ControlPanel schema={schema} config={{ grid: { cellSize: 20 } }} setConfig={vi.fn()} />,
|
|
502
|
+
);
|
|
503
|
+
const note = screen.getByText('How the background lattice is spaced.');
|
|
504
|
+
const field = screen.getByLabelText('Cell size');
|
|
505
|
+
expect(note.compareDocumentPosition(field) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
482
506
|
});
|
|
483
507
|
});
|
|
484
508
|
|
|
@@ -675,7 +699,7 @@ describe('<ControlPanel> nested groups', () => {
|
|
|
675
699
|
});
|
|
676
700
|
|
|
677
701
|
describe('<ControlPanel> auto', () => {
|
|
678
|
-
it('renders a
|
|
702
|
+
it('renders a label toggle whether or not it was given a set of auto paths', () => {
|
|
679
703
|
render(
|
|
680
704
|
<ControlPanel
|
|
681
705
|
schema={resolveConfigSchema(f.schema({ gap: f.number(12).range(0, 48) }), [])}
|
|
@@ -708,7 +732,7 @@ describe('<ControlPanel> auto', () => {
|
|
|
708
732
|
expect(setConfig).toHaveBeenCalledWith('gap', 12);
|
|
709
733
|
});
|
|
710
734
|
|
|
711
|
-
it(
|
|
735
|
+
it('reads out the bare word, resolver or not', () => {
|
|
712
736
|
render(
|
|
713
737
|
<ControlPanel
|
|
714
738
|
schema={resolveConfigSchema(
|
|
@@ -725,19 +749,8 @@ describe('<ControlPanel> auto', () => {
|
|
|
725
749
|
setConfig={() => {}}
|
|
726
750
|
/>,
|
|
727
751
|
);
|
|
728
|
-
expect(screen.getByText('auto · 18')).toBeInTheDocument();
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
it('reads "auto" alone for a path with no resolver', () => {
|
|
732
|
-
render(
|
|
733
|
-
<ControlPanel
|
|
734
|
-
schema={resolveConfigSchema(f.schema({ cols: f.number(3).range(0, 8) }), [])}
|
|
735
|
-
config={{ cols: 3 }}
|
|
736
|
-
auto={new Set(['cols'])}
|
|
737
|
-
setConfig={() => {}}
|
|
738
|
-
/>,
|
|
739
|
-
);
|
|
740
752
|
expect(screen.getByText('auto')).toBeInTheDocument();
|
|
753
|
+
expect(screen.queryByText(/auto · /)).toBeNull();
|
|
741
754
|
});
|
|
742
755
|
|
|
743
756
|
it('writes the sentinel when the dot turns a row auto', async () => {
|
|
@@ -794,11 +807,11 @@ describe('<ControlPanel> auto', () => {
|
|
|
794
807
|
expect(screen.queryByRole('button', { name: /Seed/ })).toBeNull();
|
|
795
808
|
});
|
|
796
809
|
|
|
797
|
-
it('
|
|
810
|
+
it('draws what the instrument reads when a resolver depends on another auto path', () => {
|
|
798
811
|
// `width` is auto with no resolver, so the instrument sees `undefined` and
|
|
799
812
|
// `gap` resolves from that. Re-running gap's resolver against the raw
|
|
800
|
-
// config would instead read the pinned 640 and
|
|
801
|
-
render(
|
|
813
|
+
// config would instead read the pinned 640 and draw a number nobody got.
|
|
814
|
+
const { container } = render(
|
|
802
815
|
<ControlPanel
|
|
803
816
|
schema={resolveConfigSchema(
|
|
804
817
|
f.schema({
|
|
@@ -806,7 +819,7 @@ describe('<ControlPanel> auto', () => {
|
|
|
806
819
|
gap: f
|
|
807
820
|
.number(12)
|
|
808
821
|
.range(0, 48)
|
|
809
|
-
.auto((c) => (c.width === undefined ?
|
|
822
|
+
.auto((c) => (c.width === undefined ? 5 : (c.width as number) / 64)),
|
|
810
823
|
}),
|
|
811
824
|
[],
|
|
812
825
|
)}
|
|
@@ -815,27 +828,7 @@ describe('<ControlPanel> auto', () => {
|
|
|
815
828
|
setConfig={() => {}}
|
|
816
829
|
/>,
|
|
817
830
|
);
|
|
818
|
-
expect(
|
|
819
|
-
expect(screen.queryByText('auto · 10')).toBeNull();
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
it('does not repeat a resolved value the control itself already shows', () => {
|
|
823
|
-
render(
|
|
824
|
-
<ControlPanel
|
|
825
|
-
schema={resolveConfigSchema(
|
|
826
|
-
f.schema({ caption: f.string('typed').auto(() => 'eight across') }),
|
|
827
|
-
[],
|
|
828
|
-
)}
|
|
829
|
-
config={{ caption: 'typed' }}
|
|
830
|
-
auto={new Set(['caption'])}
|
|
831
|
-
setConfig={() => {}}
|
|
832
|
-
/>,
|
|
833
|
-
);
|
|
834
|
-
// The field below the readout is already showing it, and the readout slot
|
|
835
|
-
// is one narrow column — a long string wraps it onto two lines.
|
|
836
|
-
expect(screen.getByText('auto')).toBeInTheDocument();
|
|
837
|
-
expect(screen.queryByText(/auto · /)).toBeNull();
|
|
838
|
-
expect(screen.getByDisplayValue('eight across')).toBeInTheDocument();
|
|
831
|
+
expect(container.querySelector('input[type=range]')).toHaveValue('5');
|
|
839
832
|
});
|
|
840
833
|
|
|
841
834
|
it('draws an auto control at the resolved value, not the value underneath it', () => {
|
|
@@ -881,7 +874,7 @@ describe('<ControlPanel> auto', () => {
|
|
|
881
874
|
});
|
|
882
875
|
|
|
883
876
|
// Every kind, because the panel wraps some rows before rendering them and a
|
|
884
|
-
// wrapper that drops the auto props leaves that kind silently
|
|
877
|
+
// wrapper that drops the auto props leaves that kind silently pinned.
|
|
885
878
|
it.each([
|
|
886
879
|
['number', f.number(3).range(0, 8)],
|
|
887
880
|
['slider', f.number(3).range(0, 8).slider()],
|
|
@@ -890,7 +883,7 @@ describe('<ControlPanel> auto', () => {
|
|
|
890
883
|
['radio', f.enum('a', ['a', 'b']).radio()],
|
|
891
884
|
['string', f.string('hi')],
|
|
892
885
|
['color', f.color('#3a86ff')],
|
|
893
|
-
])('marks a %s row auto and gives it a
|
|
886
|
+
])('marks a %s row auto and gives it a label toggle', (_kind, node) => {
|
|
894
887
|
const { container } = render(
|
|
895
888
|
<ControlPanel
|
|
896
889
|
schema={resolveConfigSchema(f.schema({ thing: node.label('Thing') }), [])}
|
|
@@ -899,76 +892,11 @@ describe('<ControlPanel> auto', () => {
|
|
|
899
892
|
setConfig={() => {}}
|
|
900
893
|
/>,
|
|
901
894
|
);
|
|
902
|
-
|
|
903
|
-
expect(row).not.toBeNull();
|
|
904
|
-
expect(row?.className).toMatch(/rowAuto/);
|
|
895
|
+
expect(container.querySelector('[class*=rowAuto]')).not.toBeNull();
|
|
905
896
|
expect(screen.getByRole('button', { name: 'Pin Thing' })).toBeInTheDocument();
|
|
906
897
|
});
|
|
907
898
|
});
|
|
908
899
|
|
|
909
|
-
describe('<ControlPanel> shift-click', () => {
|
|
910
|
-
const panel = (props = {}) =>
|
|
911
|
-
render(
|
|
912
|
-
<ControlPanel
|
|
913
|
-
schema={resolveConfigSchema(f.schema({ gap: f.number(12).range(0, 48) }), [])}
|
|
914
|
-
config={{ gap: 12 }}
|
|
915
|
-
auto={new Set()}
|
|
916
|
-
setConfig={() => {}}
|
|
917
|
-
{...props}
|
|
918
|
-
/>,
|
|
919
|
-
);
|
|
920
|
-
|
|
921
|
-
it('toggles a row on shift-pointerdown and suppresses the control it landed on', () => {
|
|
922
|
-
const setConfig = vi.fn();
|
|
923
|
-
const { container } = panel({ setConfig });
|
|
924
|
-
const track = container.querySelector('input[type=range]') as HTMLInputElement;
|
|
925
|
-
const ev = new PointerEvent('pointerdown', { bubbles: true, cancelable: true, shiftKey: true });
|
|
926
|
-
track.dispatchEvent(ev);
|
|
927
|
-
|
|
928
|
-
expect(setConfig).toHaveBeenCalledWith('gap', auto);
|
|
929
|
-
// A PROXY, not the real claim. jsdom synthesizes neither a label's click
|
|
930
|
-
// retargeting nor a range input's drag, so "the slider did not move" cannot
|
|
931
|
-
// fail here. What is assertable is that the default was suppressed; the
|
|
932
|
-
// browser half is covered by the story.
|
|
933
|
-
expect(ev.defaultPrevented).toBe(true);
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
it('leaves an ordinary pointerdown alone', () => {
|
|
937
|
-
const setConfig = vi.fn();
|
|
938
|
-
const { container } = panel({ setConfig });
|
|
939
|
-
container
|
|
940
|
-
.querySelector('input[type=range]')
|
|
941
|
-
?.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, cancelable: true }));
|
|
942
|
-
expect(setConfig).not.toHaveBeenCalled();
|
|
943
|
-
});
|
|
944
|
-
|
|
945
|
-
it('ignores shift-pointerdown on a manual row', () => {
|
|
946
|
-
const setConfig = vi.fn();
|
|
947
|
-
const { container } = panel({
|
|
948
|
-
schema: resolveConfigSchema(f.schema({ seed: f.number(1).manual().range(0, 8) }), []),
|
|
949
|
-
config: { seed: 1 },
|
|
950
|
-
setConfig,
|
|
951
|
-
});
|
|
952
|
-
container
|
|
953
|
-
.querySelector('input')
|
|
954
|
-
?.dispatchEvent(
|
|
955
|
-
new PointerEvent('pointerdown', { bubbles: true, cancelable: true, shiftKey: true }),
|
|
956
|
-
);
|
|
957
|
-
expect(setConfig).not.toHaveBeenCalled();
|
|
958
|
-
});
|
|
959
|
-
|
|
960
|
-
it('pins a shift-clicked auto row back at its stored value', () => {
|
|
961
|
-
const setConfig = vi.fn();
|
|
962
|
-
const { container } = panel({ config: { gap: 24 }, auto: new Set(['gap']), setConfig });
|
|
963
|
-
container
|
|
964
|
-
.querySelector('input[type=range]')
|
|
965
|
-
?.dispatchEvent(
|
|
966
|
-
new PointerEvent('pointerdown', { bubbles: true, cancelable: true, shiftKey: true }),
|
|
967
|
-
);
|
|
968
|
-
expect(setConfig).toHaveBeenCalledWith('gap', 24);
|
|
969
|
-
});
|
|
970
|
-
});
|
|
971
|
-
|
|
972
900
|
describe('<ControlPanel> pair', () => {
|
|
973
901
|
const paired = () =>
|
|
974
902
|
resolveConfigSchema(
|
|
@@ -986,9 +914,13 @@ describe('<ControlPanel> pair', () => {
|
|
|
986
914
|
const row = screen.getByText('Offset').closest('div') as HTMLElement;
|
|
987
915
|
expect(within(row).getByLabelText('X')).toHaveValue(10);
|
|
988
916
|
expect(within(row).getByLabelText('Y')).toHaveValue(20);
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
it('captions each cell of a pair with its own name, so a paired switch is not left unnamed', () => {
|
|
920
|
+
render(<ControlPanel schema={paired()} config={config} setConfig={vi.fn()} />);
|
|
921
|
+
const row = screen.getByText('Offset').closest('div') as HTMLElement;
|
|
922
|
+
expect(within(row).getByText('X')).toHaveClass('lk-pair-label');
|
|
923
|
+
expect(within(row).getByText('Y')).toHaveClass('lk-pair-label');
|
|
992
924
|
});
|
|
993
925
|
|
|
994
926
|
it('writes each cell of a paired row to its own path', () => {
|
|
@@ -998,6 +930,23 @@ describe('<ControlPanel> pair', () => {
|
|
|
998
930
|
expect(setConfig).toHaveBeenCalledWith('y', 30);
|
|
999
931
|
});
|
|
1000
932
|
|
|
933
|
+
it('keeps a segmented leaf segmented when it shares a row, and gives that row the width', () => {
|
|
934
|
+
const schema = resolveConfigSchema(
|
|
935
|
+
f.schema({
|
|
936
|
+
camera: f.enum<'2d' | '3d'>('3d', ['2d', '3d']).radio().label('').pair('Camera'),
|
|
937
|
+
hold: f.boolean(true).toggle().label('Hold front').pair('Camera'),
|
|
938
|
+
}),
|
|
939
|
+
[],
|
|
940
|
+
);
|
|
941
|
+
render(
|
|
942
|
+
<ControlPanel schema={schema} config={{ camera: '3d', hold: true }} setConfig={vi.fn()} />,
|
|
943
|
+
);
|
|
944
|
+
const row = screen.getByText('Camera').closest('div') as HTMLElement;
|
|
945
|
+
expect(within(row).getByRole('radio', { name: '2d' })).toBeInTheDocument();
|
|
946
|
+
expect(within(row).queryByRole('combobox')).toBeNull();
|
|
947
|
+
expect(row.className).toMatch(/span/);
|
|
948
|
+
});
|
|
949
|
+
|
|
1001
950
|
it('leaves an unpaired sibling on its own row', () => {
|
|
1002
951
|
render(<ControlPanel schema={paired()} config={config} setConfig={vi.fn()} />);
|
|
1003
952
|
const row = screen.getByText('Offset').closest('div') as HTMLElement;
|
|
@@ -1121,3 +1070,24 @@ describe('<ControlPanel> color alpha', () => {
|
|
|
1121
1070
|
expect(screen.queryByLabelText('Tint opacity')).toBeNull();
|
|
1122
1071
|
});
|
|
1123
1072
|
});
|
|
1073
|
+
|
|
1074
|
+
describe('<ControlPanel> title, stance and tone', () => {
|
|
1075
|
+
const fields: ConfigField[] = [{ key: 'on', label: 'On', type: 'checkbox', default: true }];
|
|
1076
|
+
|
|
1077
|
+
it('renders the bare list when given none of them', () => {
|
|
1078
|
+
const { container } = render(<ControlPanel fields={fields} config={{ on: true }} setConfig={vi.fn()} />);
|
|
1079
|
+
expect(container.firstElementChild?.classList.contains('lk-control-panel')).toBe(true);
|
|
1080
|
+
expect(container.querySelector('[data-stance], h2')).toBeNull();
|
|
1081
|
+
});
|
|
1082
|
+
|
|
1083
|
+
it('wraps its rows in a panel carrying them when asked', () => {
|
|
1084
|
+
const { container } = render(
|
|
1085
|
+
<ControlPanel title="View" stance="scope" tone={1} fields={fields} config={{ on: true }} setConfig={vi.fn()} />,
|
|
1086
|
+
);
|
|
1087
|
+
const panel = container.firstElementChild as HTMLElement;
|
|
1088
|
+
expect(panel.dataset.stance).toBe('scope');
|
|
1089
|
+
expect(panel.dataset.tone).toBe('1');
|
|
1090
|
+
expect(screen.getByRole('heading', { name: 'View' })).toBeTruthy();
|
|
1091
|
+
expect(panel.querySelector('.lk-control-panel')).not.toBeNull();
|
|
1092
|
+
});
|
|
1093
|
+
});
|