@adecore/ui 0.31.12 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/AccentSwatches.js +290 -13
  2. package/dist/Banner.js +90 -9
  3. package/dist/Button.js +114 -22
  4. package/dist/ButtonGroup.js +62 -8
  5. package/dist/Checkbox.js +73 -4
  6. package/dist/ChoiceCards.js +205 -11
  7. package/dist/CloseButton.js +87 -7
  8. package/dist/ColorSwatch.js +132 -15
  9. package/dist/ColorWheelPicker.js +305 -71
  10. package/dist/ColumnResizeHandle.js +43 -8
  11. package/dist/DisabledReason.js +27 -8
  12. package/dist/DockShell.js +144 -37
  13. package/dist/EmptyState.js +95 -6
  14. package/dist/ErrorBoundary.js +254 -31
  15. package/dist/Field.js +349 -31
  16. package/dist/FileIcon.js +67 -6
  17. package/dist/Icon.js +38 -6
  18. package/dist/IconButton.js +176 -20
  19. package/dist/IconPicker.js +344 -73
  20. package/dist/Input.js +233 -14
  21. package/dist/Kbd.js +150 -10
  22. package/dist/LazyBoundary.js +14 -5
  23. package/dist/ListRow.js +75 -15
  24. package/dist/Meter.js +108 -5
  25. package/dist/MiddleTruncate.js +126 -45
  26. package/dist/PanelEmpty.js +64 -5
  27. package/dist/PanelHeader.js +95 -13
  28. package/dist/Pill.js +114 -19
  29. package/dist/ProjectSwitcher.js +225 -12
  30. package/dist/PromptDialog.js +352 -37
  31. package/dist/SectionLabel.js +62 -8
  32. package/dist/SegmentBar.js +197 -36
  33. package/dist/Segmented.js +130 -23
  34. package/dist/Select.js +310 -19
  35. package/dist/SelectSearch.js +344 -29
  36. package/dist/Separator.js +35 -4
  37. package/dist/ShortcutHints.js +146 -76
  38. package/dist/Skeleton.js +31 -4
  39. package/dist/Slider.js +172 -10
  40. package/dist/SlidingColumn.js +194 -34
  41. package/dist/Spinner.js +100 -3
  42. package/dist/Stepper.js +232 -11
  43. package/dist/Surface.js +62 -8
  44. package/dist/Switch.js +60 -6
  45. package/dist/TextMenu.js +212 -17
  46. package/dist/Tile.js +149 -5
  47. package/dist/Toasts.js +391 -33
  48. package/dist/Tooltip.js +153 -16
  49. package/dist/UIProvider.js +62 -15
  50. package/dist/Waveform.js +362 -93
  51. package/dist/Wipe.js +259 -34
  52. package/dist/ZoomControls.js +356 -14
  53. package/dist/class-name.js +1 -1
  54. package/dist/clipboard.js +15 -17
  55. package/dist/context-menu/index.parts.js +1 -1
  56. package/dist/dialog/index.parts.js +1 -1
  57. package/dist/dialog/parts.js +378 -29
  58. package/dist/dialog-layer.js +51 -18
  59. package/dist/error-boundary.js +19 -19
  60. package/dist/error-message.js +1 -1
  61. package/dist/field-context.js +7 -5
  62. package/dist/file-icon.js +23 -21
  63. package/dist/file-tree/helpers.js +133 -119
  64. package/dist/file-tree/index.parts.js +3 -3
  65. package/dist/file-tree/parts.js +418 -127
  66. package/dist/file-tree/style.js +1 -1
  67. package/dist/file-tree/use-file-tree-shift.js +43 -30
  68. package/dist/file-tree/use-file-tree.js +60 -18
  69. package/dist/file-tree/use-slots.js +220 -192
  70. package/dist/floating.js +2 -2
  71. package/dist/format/datetime.js +88 -38
  72. package/dist/format/duration.js +59 -53
  73. package/dist/format/index.js +1 -1
  74. package/dist/format/locale.js +76 -56
  75. package/dist/format/number.js +77 -61
  76. package/dist/format/regions.js +4 -2
  77. package/dist/format/time-zone.js +1 -1
  78. package/dist/icon-button-size.js +12 -2
  79. package/dist/icon-picker.js +70 -61
  80. package/dist/index.js +57 -57
  81. package/dist/key-value-list/index.parts.js +1 -1
  82. package/dist/key-value-list/parts.js +256 -22
  83. package/dist/lazy-landings.js +10 -10
  84. package/dist/lazy.js +84 -71
  85. package/dist/locales/en.js +80 -80
  86. package/dist/locales/nl.js +80 -80
  87. package/dist/locales.js +10 -7
  88. package/dist/menu/index.parts.js +1 -1
  89. package/dist/menu/parts.js +882 -44
  90. package/dist/merge-refs.js +8 -9
  91. package/dist/middle-truncate.js +24 -25
  92. package/dist/modality.js +27 -19
  93. package/dist/placement.js +11 -20
  94. package/dist/platform.js +6 -6
  95. package/dist/popover/index.parts.js +1 -1
  96. package/dist/popover/parts.js +173 -11
  97. package/dist/popup-layer.js +38 -17
  98. package/dist/prefetch.js +78 -79
  99. package/dist/preview-card/index.parts.js +1 -1
  100. package/dist/project-switcher-row.js +153 -12
  101. package/dist/select-row.js +69 -5
  102. package/dist/select-shared.js +6 -6
  103. package/dist/selection.js +16 -16
  104. package/dist/seti-icons.js +413 -413
  105. package/dist/settings/ConfirmDialog.js +55 -8
  106. package/dist/settings/DetailHeader.js +72 -4
  107. package/dist/settings/MasterDetail.js +119 -7
  108. package/dist/settings/SettingsDialog.js +820 -80
  109. package/dist/settings/SettingsRow.js +205 -18
  110. package/dist/settings/SettingsSection.js +96 -6
  111. package/dist/settings/index.js +7 -7
  112. package/dist/settings/target.js +7 -2
  113. package/dist/shortcut-hints.js +73 -55
  114. package/dist/shortcut.js +140 -104
  115. package/dist/step-places.js +1 -1
  116. package/dist/tabs/index.parts.js +1 -1
  117. package/dist/tabs/overflow.js +18 -18
  118. package/dist/tabs/parts.js +780 -166
  119. package/dist/testing/dedupe.js +82 -75
  120. package/dist/testing/fake-source.js +12 -12
  121. package/dist/testing/index.js +1 -1
  122. package/dist/toast-store.js +65 -46
  123. package/dist/tree/index.parts.js +1 -1
  124. package/dist/tree/parts.js +721 -94
  125. package/dist/tree/shift.js +28 -22
  126. package/dist/tree/style.js +2 -2
  127. package/dist/tree/use-tree-shift.js +178 -117
  128. package/dist/useAsyncAction.js +23 -19
  129. package/dist/useColumnResize.js +36 -34
  130. package/dist/useContentSize.js +62 -18
  131. package/dist/useMeasuredWidth.js +14 -3
  132. package/dist/useNow.js +73 -30
  133. package/dist/wipe-split.js +14 -14
  134. package/dist/workspace/DropPreview.js +60 -7
  135. package/dist/workspace/SplitView.js +1025 -441
  136. package/dist/workspace/TabStrip.js +810 -191
  137. package/dist/workspace/Workspace.js +276 -26
  138. package/dist/workspace/context.js +8 -3
  139. package/dist/workspace/geometry.js +173 -150
  140. package/dist/workspace/model.js +313 -250
  141. package/dist/workspace/preview.js +61 -61
  142. package/dist/zoom.js +2 -2
  143. package/package.json +1 -1
  144. package/src/ErrorBoundary.tsx +1 -1
  145. package/src/Field.tsx +4 -3
  146. package/src/IconPicker.tsx +3 -3
  147. package/src/LazyBoundary.tsx +2 -0
  148. package/src/MiddleTruncate.tsx +2 -2
  149. package/src/SegmentBar.tsx +2 -2
  150. package/src/Toasts.tsx +3 -1
  151. package/src/Tooltip.tsx +7 -10
  152. package/src/Waveform.tsx +3 -3
  153. package/src/file-tree/parts.tsx +6 -9
  154. package/src/file-tree/use-file-tree-shift.tsx +6 -9
  155. package/src/lazy.tsx +4 -0
  156. package/src/locales/en.ts +4 -4
  157. package/src/locales/nl.ts +5 -5
  158. package/src/settings/SettingsDialog.tsx +1 -1
  159. package/src/tree/parts.tsx +5 -8
  160. package/src/useContentSize.ts +3 -3
  161. package/src/workspace/SplitView.tsx +2 -2
  162. package/src/workspace/TabStrip.tsx +2 -3
  163. package/src/workspace/Workspace.tsx +2 -5
@@ -1,292 +1,355 @@
1
1
  export function createSplitLayout(views = [], paneId = 'main') {
2
- const unique = [...new Set(views)];
3
- return { root: { type: 'pane', id: paneId, views: unique, active: unique[0] ?? null }, focused: paneId, maximized: null };
2
+ const unique = [...new Set(views)];
3
+ return {
4
+ root: {
5
+ type: 'pane',
6
+ id: paneId,
7
+ views: unique,
8
+ active: unique[0] ?? null
9
+ },
10
+ focused: paneId,
11
+ maximized: null
12
+ };
4
13
  }
5
14
  export function splitPanes(node) {
6
- return node.type === 'pane' ? [node] : node.children.flatMap(splitPanes);
15
+ return node.type === 'pane' ? [node] : node.children.flatMap(splitPanes);
7
16
  }
8
17
  export function findSplitNode(node, id) {
9
- if (node.id === id) {
10
- return node;
11
- }
12
- return node.type === 'split' ? node.children.map((child) => findSplitNode(child, id)).find(Boolean) : undefined;
18
+ if (node.id === id) {
19
+ return node;
20
+ }
21
+ return node.type === 'split' ? node.children.map(child => findSplitNode(child, id)).find(Boolean) : undefined;
13
22
  }
14
23
  function shares(values, length) {
15
- const safe = Array.from({ length }, (_, i) => (Number.isFinite(values[i]) && values[i] > 0 ? values[i] : 1));
16
- const largest = Math.max(...safe, 1);
17
- const total = safe.reduce((sum, value) => sum + value / largest, 0);
18
- return safe.map((value) => value / largest / total);
24
+ const safe = Array.from({
25
+ length
26
+ }, (_, i) => Number.isFinite(values[i]) && values[i] > 0 ? values[i] : 1);
27
+ const largest = Math.max(...safe, 1);
28
+ const total = safe.reduce((sum, value) => sum + value / largest, 0);
29
+ return safe.map(value => value / largest / total);
19
30
  }
20
31
  function flattenSplits(node) {
21
- if (node.type === 'pane') {
22
- return node;
23
- }
24
- const children = [];
25
- const sizes = [];
26
- node.children.forEach((child, i) => {
27
- const next = flattenSplits(child);
28
- // A divider balances neighboring tracks, not a pane against a hidden group on the same axis.
29
- if (next.type === 'split' && next.axis === node.axis) {
30
- children.push(...next.children);
31
- sizes.push(...next.sizes.map((size) => size * node.sizes[i]));
32
- }
33
- else {
34
- children.push(next);
35
- sizes.push(node.sizes[i]);
36
- }
37
- });
38
- if (children.length === node.children.length && children.every((child, i) => child === node.children[i])) {
39
- return node;
32
+ if (node.type === 'pane') {
33
+ return node;
34
+ }
35
+ const children = [];
36
+ const sizes = [];
37
+ node.children.forEach((child, i) => {
38
+ const next = flattenSplits(child);
39
+ // A divider balances neighboring tracks, not a pane against a hidden group on the same axis.
40
+ if (next.type === 'split' && next.axis === node.axis) {
41
+ children.push(...next.children);
42
+ sizes.push(...next.sizes.map(size => size * node.sizes[i]));
43
+ } else {
44
+ children.push(next);
45
+ sizes.push(node.sizes[i]);
40
46
  }
41
- return { ...node, children, sizes: shares(sizes, children.length) };
47
+ });
48
+ if (children.length === node.children.length && children.every((child, i) => child === node.children[i])) {
49
+ return node;
50
+ }
51
+ return {
52
+ ...node,
53
+ children,
54
+ sizes: shares(sizes, children.length)
55
+ };
42
56
  }
43
57
  function replace(node, id, transform) {
44
- if (node.id === id) {
45
- return transform(node);
46
- }
47
- if (node.type === 'pane') {
48
- return node;
49
- }
50
- const children = [];
51
- const sizes = [];
52
- node.children.forEach((child, i) => {
53
- const next = replace(child, id, transform);
54
- if (next) {
55
- children.push(next);
56
- sizes.push(node.sizes[i]);
57
- }
58
- });
59
- if (children.every((child, i) => child === node.children[i]) && children.length === node.children.length) {
60
- return node;
61
- }
62
- if (children.length < 2) {
63
- return children[0] ?? null;
58
+ if (node.id === id) {
59
+ return transform(node);
60
+ }
61
+ if (node.type === 'pane') {
62
+ return node;
63
+ }
64
+ const children = [];
65
+ const sizes = [];
66
+ node.children.forEach((child, i) => {
67
+ const next = replace(child, id, transform);
68
+ if (next) {
69
+ children.push(next);
70
+ sizes.push(node.sizes[i]);
64
71
  }
65
- return { ...node, children, sizes: shares(sizes, children.length) };
72
+ });
73
+ if (children.every((child, i) => child === node.children[i]) && children.length === node.children.length) {
74
+ return node;
75
+ }
76
+ if (children.length < 2) {
77
+ return children[0] ?? null;
78
+ }
79
+ return {
80
+ ...node,
81
+ children,
82
+ sizes: shares(sizes, children.length)
83
+ };
66
84
  }
67
85
  function finish(layout, root, focus = layout.focused) {
68
- const next = flattenSplits(root ?? createSplitLayout([], layout.focused).root);
69
- const panes = splitPanes(next);
70
- return {
71
- root: next,
72
- focused: panes.some((pane) => pane.id === focus) ? focus : panes[0].id,
73
- maximized: panes.some((pane) => pane.id === layout.maximized) ? layout.maximized : null
74
- };
86
+ const next = flattenSplits(root ?? createSplitLayout([], layout.focused).root);
87
+ const panes = splitPanes(next);
88
+ return {
89
+ root: next,
90
+ focused: panes.some(pane => pane.id === focus) ? focus : panes[0].id,
91
+ maximized: panes.some(pane => pane.id === layout.maximized) ? layout.maximized : null
92
+ };
75
93
  }
76
94
  function without(pane, views) {
77
- const remaining = pane.views.filter((view) => !views.includes(view));
78
- const position = Math.max(0, pane.views.indexOf(pane.active ?? ''));
79
- return {
80
- ...pane,
81
- views: remaining,
82
- active: remaining.includes(pane.active ?? '') ? pane.active : (remaining[Math.min(position, remaining.length - 1)] ?? null)
83
- };
95
+ const remaining = pane.views.filter(view => !views.includes(view));
96
+ const position = Math.max(0, pane.views.indexOf(pane.active ?? ''));
97
+ return {
98
+ ...pane,
99
+ views: remaining,
100
+ active: remaining.includes(pane.active ?? '') ? pane.active : remaining[Math.min(position, remaining.length - 1)] ?? null
101
+ };
84
102
  }
85
103
  function beside(target, pane, side, id) {
86
- return {
87
- type: 'split',
88
- id,
89
- axis: side === 'left' || side === 'right' ? 'horizontal' : 'vertical',
90
- children: side === 'left' || side === 'top' ? [pane, target] : [target, pane],
91
- sizes: [0.5, 0.5]
92
- };
104
+ return {
105
+ type: 'split',
106
+ id,
107
+ axis: side === 'left' || side === 'right' ? 'horizontal' : 'vertical',
108
+ children: side === 'left' || side === 'top' ? [pane, target] : [target, pane],
109
+ sizes: [0.5, 0.5]
110
+ };
93
111
  }
94
112
  function equalizeAxis(root, axis, length, gap) {
95
- const tracks = new Map();
96
- const measure = (node) => {
97
- const children = node.type === 'split' ? node.children.map(measure) : [];
98
- const count = node.type === 'pane' ? 1 : node.axis === axis ? children.reduce((sum, value) => sum + value, 0) : Math.max(...children);
99
- tracks.set(node.id, count);
100
- return count;
101
- };
102
- measure(root);
103
- const distribute = (node, extent) => {
104
- if (node.type === 'pane') {
105
- return node;
106
- }
107
- if (node.axis !== axis) {
108
- return { ...node, children: node.children.map((child) => distribute(child, extent)) };
109
- }
110
- const count = tracks.get(node.id);
111
- const spacing = Math.min(gap, extent / (count - 1));
112
- const unit = Math.max(0, extent - spacing * (count - 1)) / count;
113
- // Spanning panels also occupy the gaps between their tracks.
114
- const lengths = node.children.map((child) => {
115
- const span = tracks.get(child.id);
116
- return Math.max(Number.EPSILON, unit * span + spacing * (span - 1));
117
- });
118
- return { ...node, sizes: shares(lengths, lengths.length), children: node.children.map((child, i) => distribute(child, lengths[i])) };
119
- };
120
- return distribute(root, length);
121
- }
122
- function addPane(layout, panes, pane, command) {
123
- if (!pane || findSplitNode(layout.root, command.newPane.id) || findSplitNode(layout.root, command.splitId) || command.newPane.id === command.splitId) {
124
- return layout;
113
+ const tracks = new Map();
114
+ const measure = node => {
115
+ const children = node.type === 'split' ? node.children.map(measure) : [];
116
+ const count = node.type === 'pane' ? 1 : node.axis === axis ? children.reduce((sum, value) => sum + value, 0) : Math.max(...children);
117
+ tracks.set(node.id, count);
118
+ return count;
119
+ };
120
+ measure(root);
121
+ const distribute = (node, extent) => {
122
+ if (node.type === 'pane') {
123
+ return node;
125
124
  }
126
- const allViews = new Set(panes.flatMap((item) => item.views));
127
- if (command.newPane.views.some((view) => allViews.has(view)) || new Set(command.newPane.views).size !== command.newPane.views.length) {
128
- return layout;
125
+ if (node.axis !== axis) {
126
+ return {
127
+ ...node,
128
+ children: node.children.map(child => distribute(child, extent))
129
+ };
129
130
  }
130
- const added = {
131
- ...command.newPane,
132
- active: command.newPane.views.includes(command.newPane.active ?? '') ? command.newPane.active : (command.newPane.views[0] ?? null)
131
+ const count = tracks.get(node.id);
132
+ const spacing = Math.min(gap, extent / (count - 1));
133
+ const unit = Math.max(0, extent - spacing * (count - 1)) / count;
134
+ // Spanning panels also occupy the gaps between their tracks.
135
+ const lengths = node.children.map(child => {
136
+ const span = tracks.get(child.id);
137
+ return Math.max(Number.EPSILON, unit * span + spacing * (span - 1));
138
+ });
139
+ return {
140
+ ...node,
141
+ sizes: shares(lengths, lengths.length),
142
+ children: node.children.map((child, i) => distribute(child, lengths[i]))
133
143
  };
134
- return finish({ ...layout, maximized: null }, replace(layout.root, pane.id, () => beside(pane, added, command.side, command.splitId)), added.id);
144
+ };
145
+ return distribute(root, length);
146
+ }
147
+ function addPane(layout, panes, pane, command) {
148
+ if (!pane || findSplitNode(layout.root, command.newPane.id) || findSplitNode(layout.root, command.splitId) || command.newPane.id === command.splitId) {
149
+ return layout;
150
+ }
151
+ const allViews = new Set(panes.flatMap(item => item.views));
152
+ if (command.newPane.views.some(view => allViews.has(view)) || new Set(command.newPane.views).size !== command.newPane.views.length) {
153
+ return layout;
154
+ }
155
+ const added = {
156
+ ...command.newPane,
157
+ active: command.newPane.views.includes(command.newPane.active ?? '') ? command.newPane.active : command.newPane.views[0] ?? null
158
+ };
159
+ return finish({
160
+ ...layout,
161
+ maximized: null
162
+ }, replace(layout.root, pane.id, () => beside(pane, added, command.side, command.splitId)), added.id);
135
163
  }
136
164
  function swapPanes(layout, panes, command) {
137
- const source = panes.find((item) => item.id === command.sourceId);
138
- const target = panes.find((item) => item.id === command.targetId);
139
- if (!source || !target || source === target || source.views.length === 0 || (command.viewId !== undefined && !source.views.includes(command.viewId))) {
140
- return layout;
141
- }
142
- if (command.viewId === undefined || source.views.length === 1) {
143
- const exchange = (node) => {
144
- if (node.id === source.id) {
145
- return target;
146
- }
147
- if (node.id === target.id) {
148
- return source;
149
- }
150
- return node.type === 'pane' ? node : { ...node, children: node.children.map(exchange) };
151
- };
152
- return finish({ ...layout, maximized: null }, exchange(layout.root), source.id);
153
- }
154
- const moving = command.viewId;
155
- const displaced = target.active;
156
- const sourceNext = displaced === null
157
- ? without(source, [moving])
158
- : {
159
- ...source,
160
- views: source.views.map((view) => (view === moving ? displaced : view)),
161
- active: source.active === moving ? displaced : source.active
162
- };
163
- const targetNext = {
164
- ...target,
165
- views: displaced === null ? [moving] : target.views.map((view) => (view === displaced ? moving : view)),
166
- active: moving
165
+ const source = panes.find(item => item.id === command.sourceId);
166
+ const target = panes.find(item => item.id === command.targetId);
167
+ if (!source || !target || source === target || source.views.length === 0 || command.viewId !== undefined && !source.views.includes(command.viewId)) {
168
+ return layout;
169
+ }
170
+ if (command.viewId === undefined || source.views.length === 1) {
171
+ const exchange = node => {
172
+ if (node.id === source.id) {
173
+ return target;
174
+ }
175
+ if (node.id === target.id) {
176
+ return source;
177
+ }
178
+ return node.type === 'pane' ? node : {
179
+ ...node,
180
+ children: node.children.map(exchange)
181
+ };
167
182
  };
168
- const root = replace(layout.root, source.id, () => sourceNext);
169
- return finish({ ...layout, maximized: null }, replace(root, target.id, () => targetNext), target.id);
183
+ return finish({
184
+ ...layout,
185
+ maximized: null
186
+ }, exchange(layout.root), source.id);
187
+ }
188
+ const moving = command.viewId;
189
+ const displaced = target.active;
190
+ const sourceNext = displaced === null ? without(source, [moving]) : {
191
+ ...source,
192
+ views: source.views.map(view => view === moving ? displaced : view),
193
+ active: source.active === moving ? displaced : source.active
194
+ };
195
+ const targetNext = {
196
+ ...target,
197
+ views: displaced === null ? [moving] : target.views.map(view => view === displaced ? moving : view),
198
+ active: moving
199
+ };
200
+ const root = replace(layout.root, source.id, () => sourceNext);
201
+ return finish({
202
+ ...layout,
203
+ maximized: null
204
+ }, replace(root, target.id, () => targetNext), target.id);
170
205
  }
171
206
  function moveViews(layout, panes, command) {
172
- const source = panes.find((item) => item.id === command.sourceId);
173
- const target = panes.find((item) => item.id === command.targetId);
174
- if (!source || !target || (command.viewId !== undefined && !source.views.includes(command.viewId))) {
175
- return layout;
176
- }
177
- const moving = command.viewId === undefined ? source.views : [command.viewId];
178
- if (!moving.length || (source === target && (command.viewId === undefined || (command.side !== undefined && source.views.length === 1)))) {
179
- return layout;
207
+ const source = panes.find(item => item.id === command.sourceId);
208
+ const target = panes.find(item => item.id === command.targetId);
209
+ if (!source || !target || command.viewId !== undefined && !source.views.includes(command.viewId)) {
210
+ return layout;
211
+ }
212
+ const moving = command.viewId === undefined ? source.views : [command.viewId];
213
+ if (!moving.length || source === target && (command.viewId === undefined || command.side !== undefined && source.views.length === 1)) {
214
+ return layout;
215
+ }
216
+ let added;
217
+ if (command.side) {
218
+ const id = command.viewId === undefined ? source.id : command.newPaneId;
219
+ if (!id || !command.splitId || id === command.splitId || findSplitNode(layout.root, command.splitId) || findSplitNode(layout.root, id) && !(id === source.id && command.viewId === undefined)) {
220
+ return layout;
180
221
  }
181
- let added;
182
- if (command.side) {
183
- const id = command.viewId === undefined ? source.id : command.newPaneId;
184
- if (!id ||
185
- !command.splitId ||
186
- id === command.splitId ||
187
- findSplitNode(layout.root, command.splitId) ||
188
- (findSplitNode(layout.root, id) && !(id === source.id && command.viewId === undefined))) {
189
- return layout;
190
- }
191
- added = { type: 'pane', id, views: moving, active: command.viewId ?? source.active };
222
+ added = {
223
+ type: 'pane',
224
+ id,
225
+ views: moving,
226
+ active: command.viewId ?? source.active
227
+ };
228
+ }
229
+ const remaining = without(source, moving);
230
+ const root = replace(layout.root, source.id, () => remaining.views.length || source === target ? remaining : null);
231
+ if (!root) {
232
+ return layout;
233
+ }
234
+ const next = replace(root, target.id, node => {
235
+ if (node.type !== 'pane') {
236
+ return node;
192
237
  }
193
- const remaining = without(source, moving);
194
- const root = replace(layout.root, source.id, () => (remaining.views.length || source === target ? remaining : null));
195
- if (!root) {
196
- return layout;
238
+ if (added && command.side && command.splitId) {
239
+ return beside(node, added, command.side, command.splitId);
197
240
  }
198
- const next = replace(root, target.id, (node) => {
199
- if (node.type !== 'pane') {
200
- return node;
201
- }
202
- if (added && command.side && command.splitId) {
203
- return beside(node, added, command.side, command.splitId);
204
- }
205
- const gap = Math.max(0, Math.min(target.views.length, command.index ?? target.views.length));
206
- const lifted = source === target ? target.views.slice(0, gap).filter((view) => moving.includes(view)).length : 0;
207
- const views = [...node.views];
208
- views.splice(gap - lifted, 0, ...moving);
209
- return { ...node, views, active: command.viewId ?? source.active ?? views[0] ?? null };
210
- });
211
- return finish({ ...layout, maximized: null }, next, added?.id ?? target.id);
241
+ const gap = Math.max(0, Math.min(target.views.length, command.index ?? target.views.length));
242
+ const lifted = source === target ? target.views.slice(0, gap).filter(view => moving.includes(view)).length : 0;
243
+ const views = [...node.views];
244
+ views.splice(gap - lifted, 0, ...moving);
245
+ return {
246
+ ...node,
247
+ views,
248
+ active: command.viewId ?? source.active ?? views[0] ?? null
249
+ };
250
+ });
251
+ return finish({
252
+ ...layout,
253
+ maximized: null
254
+ }, next, added?.id ?? target.id);
212
255
  }
213
256
  function resizeBranch(layout, command) {
214
- const node = findSplitNode(layout.root, command.splitId);
215
- if (!node || node.type !== 'split') {
216
- return layout;
217
- }
218
- let sizes = [...node.sizes];
219
- if (command.type === 'resize') {
220
- if (command.sizes.length !== node.children.length || command.sizes.some((size) => !Number.isFinite(size) || size <= 0)) {
221
- return layout;
222
- }
223
- sizes = shares(command.sizes, node.children.length);
257
+ const node = findSplitNode(layout.root, command.splitId);
258
+ if (!node || node.type !== 'split') {
259
+ return layout;
260
+ }
261
+ let sizes = [...node.sizes];
262
+ if (command.type === 'resize') {
263
+ if (command.sizes.length !== node.children.length || command.sizes.some(size => !Number.isFinite(size) || size <= 0)) {
264
+ return layout;
224
265
  }
225
- else if (command.index === undefined) {
226
- sizes = node.children.map(() => 1 / node.children.length);
266
+ sizes = shares(command.sizes, node.children.length);
267
+ } else if (command.index === undefined) {
268
+ sizes = node.children.map(() => 1 / node.children.length);
269
+ } else {
270
+ const index = command.index;
271
+ if (index < 0 || index >= sizes.length - 1) {
272
+ return layout;
227
273
  }
228
- else {
229
- const index = command.index;
230
- if (index < 0 || index >= sizes.length - 1) {
231
- return layout;
232
- }
233
- sizes[index] = sizes[index + 1] = (sizes[index] + sizes[index + 1]) / 2;
234
- }
235
- return finish(layout, replace(layout.root, node.id, () => ({ ...node, sizes })));
274
+ sizes[index] = sizes[index + 1] = (sizes[index] + sizes[index + 1]) / 2;
275
+ }
276
+ return finish(layout, replace(layout.root, node.id, () => ({
277
+ ...node,
278
+ sizes
279
+ })));
236
280
  }
237
281
  /** Invalid or stale commands are no-ops. IDs for new nodes come from the caller. */
238
282
  export function updateSplitLayout(layout, command) {
239
- const panes = splitPanes(layout.root);
240
- const pane = 'paneId' in command ? panes.find((item) => item.id === command.paneId) : undefined;
241
- switch (command.type) {
242
- case 'focus':
243
- return pane && layout.focused !== pane.id ? { ...layout, focused: pane.id } : layout;
244
- case 'maximize':
245
- return command.paneId === null || pane ? { ...layout, maximized: command.paneId, focused: pane?.id ?? layout.focused } : layout;
246
- case 'activate':
247
- return pane?.views.includes(command.viewId)
248
- ? finish(layout, replace(layout.root, pane.id, () => ({ ...pane, active: command.viewId })), pane.id)
249
- : layout;
250
- case 'close': {
251
- const source = panes.find((item) => item.views.includes(command.viewId));
252
- if (!source) {
253
- return layout;
254
- }
255
- const next = without(source, [command.viewId]);
256
- return finish(layout, replace(layout.root, source.id, () => (next.views.length || panes.length === 1 ? next : null)));
283
+ const panes = splitPanes(layout.root);
284
+ const pane = 'paneId' in command ? panes.find(item => item.id === command.paneId) : undefined;
285
+ switch (command.type) {
286
+ case 'focus':
287
+ return pane && layout.focused !== pane.id ? {
288
+ ...layout,
289
+ focused: pane.id
290
+ } : layout;
291
+ case 'maximize':
292
+ return command.paneId === null || pane ? {
293
+ ...layout,
294
+ maximized: command.paneId,
295
+ focused: pane?.id ?? layout.focused
296
+ } : layout;
297
+ case 'activate':
298
+ return pane?.views.includes(command.viewId) ? finish(layout, replace(layout.root, pane.id, () => ({
299
+ ...pane,
300
+ active: command.viewId
301
+ })), pane.id) : layout;
302
+ case 'close':
303
+ {
304
+ const source = panes.find(item => item.views.includes(command.viewId));
305
+ if (!source) {
306
+ return layout;
257
307
  }
258
- case 'closePane':
259
- return pane
260
- ? finish(layout, replace(layout.root, pane.id, () => null))
261
- : layout;
262
- case 'insert': {
263
- if (!pane) {
264
- return layout;
265
- }
266
- const source = panes.find((item) => item.views.includes(command.viewId));
267
- if (source) {
268
- return updateSplitLayout(layout, { type: 'move', sourceId: source.id, targetId: pane.id, viewId: command.viewId, index: command.index });
269
- }
270
- const views = [...pane.views];
271
- views.splice(Math.max(0, Math.min(views.length, command.index ?? views.length)), 0, command.viewId);
272
- return finish(layout, replace(layout.root, pane.id, () => ({ ...pane, views, active: command.viewId })), pane.id);
308
+ const next = without(source, [command.viewId]);
309
+ return finish(layout, replace(layout.root, source.id, () => next.views.length || panes.length === 1 ? next : null));
310
+ }
311
+ case 'closePane':
312
+ return pane ? finish(layout, replace(layout.root, pane.id, () => null)) : layout;
313
+ case 'insert':
314
+ {
315
+ if (!pane) {
316
+ return layout;
273
317
  }
274
- case 'split':
275
- return addPane(layout, panes, pane, command);
276
- case 'swap':
277
- return swapPanes(layout, panes, command);
278
- case 'move':
279
- return moveViews(layout, panes, command);
280
- case 'equalizeAxis': {
281
- const length = command.length ?? 1;
282
- const gap = command.gap ?? 0;
283
- if (layout.root.type === 'pane' || !Number.isFinite(length) || length <= 0 || !Number.isFinite(gap) || gap < 0) {
284
- return layout;
285
- }
286
- return finish(layout, equalizeAxis(layout.root, command.axis, length, gap));
318
+ const source = panes.find(item => item.views.includes(command.viewId));
319
+ if (source) {
320
+ return updateSplitLayout(layout, {
321
+ type: 'move',
322
+ sourceId: source.id,
323
+ targetId: pane.id,
324
+ viewId: command.viewId,
325
+ index: command.index
326
+ });
287
327
  }
288
- case 'resize':
289
- case 'equalize':
290
- return resizeBranch(layout, command);
291
- }
292
- }
328
+ const views = [...pane.views];
329
+ views.splice(Math.max(0, Math.min(views.length, command.index ?? views.length)), 0, command.viewId);
330
+ return finish(layout, replace(layout.root, pane.id, () => ({
331
+ ...pane,
332
+ views,
333
+ active: command.viewId
334
+ })), pane.id);
335
+ }
336
+ case 'split':
337
+ return addPane(layout, panes, pane, command);
338
+ case 'swap':
339
+ return swapPanes(layout, panes, command);
340
+ case 'move':
341
+ return moveViews(layout, panes, command);
342
+ case 'equalizeAxis':
343
+ {
344
+ const length = command.length ?? 1;
345
+ const gap = command.gap ?? 0;
346
+ if (layout.root.type === 'pane' || !Number.isFinite(length) || length <= 0 || !Number.isFinite(gap) || gap < 0) {
347
+ return layout;
348
+ }
349
+ return finish(layout, equalizeAxis(layout.root, command.axis, length, gap));
350
+ }
351
+ case 'resize':
352
+ case 'equalize':
353
+ return resizeBranch(layout, command);
354
+ }
355
+ }