@svgrid/grid 2.1.21 → 2.1.23
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 +9 -2
- package/dist/DockNodeView.svelte +306 -0
- package/dist/DockNodeView.svelte.d.ts +7 -0
- package/dist/DockPopoutHost.svelte +17 -0
- package/dist/DockPopoutHost.svelte.d.ts +14 -0
- package/dist/GridMenus.svelte +83 -3
- package/dist/SvAutoComplete.svelte +5 -3
- package/dist/SvCarousel.svelte +20 -42
- package/dist/SvColorInput.svelte +4 -3
- package/dist/SvColorInput.svelte.d.ts +1 -1
- package/dist/SvComboBox.svelte +7 -3
- package/dist/SvCommand.svelte +28 -85
- package/dist/SvCountryInput.svelte +1 -1
- package/dist/SvDateRangeInput.svelte +1 -1
- package/dist/SvDateTimePicker.svelte +9 -3
- package/dist/SvDateTimePicker.svelte.d.ts +3 -0
- package/dist/SvDockLayout.svelte +244 -0
- package/dist/SvDockLayout.svelte.d.ts +77 -0
- package/dist/SvDockManager.svelte +922 -0
- package/dist/SvDockManager.svelte.d.ts +106 -0
- package/dist/SvDrawer.svelte +69 -47
- package/dist/SvDrawer.svelte.d.ts +4 -0
- package/dist/SvDropDownList.svelte +85 -13
- package/dist/SvDropDownList.svelte.d.ts +3 -0
- package/dist/SvField.svelte +21 -4
- package/dist/SvField.svelte.d.ts +1 -0
- package/dist/SvForm.svelte +201 -91
- package/dist/SvForm.svelte.d.ts +15 -22
- package/dist/SvGrid.controller.svelte.d.ts +32 -1
- package/dist/SvGrid.controller.svelte.js +156 -27
- package/dist/SvGrid.css +193 -5
- package/dist/SvGrid.svelte +357 -12
- package/dist/SvGrid.types.d.ts +452 -1
- package/dist/SvGridDropdown.svelte +8 -1
- package/dist/SvGridSelect.svelte +1 -0
- package/dist/SvListBox.svelte +36 -14
- package/dist/SvMaskedInput.svelte +4 -3
- package/dist/SvMaskedInput.svelte.d.ts +1 -1
- package/dist/SvMenu.svelte +1 -1
- package/dist/SvMenuList.svelte +23 -71
- package/dist/SvMenuList.svelte.d.ts +2 -13
- package/dist/SvModal.svelte +12 -29
- package/dist/SvMultiSelect.svelte +1 -0
- package/dist/SvNumberInput.svelte +4 -3
- package/dist/SvNumberInput.svelte.d.ts +1 -1
- package/dist/SvPagination.svelte +18 -18
- package/dist/SvPasswordInput.svelte +3 -2
- package/dist/SvPasswordInput.svelte.d.ts +1 -1
- package/dist/SvPhoneInput.svelte +3 -2
- package/dist/SvPhoneInput.svelte.d.ts +1 -1
- package/dist/SvPopover.svelte +1 -1
- package/dist/SvStepper.svelte +6 -9
- package/dist/SvTagsInput.svelte +3 -2
- package/dist/SvTagsInput.svelte.d.ts +1 -1
- package/dist/SvTooltip.svelte +12 -23
- package/dist/SvTour.svelte +32 -4
- package/dist/SvTreeSelect.svelte +1 -0
- package/dist/build-api.js +76 -54
- package/dist/cdn/svgrid.js +10907 -6444
- package/dist/cdn/svgrid.svelte-external.js +9622 -5475
- package/dist/columns.js +6 -0
- package/dist/conditional-formatting.d.ts +67 -3
- package/dist/conditional-formatting.js +124 -17
- package/dist/createCarousel.svelte.d.ts +72 -0
- package/dist/createCarousel.svelte.js +80 -0
- package/dist/createCommand.svelte.d.ts +62 -0
- package/dist/createCommand.svelte.js +109 -0
- package/dist/createForm.svelte.d.ts +62 -0
- package/dist/createForm.svelte.js +374 -0
- package/dist/createMenu.svelte.d.ts +88 -0
- package/dist/createMenu.svelte.js +153 -0
- package/dist/createOverlay.svelte.d.ts +38 -0
- package/dist/createOverlay.svelte.js +68 -0
- package/dist/createPagination.d.ts +74 -0
- package/dist/createPagination.js +71 -0
- package/dist/createPopoverSelect.svelte.js +6 -12
- package/dist/createStepper.d.ts +44 -0
- package/dist/createStepper.js +26 -0
- package/dist/createTooltip.svelte.d.ts +32 -0
- package/dist/createTooltip.svelte.js +61 -0
- package/dist/datetime/timezone.d.ts +36 -0
- package/dist/datetime/timezone.js +110 -0
- package/dist/dock-context.d.ts +52 -0
- package/dist/dock-context.js +1 -0
- package/dist/dock-manager-model.d.ts +136 -0
- package/dist/dock-manager-model.js +514 -0
- package/dist/dock-model.d.ts +105 -0
- package/dist/dock-model.js +288 -0
- package/dist/dock-popout.d.ts +30 -0
- package/dist/dock-popout.js +81 -0
- package/dist/editor-contract.d.ts +2 -0
- package/dist/filter-operators.d.ts +6 -0
- package/dist/filter-operators.js +35 -2
- package/dist/filtering/excel-filters.d.ts +18 -1
- package/dist/filtering/excel-filters.js +56 -0
- package/dist/form-field.d.ts +73 -0
- package/dist/form-field.js +15 -0
- package/dist/index.d.ts +25 -5
- package/dist/index.js +40 -4
- package/dist/list-nav.d.ts +18 -0
- package/dist/list-nav.js +30 -0
- package/dist/list-option.d.ts +2 -0
- package/dist/menu-item.d.ts +20 -0
- package/dist/menu-item.js +1 -0
- package/dist/menus.d.ts +5 -0
- package/dist/menus.js +68 -16
- package/dist/panel-resize.d.ts +25 -0
- package/dist/panel-resize.js +40 -0
- package/dist/popover.d.ts +29 -3
- package/dist/popover.js +22 -6
- package/dist/recurrence.d.ts +33 -7
- package/dist/recurrence.js +151 -13
- package/dist/row-drag.d.ts +8 -0
- package/dist/row-drag.js +11 -0
- package/dist/scheduler-ical.d.ts +30 -0
- package/dist/scheduler-ical.js +180 -0
- package/dist/scheduler-model.d.ts +269 -0
- package/dist/scheduler-model.js +602 -0
- package/dist/scheduler-view.svelte.d.ts +22 -0
- package/dist/scheduler-view.svelte.js +13 -0
- package/dist/spreadsheet.js +20 -12
- package/dist/ui-app.types.d.ts +3 -0
- package/package.json +5 -1
- package/src/DockNodeView.svelte +306 -0
- package/src/DockPopoutHost.svelte +17 -0
- package/src/GridMenus.svelte +83 -3
- package/src/SvAutoComplete.svelte +5 -3
- package/src/SvCarousel.svelte +20 -42
- package/src/SvCarousel.test.ts +68 -0
- package/src/SvColorInput.svelte +4 -3
- package/src/SvComboBox.svelte +7 -3
- package/src/SvCommand.svelte +28 -85
- package/src/SvCommand.test.ts +78 -0
- package/src/SvCountryInput.svelte +1 -1
- package/src/SvDateRangeInput.svelte +1 -1
- package/src/SvDateTimePicker.svelte +9 -3
- package/src/SvDockLayout.svelte +244 -0
- package/src/SvDockManager.svelte +922 -0
- package/src/SvDrawer.svelte +69 -47
- package/src/SvDropDownList.svelte +85 -13
- package/src/SvField.svelte +21 -4
- package/src/SvForm.svelte +201 -91
- package/src/SvForm.test.ts +299 -0
- package/src/SvGrid.controller.svelte.ts +152 -28
- package/src/SvGrid.css +193 -5
- package/src/SvGrid.svelte +357 -12
- package/src/SvGrid.types.ts +463 -1
- package/src/SvGridDropdown.svelte +8 -1
- package/src/SvGridSelect.svelte +1 -0
- package/src/SvListBox.svelte +36 -14
- package/src/SvMaskedInput.svelte +4 -3
- package/src/SvMenu.svelte +1 -1
- package/src/SvMenu.test.ts +24 -0
- package/src/SvMenuList.svelte +23 -71
- package/src/SvModal.svelte +12 -29
- package/src/SvModal.test.ts +82 -0
- package/src/SvMultiSelect.svelte +1 -0
- package/src/SvNumberInput.svelte +4 -3
- package/src/SvPagination.svelte +18 -18
- package/src/SvPasswordInput.svelte +3 -2
- package/src/SvPhoneInput.svelte +3 -2
- package/src/SvPopover.svelte +1 -1
- package/src/SvStepper.svelte +6 -9
- package/src/SvTagsInput.svelte +3 -2
- package/src/SvTooltip.svelte +12 -23
- package/src/SvTooltip.test.ts +73 -0
- package/src/SvTour.svelte +32 -4
- package/src/SvTreeSelect.svelte +1 -0
- package/src/build-api.ts +74 -51
- package/src/columns.ts +5 -0
- package/src/conditional-formatting.test.ts +104 -0
- package/src/conditional-formatting.ts +176 -19
- package/src/createCarousel.svelte.ts +104 -0
- package/src/createCommand.svelte.ts +125 -0
- package/src/createForm.svelte.ts +333 -0
- package/src/createMenu.svelte.ts +202 -0
- package/src/createOverlay.svelte.ts +101 -0
- package/src/createPagination.test.ts +65 -0
- package/src/createPagination.ts +84 -0
- package/src/createPopoverSelect.svelte.ts +5 -9
- package/src/createStepper.test.ts +62 -0
- package/src/createStepper.ts +61 -0
- package/src/createTooltip.svelte.ts +86 -0
- package/src/datetime/timezone.test.ts +69 -0
- package/src/datetime/timezone.ts +134 -0
- package/src/dock-context.ts +47 -0
- package/src/dock-manager-model.test.ts +275 -0
- package/src/dock-manager-model.ts +593 -0
- package/src/dock-model.test.ts +163 -0
- package/src/dock-model.ts +368 -0
- package/src/dock-popout.ts +94 -0
- package/src/editor-contract.ts +2 -0
- package/src/filter-operators.test.ts +59 -0
- package/src/filter-operators.ts +35 -2
- package/src/filtering/excel-filters.test.ts +86 -1
- package/src/filtering/excel-filters.ts +65 -0
- package/src/form-field.ts +87 -0
- package/src/index.ts +158 -4
- package/src/list-nav.test.ts +49 -0
- package/src/list-nav.ts +29 -0
- package/src/list-option.ts +2 -0
- package/src/menu-item.ts +21 -0
- package/src/menus.test.ts +48 -0
- package/src/menus.ts +73 -16
- package/src/panel-resize.ts +52 -0
- package/src/popover.bounds.test.ts +93 -0
- package/src/popover.ts +51 -7
- package/src/recurrence.test.ts +88 -1
- package/src/recurrence.ts +166 -15
- package/src/row-drag.ts +10 -0
- package/src/scheduler-ical.test.ts +68 -0
- package/src/scheduler-ical.ts +180 -0
- package/src/scheduler-model.test.ts +546 -0
- package/src/scheduler-model.ts +853 -0
- package/src/scheduler-view.svelte.ts +33 -0
- package/src/spreadsheet.ts +20 -12
- package/src/svgrid.effect-driven-filter.svelte.test.ts +116 -0
- package/src/ui-app.types.ts +3 -0
- package/src/virtual.test.ts +6 -4
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { pane, tabs, group, allPaneIds, type DockNode, type DockTabs } from './dock-model'
|
|
3
|
+
import {
|
|
4
|
+
floatPane,
|
|
5
|
+
dockPaneOnto,
|
|
6
|
+
dockWindowOnto,
|
|
7
|
+
reorderTab,
|
|
8
|
+
autoHideLeaf,
|
|
9
|
+
autoHidePaneToSide,
|
|
10
|
+
pinAutoHidden,
|
|
11
|
+
closePane,
|
|
12
|
+
moveWindow,
|
|
13
|
+
resizeWindow,
|
|
14
|
+
bringToFront,
|
|
15
|
+
setWindowMinimized,
|
|
16
|
+
toggleWindowMaximized,
|
|
17
|
+
closeWindow,
|
|
18
|
+
autoHideWindow,
|
|
19
|
+
toggleMaximizeLeaf,
|
|
20
|
+
findLeafById,
|
|
21
|
+
addPaneToMain,
|
|
22
|
+
locatePane,
|
|
23
|
+
surfaceOfTabs,
|
|
24
|
+
allManagerPaneIds,
|
|
25
|
+
allManagerIds,
|
|
26
|
+
dedupeManagerNodeIds,
|
|
27
|
+
setManagerActive,
|
|
28
|
+
type DockManagerState,
|
|
29
|
+
} from './dock-manager-model'
|
|
30
|
+
|
|
31
|
+
function counter() {
|
|
32
|
+
let n = 0
|
|
33
|
+
return () => `m${n++}`
|
|
34
|
+
}
|
|
35
|
+
const rect = { x: 100, y: 100, width: 320, height: 240 }
|
|
36
|
+
|
|
37
|
+
/** main = [A | B], no floats, no auto-hide. Returns the SHARED id generator so
|
|
38
|
+
* follow-up ops mint ids from the same sequence (no collisions - mirrors how
|
|
39
|
+
* SvDockManager uses a single genId). */
|
|
40
|
+
function base(): { state: DockManagerState; A: DockTabs; B: DockTabs; g: () => string } {
|
|
41
|
+
const g = counter()
|
|
42
|
+
const A = tabs(g, [pane('a', 'A')])
|
|
43
|
+
const B = tabs(g, [pane('b', 'B')])
|
|
44
|
+
return { state: { main: group(g, 'row', [A, B]) as DockNode, floating: [], autoHide: [] }, A, B, g }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe('floatPane', () => {
|
|
48
|
+
it('pops a pane into a floating window and collapses its old leaf', () => {
|
|
49
|
+
const { state, g } = base()
|
|
50
|
+
const next = floatPane(state, 'a', rect, g)
|
|
51
|
+
expect(next.floating).toHaveLength(1)
|
|
52
|
+
expect(next.floating[0]!.leaf.panes.map((p) => p.id)).toEqual(['a'])
|
|
53
|
+
// main collapsed to the bare B leaf.
|
|
54
|
+
expect(next.main?.type).toBe('tabs')
|
|
55
|
+
expect(allPaneIds(next.main!)).toEqual(['b'])
|
|
56
|
+
expect(locatePane(next, 'a')).toEqual({ kind: 'floating', windowId: next.floating[0]!.id })
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('is a no-op for a pane already alone in its float', () => {
|
|
60
|
+
const { state, g } = base()
|
|
61
|
+
const once = floatPane(state, 'a', rect, g)
|
|
62
|
+
const twice = floatPane(once, 'a', rect, g)
|
|
63
|
+
expect(twice).toBe(once)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe('dockPaneOnto - cross surface', () => {
|
|
68
|
+
it('docks a floating pane back into a main leaf as a tab', () => {
|
|
69
|
+
const { state, B, g } = base()
|
|
70
|
+
const floated = floatPane(state, 'a', rect, g)
|
|
71
|
+
const docked = dockPaneOnto(floated, 'a', B.id, 'center', g)
|
|
72
|
+
expect(docked.floating).toHaveLength(0)
|
|
73
|
+
const leaf = docked.main as DockTabs
|
|
74
|
+
expect(leaf.panes.map((p) => p.id)).toEqual(['b', 'a'])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('edge-docks within main', () => {
|
|
78
|
+
const { state, A, g } = base()
|
|
79
|
+
const floated = floatPane(state, 'a', rect, g) // main is now just B
|
|
80
|
+
// Re-dock A to the LEFT of B (A's old leaf id is gone; target B).
|
|
81
|
+
const bId = surfaceOfTabs(floated, (floated.main as DockTabs).id) === 'main' ? (floated.main as DockTabs).id : ''
|
|
82
|
+
const docked = dockPaneOnto(floated, 'a', bId, 'left', g)
|
|
83
|
+
expect(allPaneIds(docked.main!)).toEqual(['a', 'b'])
|
|
84
|
+
void A
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe('reorderTab', () => {
|
|
89
|
+
it('reorders tabs inside a leaf (main)', () => {
|
|
90
|
+
const g = counter()
|
|
91
|
+
const leaf = tabs(g, [pane('a', 'A'), pane('b', 'B'), pane('c', 'C')], 0)
|
|
92
|
+
const state: DockManagerState = { main: leaf, floating: [], autoHide: [] }
|
|
93
|
+
const next = reorderTab(state, leaf.id, 0, 2)
|
|
94
|
+
expect((next.main as DockTabs).panes.map((p) => p.id)).toEqual(['b', 'c', 'a'])
|
|
95
|
+
// active followed pane A.
|
|
96
|
+
expect((next.main as DockTabs).active).toBe(2)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('reorders tabs inside a floating window', () => {
|
|
100
|
+
const { state, g } = base()
|
|
101
|
+
let s = floatPane(state, 'a', rect, g)
|
|
102
|
+
s = dockPaneOnto(s, 'b', s.floating[0]!.leaf.id, 'center', g) // float now [a, b]
|
|
103
|
+
const wid = s.floating[0]!.leaf.id
|
|
104
|
+
const next = reorderTab(s, wid, 0, 1)
|
|
105
|
+
expect(next.floating[0]!.leaf.panes.map((p) => p.id)).toEqual(['b', 'a'])
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('auto-hide + pin', () => {
|
|
110
|
+
it('collapses a main leaf to an edge, then pins it back', () => {
|
|
111
|
+
const { state, B, g } = base()
|
|
112
|
+
const hidden = autoHideLeaf(state, B.id, 'right')
|
|
113
|
+
expect(hidden.autoHide).toHaveLength(1)
|
|
114
|
+
expect(hidden.autoHide[0]!.side).toBe('right')
|
|
115
|
+
expect(allPaneIds(hidden.main!)).toEqual(['a']) // only A left tiled
|
|
116
|
+
expect(allManagerPaneIds(hidden)).toEqual(['a', 'b']) // B still exists, hidden
|
|
117
|
+
|
|
118
|
+
const pinned = pinAutoHidden(hidden, hidden.autoHide[0]!.id, g)
|
|
119
|
+
expect(pinned.autoHide).toHaveLength(0)
|
|
120
|
+
expect(pinned.main?.type).toBe('group')
|
|
121
|
+
expect(allPaneIds(pinned.main!)).toEqual(['a', 'b']) // B re-docked on the right
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
describe('auto-hide to any of the 4 sides', () => {
|
|
126
|
+
it.each(['left', 'right', 'top', 'bottom'] as const)('collapses + pins back on the %s edge', (side) => {
|
|
127
|
+
const { state, B, g } = base()
|
|
128
|
+
const hidden = autoHideLeaf(state, B.id, side)
|
|
129
|
+
expect(hidden.autoHide[0]!.side).toBe(side)
|
|
130
|
+
const pinned = pinAutoHidden(hidden, hidden.autoHide[0]!.id, g)
|
|
131
|
+
const root = pinned.main as Extract<DockNode, { type: 'group' }>
|
|
132
|
+
expect(root.type).toBe('group')
|
|
133
|
+
// Row for left/right, column for top/bottom.
|
|
134
|
+
expect(root.direction).toBe(side === 'left' || side === 'right' ? 'row' : 'column')
|
|
135
|
+
expect(allPaneIds(pinned.main!).sort()).toEqual(['a', 'b'])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('pins back with the requested size fraction (not 50/50)', () => {
|
|
139
|
+
const { state, B, g } = base()
|
|
140
|
+
const hidden = autoHideLeaf(state, B.id, 'right')
|
|
141
|
+
const pinned = pinAutoHidden(hidden, hidden.autoHide[0]!.id, g, 0.2)
|
|
142
|
+
const root = pinned.main as Extract<DockNode, { type: 'group' }>
|
|
143
|
+
// Right side => [content, pinnedLeaf]; the pinned leaf takes ~0.2.
|
|
144
|
+
expect(root.sizes[1]).toBeCloseTo(0.2, 1)
|
|
145
|
+
expect(root.sizes[0]).toBeCloseTo(0.8, 1)
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('autoHidePaneToSide (drag a tab to an edge)', () => {
|
|
150
|
+
it('pulls a single pane out to an edge as its own entry', () => {
|
|
151
|
+
const g = counter()
|
|
152
|
+
const leaf = tabs(g, [pane('a', 'A'), pane('b', 'B')])
|
|
153
|
+
const s: DockManagerState = { main: leaf, floating: [], autoHide: [] }
|
|
154
|
+
const next = autoHidePaneToSide(s, 'a', 'bottom', g)
|
|
155
|
+
expect(next.autoHide).toHaveLength(1)
|
|
156
|
+
expect(next.autoHide[0]!.side).toBe('bottom')
|
|
157
|
+
expect(next.autoHide[0]!.leaf.panes.map((p) => p.id)).toEqual(['a'])
|
|
158
|
+
// 'b' stays in the tiled leaf.
|
|
159
|
+
expect(allPaneIds(next.main!)).toEqual(['b'])
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
describe('dockWindowOnto', () => {
|
|
164
|
+
it('docks a whole window edge-wise into main', () => {
|
|
165
|
+
const { state, A, g } = base()
|
|
166
|
+
const floated = floatPane(state, 'b', rect, g) // main = A, float = [B]
|
|
167
|
+
const wid = floated.floating[0]!.id
|
|
168
|
+
const next = dockWindowOnto(floated, wid, A.id, 'right', g)
|
|
169
|
+
expect(next.floating).toHaveLength(0)
|
|
170
|
+
expect(allPaneIds(next.main!)).toEqual(['a', 'b'])
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
describe('maximize a tiled leaf + addPaneToMain', () => {
|
|
175
|
+
it('toggles maximizedLeaf and finds a leaf by id', () => {
|
|
176
|
+
const { state, A } = base()
|
|
177
|
+
expect(findLeafById(state, A.id)?.id).toBe(A.id)
|
|
178
|
+
const on = toggleMaximizeLeaf(state, A.id)
|
|
179
|
+
expect(on.maximizedLeaf).toBe(A.id)
|
|
180
|
+
expect(toggleMaximizeLeaf(on, A.id).maximizedLeaf).toBeNull()
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('adds a pane into the first main leaf (or as main when empty)', () => {
|
|
184
|
+
const { state } = base()
|
|
185
|
+
const next = addPaneToMain(state, pane('z', 'Z'), counter())
|
|
186
|
+
expect(allManagerPaneIds(next)).toContain('z')
|
|
187
|
+
const empty: DockManagerState = { main: null, floating: [], autoHide: [] }
|
|
188
|
+
const filled = addPaneToMain(empty, pane('z', 'Z'), counter())
|
|
189
|
+
expect(filled.main?.type).toBe('tabs')
|
|
190
|
+
expect(allManagerPaneIds(filled)).toEqual(['z'])
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
describe('window controls', () => {
|
|
195
|
+
it('minimizes, maximizes (toggle), closes, and auto-hides a window', () => {
|
|
196
|
+
const { state, g } = base()
|
|
197
|
+
let s = floatPane(state, 'a', rect, g)
|
|
198
|
+
const wid = s.floating[0]!.id
|
|
199
|
+
s = setWindowMinimized(s, wid, true)
|
|
200
|
+
expect(s.floating[0]!.minimized).toBe(true)
|
|
201
|
+
s = toggleWindowMaximized(s, wid)
|
|
202
|
+
expect(s.floating[0]!.maximized).toBe(true)
|
|
203
|
+
expect(s.floating[0]!.minimized).toBe(false) // max clears min
|
|
204
|
+
s = toggleWindowMaximized(s, wid)
|
|
205
|
+
expect(s.floating[0]!.maximized).toBe(false)
|
|
206
|
+
// auto-hide the window to the left edge
|
|
207
|
+
s = autoHideWindow(s, wid, 'left', g)
|
|
208
|
+
expect(s.floating).toHaveLength(0)
|
|
209
|
+
expect(s.autoHide[0]!.side).toBe('left')
|
|
210
|
+
expect(s.autoHide[0]!.leaf.panes.map((p) => p.id)).toEqual(['a'])
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('closeWindow drops the window and its panes', () => {
|
|
214
|
+
const { state, g } = base()
|
|
215
|
+
const s = floatPane(state, 'a', rect, g)
|
|
216
|
+
const next = closeWindow(s, s.floating[0]!.id)
|
|
217
|
+
expect(next.floating).toHaveLength(0)
|
|
218
|
+
expect(allManagerPaneIds(next)).toEqual(['b'])
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
describe('window ops + close', () => {
|
|
223
|
+
it('moves, resizes, and restacks windows; closes a pane anywhere', () => {
|
|
224
|
+
const { state, g } = base()
|
|
225
|
+
let s = floatPane(state, 'a', rect, g)
|
|
226
|
+
const wid = s.floating[0]!.id
|
|
227
|
+
s = moveWindow(s, wid, 40, 60)
|
|
228
|
+
s = resizeWindow(s, wid, 500, 400)
|
|
229
|
+
expect(s.floating[0]).toMatchObject({ x: 40, y: 60, width: 500, height: 400 })
|
|
230
|
+
const z0 = s.floating[0]!.z
|
|
231
|
+
s = bringToFront(s, wid)
|
|
232
|
+
expect(s.floating[0]!.z).toBeGreaterThan(z0)
|
|
233
|
+
s = closePane(s, 'a')
|
|
234
|
+
expect(s.floating).toHaveLength(0)
|
|
235
|
+
expect(allManagerPaneIds(s)).toEqual(['b'])
|
|
236
|
+
})
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
describe('setManagerActive', () => {
|
|
240
|
+
it('sets active in a main leaf and in a float', () => {
|
|
241
|
+
const g = counter()
|
|
242
|
+
const leaf = tabs(g, [pane('a', 'A'), pane('b', 'B')], 0)
|
|
243
|
+
const s: DockManagerState = { main: leaf, floating: [], autoHide: [] }
|
|
244
|
+
expect((setManagerActive(s, leaf.id, 1).main as DockTabs).active).toBe(1)
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
describe('dedupeManagerNodeIds', () => {
|
|
249
|
+
it('reassigns duplicate node ids so keyed sibling lists never collide', () => {
|
|
250
|
+
// A restored workspace where two sibling leaves share a generated id (the id
|
|
251
|
+
// counter had reset across reloads) - the shape that threw each_key_duplicate.
|
|
252
|
+
const dup: DockManagerState = {
|
|
253
|
+
main: {
|
|
254
|
+
type: 'group', id: 'dm-1000000', direction: 'row', sizes: [0.5, 0.5],
|
|
255
|
+
children: [
|
|
256
|
+
{ type: 'tabs', id: 'dm-1000000', panes: [pane('rail', 'Pages')], active: 0 },
|
|
257
|
+
{ type: 'tabs', id: 'dm-1000000', panes: [pane('main', 'Canvas')], active: 0 },
|
|
258
|
+
],
|
|
259
|
+
} as DockNode,
|
|
260
|
+
floating: [], autoHide: [],
|
|
261
|
+
}
|
|
262
|
+
const fixed = dedupeManagerNodeIds(dup)
|
|
263
|
+
const ids = allManagerIds(fixed)
|
|
264
|
+
// Every node id is now unique...
|
|
265
|
+
const nodeIds = ids.filter((i) => i.startsWith('dm-'))
|
|
266
|
+
expect(new Set(nodeIds).size).toBe(nodeIds.length)
|
|
267
|
+
// ...while pane ids (which key content) are preserved.
|
|
268
|
+
expect(allManagerPaneIds(fixed).sort()).toEqual(['main', 'rail'])
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
it('is value-equal on an already-unique workspace', () => {
|
|
272
|
+
const { state } = base()
|
|
273
|
+
expect(dedupeManagerNodeIds(state)).toBe(state)
|
|
274
|
+
})
|
|
275
|
+
})
|