@window-splitter/state 0.2.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/.tshy/build.json +8 -0
- package/.tshy/commonjs.json +17 -0
- package/.tshy/esm.json +16 -0
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-lint.log +5 -0
- package/.turbo/turbo-test.log +278 -0
- package/CHANGELOG.md +191 -0
- package/README.md +13 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +350 -0
- package/coverage/coverage-final.json +2 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +116 -0
- package/coverage/index.ts.html +4627 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/dist/commonjs/index.d.ts +314 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +932 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/machine.test.d.ts +5 -0
- package/dist/commonjs/machine.test.d.ts.map +1 -0
- package/dist/commonjs/machine.test.js +1038 -0
- package/dist/commonjs/machine.test.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/commonjs/utils.test.d.ts +2 -0
- package/dist/commonjs/utils.test.d.ts.map +1 -0
- package/dist/commonjs/utils.test.js +79 -0
- package/dist/commonjs/utils.test.js.map +1 -0
- package/dist/esm/index.d.ts +314 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +890 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/machine.test.d.ts +5 -0
- package/dist/esm/machine.test.d.ts.map +1 -0
- package/dist/esm/machine.test.js +1036 -0
- package/dist/esm/machine.test.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/utils.test.d.ts +2 -0
- package/dist/esm/utils.test.d.ts.map +1 -0
- package/dist/esm/utils.test.js +77 -0
- package/dist/esm/utils.test.js.map +1 -0
- package/eslint.config.js +3 -0
- package/package.json +79 -0
- package/src/index.ts +1514 -0
- package/src/machine.test.ts +1316 -0
- package/src/utils.test.ts +104 -0
- package/tsconfig.json +3 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,890 @@
|
|
|
1
|
+
import { raf } from "@react-spring/rafz";
|
|
2
|
+
import { createMachine, assign, enqueueActions, fromPromise } from "xstate";
|
|
3
|
+
import invariant from "invariant";
|
|
4
|
+
import * as easings from "d3-ease";
|
|
5
|
+
// #region Constants
|
|
6
|
+
/** The default amount a user can `dragOvershoot` before the panel collapses */
|
|
7
|
+
const COLLAPSE_THRESHOLD = 50;
|
|
8
|
+
function makePercentUnit(value) {
|
|
9
|
+
return { type: "percent", value };
|
|
10
|
+
}
|
|
11
|
+
function makePixelUnit(value) {
|
|
12
|
+
return { type: "pixel", value };
|
|
13
|
+
}
|
|
14
|
+
function getCollapseAnimation(panel) {
|
|
15
|
+
let easeFn = collapseAnimations.linear;
|
|
16
|
+
let duration = 300;
|
|
17
|
+
if (panel.collapseAnimation) {
|
|
18
|
+
if (typeof panel.collapseAnimation === "string") {
|
|
19
|
+
easeFn = collapseAnimations[panel.collapseAnimation];
|
|
20
|
+
}
|
|
21
|
+
else if ("duration" in panel.collapseAnimation) {
|
|
22
|
+
duration = panel.collapseAnimation.duration ?? duration;
|
|
23
|
+
easeFn =
|
|
24
|
+
typeof panel.collapseAnimation.easing === "function"
|
|
25
|
+
? panel.collapseAnimation.easing
|
|
26
|
+
: collapseAnimations[panel.collapseAnimation.easing];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { ease: easeFn, duration };
|
|
30
|
+
}
|
|
31
|
+
const collapseAnimations = {
|
|
32
|
+
"ease-in-out": easings.easeQuadInOut,
|
|
33
|
+
bounce: easings.easeBackInOut,
|
|
34
|
+
linear: easings.easeLinear,
|
|
35
|
+
};
|
|
36
|
+
// #endregion
|
|
37
|
+
// #region Helpers
|
|
38
|
+
/** Assert that the provided event is one of the accepted types */
|
|
39
|
+
function isEvent(event, eventType) {
|
|
40
|
+
invariant(eventType.includes(event.type), `Invalid event type: ${eventType}. Expected: ${eventType.join(" | ")}`);
|
|
41
|
+
}
|
|
42
|
+
/** Determine if an item is a panel */
|
|
43
|
+
export function isPanelData(value) {
|
|
44
|
+
return Boolean(value &&
|
|
45
|
+
typeof value === "object" &&
|
|
46
|
+
"type" in value &&
|
|
47
|
+
value.type === "panel");
|
|
48
|
+
}
|
|
49
|
+
/** Determine if an item is a panel handle */
|
|
50
|
+
export function isPanelHandle(value) {
|
|
51
|
+
return Boolean(value &&
|
|
52
|
+
typeof value === "object" &&
|
|
53
|
+
"type" in value &&
|
|
54
|
+
value.type === "handle");
|
|
55
|
+
}
|
|
56
|
+
export function initializePanel(item) {
|
|
57
|
+
const data = {
|
|
58
|
+
type: "panel",
|
|
59
|
+
min: parseUnit(item.min || "0px"),
|
|
60
|
+
max: item.max ? parseUnit(item.max) : "1fr",
|
|
61
|
+
collapsed: item.collapsible
|
|
62
|
+
? (item.collapsed ?? item.defaultCollapsed ?? false)
|
|
63
|
+
: undefined,
|
|
64
|
+
collapsible: item.collapsible,
|
|
65
|
+
collapsedSize: parseUnit(item.collapsedSize ?? "0px"),
|
|
66
|
+
onCollapseChange: item.onCollapseChange,
|
|
67
|
+
collapseIsControlled: typeof item.collapsed !== "undefined",
|
|
68
|
+
sizeBeforeCollapse: undefined,
|
|
69
|
+
id: item.id,
|
|
70
|
+
collapseAnimation: item.collapseAnimation,
|
|
71
|
+
default: item.default ? parseUnit(item.default) : undefined,
|
|
72
|
+
};
|
|
73
|
+
return { ...data, currentValue: makePixelUnit(-1) };
|
|
74
|
+
}
|
|
75
|
+
/** Parse a `Unit` string or `clamp` value */
|
|
76
|
+
export function parseUnit(unit) {
|
|
77
|
+
if (unit === "1fr") {
|
|
78
|
+
unit = "100%";
|
|
79
|
+
}
|
|
80
|
+
if (unit.endsWith("px")) {
|
|
81
|
+
return makePixelUnit(parseFloat(unit));
|
|
82
|
+
}
|
|
83
|
+
if (unit.endsWith("%")) {
|
|
84
|
+
return makePercentUnit(parseFloat(unit));
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Invalid unit: ${unit}`);
|
|
87
|
+
}
|
|
88
|
+
/** Convert a `Unit` to a percentage of the group size */
|
|
89
|
+
export function getUnitPercentageValue(groupsSize, unit) {
|
|
90
|
+
if (unit.type === "pixel") {
|
|
91
|
+
return unit.value / groupsSize;
|
|
92
|
+
}
|
|
93
|
+
return unit.value;
|
|
94
|
+
}
|
|
95
|
+
export function getGroupSize(context) {
|
|
96
|
+
return context.orientation === "horizontal"
|
|
97
|
+
? context.size.width
|
|
98
|
+
: context.size.height;
|
|
99
|
+
}
|
|
100
|
+
/** Get the size of a panel in pixels */
|
|
101
|
+
export function getUnitPixelValue(context, unit) {
|
|
102
|
+
const parsed = unit === "1fr" ? parseUnit(unit) : unit;
|
|
103
|
+
return parsed.type === "pixel"
|
|
104
|
+
? parsed.value
|
|
105
|
+
: (parsed.value / 100) * getGroupSize(context);
|
|
106
|
+
}
|
|
107
|
+
/** Clamp a new `currentValue` given the panel's constraints. */
|
|
108
|
+
function clampUnit(context, item, value) {
|
|
109
|
+
return Math.min(Math.max(value, getUnitPixelValue(context, item.min)), getUnitPixelValue(context, item.max));
|
|
110
|
+
}
|
|
111
|
+
/** Get a panel with a particular ID. */
|
|
112
|
+
export function getPanelWithId(context, panelId) {
|
|
113
|
+
const item = context.items.find((i) => i.id === panelId);
|
|
114
|
+
if (item && isPanelData(item)) {
|
|
115
|
+
return item;
|
|
116
|
+
}
|
|
117
|
+
throw new Error(`Expected panel with id: ${panelId}`);
|
|
118
|
+
}
|
|
119
|
+
/** Get a panel with a particular ID. */
|
|
120
|
+
function getPanelHandleIndex(context, handleId) {
|
|
121
|
+
const item = context.items.findIndex((i) => i.id === handleId);
|
|
122
|
+
if (item !== -1 && isPanelHandle(context.items[item])) {
|
|
123
|
+
return item;
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`Expected panel handle with id: ${handleId}`);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the panel that's collapsible next to a resize handle.
|
|
129
|
+
* Will first check the left panel then the right.
|
|
130
|
+
*/
|
|
131
|
+
export function getCollapsiblePanelForHandleId(context, handleId) {
|
|
132
|
+
if (!context.items.length) {
|
|
133
|
+
throw new Error("No items in group");
|
|
134
|
+
}
|
|
135
|
+
const handleIndex = getPanelHandleIndex(context, handleId);
|
|
136
|
+
const panelBefore = context.items[handleIndex - 1];
|
|
137
|
+
const panelAfter = context.items[handleIndex + 1];
|
|
138
|
+
if (panelBefore && isPanelData(panelBefore) && panelBefore.collapsible) {
|
|
139
|
+
return panelBefore;
|
|
140
|
+
}
|
|
141
|
+
if (panelAfter && isPanelData(panelAfter) && panelAfter.collapsible) {
|
|
142
|
+
return panelAfter;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`No collapsible panel found for handle: ${handleId}`);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the handle closest to the target panel.
|
|
148
|
+
* This is used to simulate collapse/expand
|
|
149
|
+
*/
|
|
150
|
+
function getHandleForPanelId(context, panelId) {
|
|
151
|
+
const panelIndex = context.items.findIndex((item) => item.id === panelId);
|
|
152
|
+
invariant(panelIndex !== -1, `Expected panel before: ${panelId}`);
|
|
153
|
+
let item = context.items[panelIndex + 1];
|
|
154
|
+
if (item && isPanelHandle(item)) {
|
|
155
|
+
return { item, direction: 1 };
|
|
156
|
+
}
|
|
157
|
+
item = context.items[panelIndex - 1];
|
|
158
|
+
if (item && isPanelHandle(item)) {
|
|
159
|
+
return { item, direction: -1 };
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Cant find handle for panel: ${panelId}`);
|
|
162
|
+
}
|
|
163
|
+
/** Given the specified order props and default order of the items, order the items */
|
|
164
|
+
function sortWithOrder(items) {
|
|
165
|
+
const defaultPlacement = {};
|
|
166
|
+
const takenPlacements = items
|
|
167
|
+
.map((i) => i.order)
|
|
168
|
+
.filter((i) => i !== undefined);
|
|
169
|
+
let defaultOrder = 0;
|
|
170
|
+
// Generate default orders for items that don't have it
|
|
171
|
+
for (const item of items) {
|
|
172
|
+
if (item.order === undefined) {
|
|
173
|
+
while (takenPlacements.includes(defaultOrder) ||
|
|
174
|
+
Object.values(defaultPlacement).includes(defaultOrder)) {
|
|
175
|
+
defaultOrder++;
|
|
176
|
+
}
|
|
177
|
+
defaultPlacement[item.id] = defaultOrder;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const withoutOrder = items.filter((i) => i.order === undefined);
|
|
181
|
+
const sortedWithOrder = items
|
|
182
|
+
.filter((i) => i.order !== undefined)
|
|
183
|
+
.sort((a, b) => a.order - b.order);
|
|
184
|
+
for (const item of sortedWithOrder) {
|
|
185
|
+
// insert item at order index
|
|
186
|
+
withoutOrder.splice(item.order, 0, item);
|
|
187
|
+
}
|
|
188
|
+
return withoutOrder;
|
|
189
|
+
}
|
|
190
|
+
/** Check if the panel has space available to add to */
|
|
191
|
+
function panelHasSpace(context, item) {
|
|
192
|
+
invariant(item.currentValue.type === "pixel", `panelHasSpace only works with number values: ${item.id} ${item.currentValue}`);
|
|
193
|
+
if (item.collapsible && !item.collapsed) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
return item.currentValue.value > getUnitPixelValue(context, item.min);
|
|
197
|
+
}
|
|
198
|
+
/** Search in a `direction` for a panel that still has space to expand. */
|
|
199
|
+
function findPanelWithSpace(context, items, start, direction, disregardCollapseBuffer) {
|
|
200
|
+
const slice = direction === -1 ? items.slice(0, start + 1).reverse() : items.slice(start);
|
|
201
|
+
for (const panel of slice) {
|
|
202
|
+
if (!isPanelData(panel)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const targetPanel = disregardCollapseBuffer
|
|
206
|
+
? createUnrestrainedPanel(context, panel)
|
|
207
|
+
: panel;
|
|
208
|
+
if (panelHasSpace(context, targetPanel)) {
|
|
209
|
+
return panel;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Add up all the static values in the layout */
|
|
214
|
+
function getStaticWidth(context) {
|
|
215
|
+
let width = 0;
|
|
216
|
+
for (const item of context.items) {
|
|
217
|
+
if (isPanelHandle(item)) {
|
|
218
|
+
width += item.size.value;
|
|
219
|
+
}
|
|
220
|
+
else if (isPanelData(item) &&
|
|
221
|
+
item.collapsed &&
|
|
222
|
+
item.currentValue.type === "pixel") {
|
|
223
|
+
width += item.currentValue.value;
|
|
224
|
+
}
|
|
225
|
+
else if (isPanelData(item) &&
|
|
226
|
+
item.default &&
|
|
227
|
+
item.default.type === "pixel") {
|
|
228
|
+
width += item.default.value;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return width;
|
|
232
|
+
}
|
|
233
|
+
function formatUnit(unit) {
|
|
234
|
+
if (unit.type === "pixel") {
|
|
235
|
+
return `${unit.value}px`;
|
|
236
|
+
}
|
|
237
|
+
return `${unit.value}%`;
|
|
238
|
+
}
|
|
239
|
+
/** Build the grid template from the item values. */
|
|
240
|
+
export function buildTemplate(context) {
|
|
241
|
+
const staticWidth = getStaticWidth(context);
|
|
242
|
+
return context.items
|
|
243
|
+
.map((item) => {
|
|
244
|
+
if (item.type === "panel") {
|
|
245
|
+
const min = formatUnit(item.min);
|
|
246
|
+
if (item.currentValue.type === "pixel" &&
|
|
247
|
+
item.currentValue.value !== -1) {
|
|
248
|
+
return formatUnit(item.currentValue);
|
|
249
|
+
}
|
|
250
|
+
else if (item.currentValue.type === "percent") {
|
|
251
|
+
const max = item.max === "1fr" ? "100%" : formatUnit(item.max);
|
|
252
|
+
return `minmax(${min}, min(calc(${item.currentValue.value} * (100% - ${staticWidth}px)), ${max}))`;
|
|
253
|
+
}
|
|
254
|
+
else if (item.collapsible && item.collapsed) {
|
|
255
|
+
return formatUnit(item.collapsedSize);
|
|
256
|
+
}
|
|
257
|
+
else if (item.default) {
|
|
258
|
+
return formatUnit(item.default);
|
|
259
|
+
}
|
|
260
|
+
const max = item.max === "1fr" ? "1fr" : formatUnit(item.max);
|
|
261
|
+
return `minmax(${min}, ${max})`;
|
|
262
|
+
}
|
|
263
|
+
return formatUnit(item.size);
|
|
264
|
+
})
|
|
265
|
+
.join(" ");
|
|
266
|
+
}
|
|
267
|
+
function addDeDuplicatedItems(items, newItem) {
|
|
268
|
+
const currentItemIndex = items.findIndex((item) => item.id === newItem.id ||
|
|
269
|
+
(typeof item.order === "number" && item.order === newItem.order));
|
|
270
|
+
let restItems = items;
|
|
271
|
+
if (currentItemIndex !== -1) {
|
|
272
|
+
restItems = items.filter((_, index) => index !== currentItemIndex);
|
|
273
|
+
}
|
|
274
|
+
return sortWithOrder([...restItems, newItem]);
|
|
275
|
+
}
|
|
276
|
+
function createUnrestrainedPanel(context, data) {
|
|
277
|
+
return {
|
|
278
|
+
...data,
|
|
279
|
+
min: makePixelUnit(0),
|
|
280
|
+
max: makePixelUnit(getGroupSize(context)),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
// #endregion
|
|
284
|
+
// #region Update Logic
|
|
285
|
+
/**
|
|
286
|
+
* This is the main meat of the layout logic.
|
|
287
|
+
* It's responsible for figuring out how to distribute the space
|
|
288
|
+
* amongst the panels.
|
|
289
|
+
*
|
|
290
|
+
* It's built around applying small deltas to panels relative to their
|
|
291
|
+
* the resize handles.
|
|
292
|
+
*
|
|
293
|
+
* As much as possible we try to rely on the browser to do the layout.
|
|
294
|
+
* During the initial layout we rely on CSS grid and a group might be
|
|
295
|
+
* defined like this:
|
|
296
|
+
*
|
|
297
|
+
* ```css
|
|
298
|
+
* grid-template-columns: minmax(100px, 1fr) 1px minmax(100px, 300px);
|
|
299
|
+
* ```
|
|
300
|
+
*
|
|
301
|
+
* Without any resizing this is nice and simple and the components don't do much.
|
|
302
|
+
*
|
|
303
|
+
* Once the user starts resizing the layout will be more complex.
|
|
304
|
+
*
|
|
305
|
+
* It's broken down into 3 phases:
|
|
306
|
+
*
|
|
307
|
+
* 1. `prepareItems` - The size of the group has been measure and we
|
|
308
|
+
* can convert all the panel sizes into pixels. Converting into pixels
|
|
309
|
+
* makes doing the math for the updates easier.
|
|
310
|
+
*
|
|
311
|
+
* ```css
|
|
312
|
+
* grid-template-columns: 500px 1px 300px;
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* 2. `updateLayout` - This is where the actual updates are applied.
|
|
316
|
+
* This is where the user's drag interactions are applied. We also
|
|
317
|
+
* use this to collapse/expand panels by simulating a drag interaction.
|
|
318
|
+
*
|
|
319
|
+
* ```css
|
|
320
|
+
* grid-template-columns: 490px 1px 310px;
|
|
321
|
+
* ```
|
|
322
|
+
*
|
|
323
|
+
* 3. `commitLayout` - Once the updates have been applied we convert the
|
|
324
|
+
* updated sizes back into a format that allows for easy resizing without
|
|
325
|
+
* lots of updates.
|
|
326
|
+
*
|
|
327
|
+
* ```css
|
|
328
|
+
* grid-template-columns: minmax(100px, min(calc(0.06117 * (100% - 1px)), 100%)) 1px minmax(100px, min(calc(0.0387 * (100% - 1px)), 300px));
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* When another update loop is triggered the above template will be converted back to pixels.
|
|
332
|
+
*/
|
|
333
|
+
/** Converts the items to pixels */
|
|
334
|
+
export function prepareItems(context) {
|
|
335
|
+
const newItems = [...context.items];
|
|
336
|
+
const staticWidth = getStaticWidth(context);
|
|
337
|
+
for (const item of newItems) {
|
|
338
|
+
if (!item || !isPanelData(item)) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (item.currentValue.type === "pixel") {
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
// TODO: Decimal proposal
|
|
345
|
+
item.currentValue = makePixelUnit(Math.round((getGroupSize(context) - staticWidth) * item.currentValue.value));
|
|
346
|
+
}
|
|
347
|
+
return newItems;
|
|
348
|
+
}
|
|
349
|
+
/** On every mouse move we distribute the space added */
|
|
350
|
+
function updateLayout(context, dragEvent) {
|
|
351
|
+
const handleIndex = getPanelHandleIndex(context, dragEvent.handleId);
|
|
352
|
+
const handle = context.items[handleIndex];
|
|
353
|
+
const newItems = [...context.items];
|
|
354
|
+
let moveAmount = context.orientation === "horizontal"
|
|
355
|
+
? dragEvent.value.deltaX
|
|
356
|
+
: dragEvent.value.deltaY;
|
|
357
|
+
if (dragEvent.value.shiftKey) {
|
|
358
|
+
moveAmount *= 15;
|
|
359
|
+
}
|
|
360
|
+
if (moveAmount === 0) {
|
|
361
|
+
return {};
|
|
362
|
+
}
|
|
363
|
+
const moveDirection = moveAmount / Math.abs(moveAmount);
|
|
364
|
+
// Go forward into the shrinking panels to find a panel that still has space.
|
|
365
|
+
const panelBefore = findPanelWithSpace(context, newItems, handleIndex + moveDirection, moveDirection, dragEvent.disregardCollapseBuffer);
|
|
366
|
+
// No panel with space, just record the drag overshoot
|
|
367
|
+
if (!panelBefore) {
|
|
368
|
+
return {
|
|
369
|
+
dragOvershoot: context.dragOvershoot + moveAmount,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
invariant(isPanelData(panelBefore), `Expected panel before: ${handle.id}`);
|
|
373
|
+
const panelAfter = newItems[handleIndex - moveDirection];
|
|
374
|
+
invariant(panelAfter && isPanelData(panelAfter), `Expected panel after: ${handle.id}`);
|
|
375
|
+
const newDragOvershoot = context.dragOvershoot + moveAmount;
|
|
376
|
+
// Don't let the panel expand until the threshold is reached
|
|
377
|
+
if (!dragEvent.disregardCollapseBuffer) {
|
|
378
|
+
if (panelAfter.collapsible && panelAfter.collapsed) {
|
|
379
|
+
const isInLeftBuffer = newDragOvershoot < 0 && moveDirection > 0;
|
|
380
|
+
const isInLeftOvershoot = newDragOvershoot > 0 && moveDirection > 0;
|
|
381
|
+
const isInRightBuffer = newDragOvershoot > 0 && moveDirection < 0;
|
|
382
|
+
const isInRightOvershoot = newDragOvershoot < 0 && moveDirection < 0;
|
|
383
|
+
const potentialNewValue = panelAfter.currentValue.value +
|
|
384
|
+
newDragOvershoot * (isInRightBuffer ? moveDirection : 1);
|
|
385
|
+
const min = getUnitPixelValue(context, panelAfter.min);
|
|
386
|
+
if ((newDragOvershoot === 0 ||
|
|
387
|
+
isInRightBuffer ||
|
|
388
|
+
isInLeftBuffer ||
|
|
389
|
+
((isInLeftOvershoot || isInRightOvershoot) &&
|
|
390
|
+
Math.abs(newDragOvershoot) < COLLAPSE_THRESHOLD)) &&
|
|
391
|
+
potentialNewValue < min) {
|
|
392
|
+
return { dragOvershoot: newDragOvershoot };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
// Don't let the panel collapse until the threshold is reached
|
|
396
|
+
else if (panelBefore.collapsible &&
|
|
397
|
+
panelBefore.currentValue.value ===
|
|
398
|
+
getUnitPixelValue(context, panelBefore.min)) {
|
|
399
|
+
const potentialNewValue = panelBefore.currentValue.value - Math.abs(newDragOvershoot);
|
|
400
|
+
if (Math.abs(newDragOvershoot) < COLLAPSE_THRESHOLD &&
|
|
401
|
+
potentialNewValue >
|
|
402
|
+
getUnitPixelValue(context, panelBefore.collapsedSize)) {
|
|
403
|
+
return { dragOvershoot: newDragOvershoot };
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
// Apply the move amount to the panel before the slider
|
|
408
|
+
const unrestrainedPanelBefore = createUnrestrainedPanel(context, panelBefore);
|
|
409
|
+
const panelBeforePreviousValue = panelBefore.currentValue.value;
|
|
410
|
+
const panelBeforeNewValueRaw = panelBefore.currentValue.value - moveAmount * moveDirection;
|
|
411
|
+
let panelBeforeNewValue = dragEvent.disregardCollapseBuffer
|
|
412
|
+
? clampUnit(context, unrestrainedPanelBefore, panelBeforeNewValueRaw)
|
|
413
|
+
: clampUnit(context, panelBefore, panelBeforeNewValueRaw);
|
|
414
|
+
// Also apply the move amount the panel after the slider
|
|
415
|
+
const unrestrainedPanelAfter = createUnrestrainedPanel(context, panelAfter);
|
|
416
|
+
const panelAfterPreviousValue = panelAfter.currentValue.value;
|
|
417
|
+
const applied = panelBeforePreviousValue - panelBeforeNewValue;
|
|
418
|
+
const panelAfterNewValueRaw = panelAfter.currentValue.value + applied;
|
|
419
|
+
let panelAfterNewValue = dragEvent.disregardCollapseBuffer
|
|
420
|
+
? clampUnit(context, unrestrainedPanelAfter, panelAfterNewValueRaw)
|
|
421
|
+
: clampUnit(context, panelAfter, panelAfterNewValueRaw);
|
|
422
|
+
if (dragEvent.disregardCollapseBuffer) {
|
|
423
|
+
if (panelAfter.collapsible && panelAfter.collapsed) {
|
|
424
|
+
panelAfter.collapsed = false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// If the panel was collapsed, expand it
|
|
428
|
+
// We need to re-apply the move amount since the the expansion of the
|
|
429
|
+
// collapsed panel disregards that.
|
|
430
|
+
else if (panelAfter.collapsible && panelAfter.collapsed) {
|
|
431
|
+
if (panelAfter.onCollapseChange?.current &&
|
|
432
|
+
panelAfter.collapseIsControlled &&
|
|
433
|
+
!dragEvent.controlled) {
|
|
434
|
+
panelAfter.onCollapseChange.current(false);
|
|
435
|
+
return { dragOvershoot: newDragOvershoot };
|
|
436
|
+
}
|
|
437
|
+
// Calculate the amount "extra" after the minSize the panel should grow
|
|
438
|
+
const extra =
|
|
439
|
+
// Take the size it was at
|
|
440
|
+
getUnitPixelValue(context, panelAfter.collapsedSize) +
|
|
441
|
+
// Add in the full overshoot so the cursor is near the slider
|
|
442
|
+
Math.abs(context.dragOvershoot) -
|
|
443
|
+
// Subtract the min size of the panel
|
|
444
|
+
panelAfterNewValue +
|
|
445
|
+
// Then re-add the move amount
|
|
446
|
+
Math.abs(moveAmount);
|
|
447
|
+
panelAfter.collapsed = false;
|
|
448
|
+
if (extra > 0) {
|
|
449
|
+
panelAfterNewValue += extra;
|
|
450
|
+
}
|
|
451
|
+
panelBeforeNewValue -=
|
|
452
|
+
// Subtract the delta of the after panel's size
|
|
453
|
+
panelAfterNewValue -
|
|
454
|
+
panelAfterPreviousValue -
|
|
455
|
+
// And then re-apply the movement value
|
|
456
|
+
Math.abs(moveAmount);
|
|
457
|
+
if (panelAfter.onCollapseChange?.current &&
|
|
458
|
+
!panelAfter.collapseIsControlled &&
|
|
459
|
+
!dragEvent.controlled) {
|
|
460
|
+
panelAfter.onCollapseChange.current(false);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const panelBeforeIsAboutToCollapse = panelBefore.currentValue.value ===
|
|
464
|
+
getUnitPixelValue(context, panelBefore.min);
|
|
465
|
+
// If the panel was expanded and now is at it's min size, collapse it
|
|
466
|
+
if (!dragEvent.disregardCollapseBuffer &&
|
|
467
|
+
panelBefore.collapsible &&
|
|
468
|
+
panelBeforeIsAboutToCollapse) {
|
|
469
|
+
if (panelBefore.onCollapseChange?.current &&
|
|
470
|
+
panelBefore.collapseIsControlled &&
|
|
471
|
+
!dragEvent.controlled) {
|
|
472
|
+
panelBefore.onCollapseChange.current(true);
|
|
473
|
+
return { dragOvershoot: newDragOvershoot };
|
|
474
|
+
}
|
|
475
|
+
// Make it collapsed
|
|
476
|
+
panelBefore.collapsed = true;
|
|
477
|
+
panelBeforeNewValue = getUnitPixelValue(context, panelBefore.collapsedSize);
|
|
478
|
+
// Add the extra space created to the before panel
|
|
479
|
+
panelAfterNewValue += panelBeforePreviousValue - panelBeforeNewValue;
|
|
480
|
+
if (panelBefore.onCollapseChange?.current &&
|
|
481
|
+
!panelBefore.collapseIsControlled &&
|
|
482
|
+
!dragEvent.controlled) {
|
|
483
|
+
panelBefore.onCollapseChange.current(true);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
panelBefore.currentValue = makePixelUnit(panelBeforeNewValue);
|
|
487
|
+
panelAfter.currentValue = makePixelUnit(panelAfterNewValue);
|
|
488
|
+
const leftoverSpace = getGroupSize(context) -
|
|
489
|
+
newItems.reduce((acc, b) => acc +
|
|
490
|
+
// in updateLayout the panel units will always be numbers
|
|
491
|
+
(isPanelData(b) ? b.currentValue.value : b.size.value), 0);
|
|
492
|
+
// TODO: this is wrong?
|
|
493
|
+
panelBefore.currentValue.value += leftoverSpace;
|
|
494
|
+
return { items: newItems, dragOvershoot: 0 };
|
|
495
|
+
}
|
|
496
|
+
/** Converts the items to percentages */
|
|
497
|
+
export function commitLayout(context) {
|
|
498
|
+
const newItems = [...context.items];
|
|
499
|
+
// First set all the static width
|
|
500
|
+
newItems.forEach((item, index) => {
|
|
501
|
+
if (item.type !== "panel") {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (item.collapsed) {
|
|
505
|
+
newItems[index] = {
|
|
506
|
+
...item,
|
|
507
|
+
currentValue: item.collapsedSize,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
const staticWidth = getStaticWidth({ ...context, items: newItems });
|
|
512
|
+
newItems.forEach((item, index) => {
|
|
513
|
+
if (item.type !== "panel" || item.collapsed) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
newItems[index] = {
|
|
517
|
+
...item,
|
|
518
|
+
currentValue: makePercentUnit(item.currentValue.value / (getGroupSize(context) - staticWidth)),
|
|
519
|
+
};
|
|
520
|
+
});
|
|
521
|
+
return newItems;
|
|
522
|
+
}
|
|
523
|
+
export function dragHandlePayload({ delta, orientation, shiftKey = false, }) {
|
|
524
|
+
return {
|
|
525
|
+
type: "move",
|
|
526
|
+
pointerType: "keyboard",
|
|
527
|
+
shiftKey,
|
|
528
|
+
ctrlKey: false,
|
|
529
|
+
altKey: false,
|
|
530
|
+
metaKey: false,
|
|
531
|
+
deltaX: orientation === "horizontal" ? delta : 0,
|
|
532
|
+
deltaY: orientation === "horizontal" ? 0 : delta,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
/** Iteratively applies a large delta value simulating a user's drag */
|
|
536
|
+
function iterativelyUpdateLayout({ context, handleId, delta, direction, controlled, disregardCollapseBuffer, }) {
|
|
537
|
+
let newContext = context;
|
|
538
|
+
for (let i = 0; i < Math.abs(delta); i++) {
|
|
539
|
+
newContext = updateLayout({
|
|
540
|
+
...context,
|
|
541
|
+
...newContext,
|
|
542
|
+
}, {
|
|
543
|
+
handleId,
|
|
544
|
+
type: "collapsePanel",
|
|
545
|
+
controlled,
|
|
546
|
+
disregardCollapseBuffer,
|
|
547
|
+
value: dragHandlePayload({
|
|
548
|
+
delta: direction,
|
|
549
|
+
orientation: context.orientation,
|
|
550
|
+
}),
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
return newContext;
|
|
554
|
+
}
|
|
555
|
+
function applyDeltaInBothDirections(context, newItems, itemIndex, delta) {
|
|
556
|
+
let hasTriedBothDirections = false;
|
|
557
|
+
let direction = 1;
|
|
558
|
+
// Starting from where the items was removed add space to the panels around it.
|
|
559
|
+
// This is only needed for conditional rendering.
|
|
560
|
+
while (delta !== 0) {
|
|
561
|
+
const targetPanel = findPanelWithSpace(context, newItems, itemIndex + direction, direction);
|
|
562
|
+
if (!targetPanel) {
|
|
563
|
+
if (hasTriedBothDirections) {
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
direction = direction === 1 ? -1 : 1;
|
|
568
|
+
hasTriedBothDirections = true;
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
const oldValue = targetPanel.currentValue.value;
|
|
573
|
+
const newValue = clampUnit(context, targetPanel, oldValue + delta);
|
|
574
|
+
targetPanel.currentValue.value = newValue;
|
|
575
|
+
delta -= newValue - oldValue;
|
|
576
|
+
direction = direction === 1 ? -1 : 1;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
const animationActor = fromPromise(({ input: { send, context, event } }) => new Promise((resolve) => {
|
|
580
|
+
const panel = getPanelWithId(context, event.panelId);
|
|
581
|
+
const handle = getHandleForPanelId(context, event.panelId);
|
|
582
|
+
let direction = handle.direction;
|
|
583
|
+
let fullDelta = 0;
|
|
584
|
+
if (event.type === "expandPanel") {
|
|
585
|
+
fullDelta =
|
|
586
|
+
(panel.sizeBeforeCollapse ?? getUnitPixelValue(context, panel.min)) -
|
|
587
|
+
panel.currentValue.value;
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
const collapsedSize = getUnitPixelValue(context, panel.collapsedSize);
|
|
591
|
+
panel.sizeBeforeCollapse = panel.currentValue.value;
|
|
592
|
+
direction *= -1;
|
|
593
|
+
fullDelta = panel.currentValue.value - collapsedSize;
|
|
594
|
+
}
|
|
595
|
+
const fps = 60;
|
|
596
|
+
const { duration, ease } = getCollapseAnimation(panel);
|
|
597
|
+
const totalFrames = Math.ceil(panel.collapseAnimation ? duration / (1000 / fps) : 1);
|
|
598
|
+
let frame = 0;
|
|
599
|
+
let appliedDelta = 0;
|
|
600
|
+
function renderFrame() {
|
|
601
|
+
const progress = (frame++ + 1) / totalFrames;
|
|
602
|
+
const e = panel.collapseAnimation ? ease(progress) : 1;
|
|
603
|
+
const delta = (e * fullDelta - appliedDelta) * direction;
|
|
604
|
+
send({ type: "applyDelta", handleId: handle.item.id, delta });
|
|
605
|
+
appliedDelta +=
|
|
606
|
+
Math.abs(delta) *
|
|
607
|
+
((delta > 0 && direction === -1) || (delta < 0 && direction === 1)
|
|
608
|
+
? -1
|
|
609
|
+
: 1);
|
|
610
|
+
if (e === 1) {
|
|
611
|
+
const action = event.type === "expandPanel" ? "expand" : "collapse";
|
|
612
|
+
resolve({ panelId: panel.id, action });
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
return true;
|
|
616
|
+
}
|
|
617
|
+
raf(renderFrame);
|
|
618
|
+
}));
|
|
619
|
+
export const groupMachine = createMachine({
|
|
620
|
+
initial: "idle",
|
|
621
|
+
types: {
|
|
622
|
+
context: {},
|
|
623
|
+
events: {},
|
|
624
|
+
input: {},
|
|
625
|
+
},
|
|
626
|
+
context: ({ input }) => ({
|
|
627
|
+
size: { width: 0, height: 0 },
|
|
628
|
+
items: input.initialItems || [],
|
|
629
|
+
orientation: input.orientation || "horizontal",
|
|
630
|
+
dragOvershoot: 0,
|
|
631
|
+
autosaveId: input.autosaveId,
|
|
632
|
+
groupId: input.groupId,
|
|
633
|
+
}),
|
|
634
|
+
states: {
|
|
635
|
+
idle: {
|
|
636
|
+
on: {
|
|
637
|
+
setActualItemsSize: { actions: ["recordActualItemSize"] },
|
|
638
|
+
dragHandleStart: { target: "dragging" },
|
|
639
|
+
setPanelPixelSize: {
|
|
640
|
+
actions: ["prepare", "onSetPanelSize", "commit"],
|
|
641
|
+
},
|
|
642
|
+
collapsePanel: [
|
|
643
|
+
{
|
|
644
|
+
actions: "notifyCollapseToggle",
|
|
645
|
+
guard: "shouldNotifyCollapseToggle",
|
|
646
|
+
},
|
|
647
|
+
{ target: "togglingCollapse" },
|
|
648
|
+
],
|
|
649
|
+
expandPanel: [
|
|
650
|
+
{
|
|
651
|
+
actions: "notifyCollapseToggle",
|
|
652
|
+
guard: "shouldNotifyCollapseToggle",
|
|
653
|
+
},
|
|
654
|
+
{ target: "togglingCollapse" },
|
|
655
|
+
],
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
dragging: {
|
|
659
|
+
entry: ["prepare"],
|
|
660
|
+
on: {
|
|
661
|
+
dragHandle: { actions: ["onDragHandle"] },
|
|
662
|
+
dragHandleEnd: { target: "idle" },
|
|
663
|
+
collapsePanel: {
|
|
664
|
+
guard: "shouldCollapseToggle",
|
|
665
|
+
actions: "runCollapseToggle",
|
|
666
|
+
},
|
|
667
|
+
expandPanel: {
|
|
668
|
+
guard: "shouldCollapseToggle",
|
|
669
|
+
actions: "runCollapseToggle",
|
|
670
|
+
},
|
|
671
|
+
},
|
|
672
|
+
exit: ["commit", "onAutosave"],
|
|
673
|
+
},
|
|
674
|
+
togglingCollapse: {
|
|
675
|
+
entry: ["prepare"],
|
|
676
|
+
invoke: {
|
|
677
|
+
src: "animation",
|
|
678
|
+
input: (i) => ({ ...i, send: i.self.send }),
|
|
679
|
+
onDone: {
|
|
680
|
+
target: "idle",
|
|
681
|
+
actions: ["onToggleCollapseComplete", "commit", "onAutosave"],
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
on: {
|
|
685
|
+
applyDelta: { actions: ["onApplyDelta"] },
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
},
|
|
689
|
+
on: {
|
|
690
|
+
registerPanel: { actions: ["assignPanelData"] },
|
|
691
|
+
registerDynamicPanel: {
|
|
692
|
+
actions: ["prepare", "onRegisterDynamicPanel", "commit", "onAutosave"],
|
|
693
|
+
},
|
|
694
|
+
unregisterPanel: {
|
|
695
|
+
actions: ["prepare", "removeItem", "commit", "onAutosave"],
|
|
696
|
+
},
|
|
697
|
+
registerPanelHandle: { actions: ["assignPanelHandleData"] },
|
|
698
|
+
unregisterPanelHandle: {
|
|
699
|
+
actions: ["prepare", "removeItem", "commit", "onAutosave"],
|
|
700
|
+
},
|
|
701
|
+
setSize: { actions: ["updateSize"] },
|
|
702
|
+
setOrientation: { actions: ["updateOrientation"] },
|
|
703
|
+
},
|
|
704
|
+
}, {
|
|
705
|
+
guards: {
|
|
706
|
+
shouldNotifyCollapseToggle: ({ context, event }) => {
|
|
707
|
+
isEvent(event, ["collapsePanel", "expandPanel"]);
|
|
708
|
+
const panel = getPanelWithId(context, event.panelId);
|
|
709
|
+
return !event.controlled && panel.collapseIsControlled === true;
|
|
710
|
+
},
|
|
711
|
+
shouldCollapseToggle: ({ context, event }) => {
|
|
712
|
+
isEvent(event, ["collapsePanel", "expandPanel"]);
|
|
713
|
+
const panel = getPanelWithId(context, event.panelId);
|
|
714
|
+
return panel.collapseIsControlled === true;
|
|
715
|
+
},
|
|
716
|
+
},
|
|
717
|
+
actors: {
|
|
718
|
+
animation: animationActor,
|
|
719
|
+
},
|
|
720
|
+
actions: {
|
|
721
|
+
notifyCollapseToggle: ({ context, event }) => {
|
|
722
|
+
isEvent(event, ["collapsePanel", "expandPanel"]);
|
|
723
|
+
const panel = getPanelWithId(context, event.panelId);
|
|
724
|
+
panel.onCollapseChange?.current?.(!panel.collapsed);
|
|
725
|
+
},
|
|
726
|
+
runCollapseToggle: enqueueActions(({ context, event, enqueue }) => {
|
|
727
|
+
isEvent(event, ["collapsePanel", "expandPanel"]);
|
|
728
|
+
const handle = getHandleForPanelId(context, event.panelId);
|
|
729
|
+
// When collapsing a panel it will be in the opposite direction
|
|
730
|
+
// that handle assumes
|
|
731
|
+
const delta = event.type === "collapsePanel"
|
|
732
|
+
? handle.direction * -1
|
|
733
|
+
: handle.direction;
|
|
734
|
+
const newContext = updateLayout(context, {
|
|
735
|
+
handleId: handle.item.id,
|
|
736
|
+
type: "dragHandle",
|
|
737
|
+
controlled: event.controlled,
|
|
738
|
+
value: dragHandlePayload({ delta, orientation: context.orientation }),
|
|
739
|
+
});
|
|
740
|
+
enqueue.assign(newContext);
|
|
741
|
+
}),
|
|
742
|
+
onToggleCollapseComplete: assign({
|
|
743
|
+
items: ({ context, event: e }) => {
|
|
744
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
745
|
+
const output = e.output;
|
|
746
|
+
invariant(output, "Expected output from animation actor");
|
|
747
|
+
const panel = getPanelWithId(context, output.panelId);
|
|
748
|
+
panel.collapsed = output.action === "collapse";
|
|
749
|
+
if (panel.collapsed) {
|
|
750
|
+
panel.currentValue = panel.collapsedSize;
|
|
751
|
+
}
|
|
752
|
+
return context.items;
|
|
753
|
+
},
|
|
754
|
+
}),
|
|
755
|
+
updateSize: assign({
|
|
756
|
+
size: ({ event }) => {
|
|
757
|
+
isEvent(event, ["setSize"]);
|
|
758
|
+
return event.size;
|
|
759
|
+
},
|
|
760
|
+
}),
|
|
761
|
+
recordActualItemSize: assign({
|
|
762
|
+
items: ({ context, event }) => {
|
|
763
|
+
isEvent(event, ["setActualItemsSize"]);
|
|
764
|
+
const orientation = context.orientation;
|
|
765
|
+
for (const [id, size] of Object.entries(event.childrenSizes)) {
|
|
766
|
+
const item = context.items.find((i) => i.id === id);
|
|
767
|
+
if (!isPanelData(item)) {
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
item.currentValue = makePixelUnit(orientation === "horizontal" ? size.width : size.height);
|
|
771
|
+
}
|
|
772
|
+
return commitLayout(context);
|
|
773
|
+
},
|
|
774
|
+
}),
|
|
775
|
+
updateOrientation: assign({
|
|
776
|
+
orientation: ({ event }) => {
|
|
777
|
+
isEvent(event, ["setOrientation"]);
|
|
778
|
+
return event.orientation;
|
|
779
|
+
},
|
|
780
|
+
}),
|
|
781
|
+
assignPanelData: assign({
|
|
782
|
+
items: ({ context, event }) => {
|
|
783
|
+
isEvent(event, ["registerPanel"]);
|
|
784
|
+
return addDeDuplicatedItems(context.items, {
|
|
785
|
+
type: "panel",
|
|
786
|
+
currentValue: makePixelUnit(-1),
|
|
787
|
+
...event.data,
|
|
788
|
+
});
|
|
789
|
+
},
|
|
790
|
+
}),
|
|
791
|
+
onRegisterDynamicPanel: assign({
|
|
792
|
+
items: ({ context, event }) => {
|
|
793
|
+
isEvent(event, ["registerDynamicPanel"]);
|
|
794
|
+
let currentValue = makePixelUnit(0);
|
|
795
|
+
if (event.data.collapsible &&
|
|
796
|
+
event.data.collapsed &&
|
|
797
|
+
event.data.collapsedSize) {
|
|
798
|
+
currentValue = event.data.collapsedSize;
|
|
799
|
+
}
|
|
800
|
+
else if (event.data.default) {
|
|
801
|
+
currentValue = event.data.default;
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
currentValue = event.data.min;
|
|
805
|
+
}
|
|
806
|
+
const newItems = addDeDuplicatedItems(context.items, {
|
|
807
|
+
type: "panel",
|
|
808
|
+
...event.data,
|
|
809
|
+
currentValue,
|
|
810
|
+
});
|
|
811
|
+
const itemIndex = newItems.findIndex((item) => item.id === event.data.id);
|
|
812
|
+
const newContext = { ...context, items: newItems };
|
|
813
|
+
const overflowDueToHandles = context.items.reduce((acc, i) => {
|
|
814
|
+
if (isPanelHandle(i)) {
|
|
815
|
+
return acc + getUnitPixelValue(context, i.size);
|
|
816
|
+
}
|
|
817
|
+
return acc + i.currentValue.value;
|
|
818
|
+
}, 0) - getGroupSize(context);
|
|
819
|
+
applyDeltaInBothDirections(newContext, newItems, itemIndex, -1 * (currentValue.value + overflowDueToHandles));
|
|
820
|
+
return newItems;
|
|
821
|
+
},
|
|
822
|
+
}),
|
|
823
|
+
assignPanelHandleData: assign({
|
|
824
|
+
items: ({ context, event }) => {
|
|
825
|
+
isEvent(event, ["registerPanelHandle"]);
|
|
826
|
+
return addDeDuplicatedItems(context.items, {
|
|
827
|
+
type: "handle",
|
|
828
|
+
...event.data,
|
|
829
|
+
size: event.data.size,
|
|
830
|
+
});
|
|
831
|
+
},
|
|
832
|
+
}),
|
|
833
|
+
removeItem: assign({
|
|
834
|
+
items: ({ context, event }) => {
|
|
835
|
+
isEvent(event, ["unregisterPanel", "unregisterPanelHandle"]);
|
|
836
|
+
const itemIndex = context.items.findIndex((item) => item.id === event.id);
|
|
837
|
+
const item = context.items[itemIndex];
|
|
838
|
+
if (!item) {
|
|
839
|
+
return context.items;
|
|
840
|
+
}
|
|
841
|
+
const newItems = context.items.filter((i) => i.id !== event.id);
|
|
842
|
+
const removedSize = isPanelData(item)
|
|
843
|
+
? item.currentValue.value
|
|
844
|
+
: item.size.value;
|
|
845
|
+
applyDeltaInBothDirections(context, newItems, itemIndex, removedSize);
|
|
846
|
+
return newItems;
|
|
847
|
+
},
|
|
848
|
+
}),
|
|
849
|
+
prepare: assign({
|
|
850
|
+
items: ({ context }) => prepareItems(context),
|
|
851
|
+
}),
|
|
852
|
+
onDragHandle: enqueueActions(({ context, event, enqueue }) => {
|
|
853
|
+
isEvent(event, ["dragHandle"]);
|
|
854
|
+
enqueue.assign(updateLayout(context, event));
|
|
855
|
+
}),
|
|
856
|
+
commit: assign({
|
|
857
|
+
dragOvershoot: 0,
|
|
858
|
+
items: ({ context }) => commitLayout(context),
|
|
859
|
+
}),
|
|
860
|
+
onApplyDelta: assign(({ context, event }) => {
|
|
861
|
+
isEvent(event, ["applyDelta"]);
|
|
862
|
+
return updateLayout(context, {
|
|
863
|
+
handleId: event.handleId,
|
|
864
|
+
type: "collapsePanel",
|
|
865
|
+
disregardCollapseBuffer: true,
|
|
866
|
+
value: dragHandlePayload({
|
|
867
|
+
delta: event.delta,
|
|
868
|
+
orientation: context.orientation,
|
|
869
|
+
}),
|
|
870
|
+
});
|
|
871
|
+
}),
|
|
872
|
+
onSetPanelSize: enqueueActions(({ context, event, enqueue }) => {
|
|
873
|
+
isEvent(event, ["setPanelPixelSize"]);
|
|
874
|
+
const panel = getPanelWithId(context, event.panelId);
|
|
875
|
+
const handle = getHandleForPanelId(context, event.panelId);
|
|
876
|
+
const current = panel.currentValue.value;
|
|
877
|
+
const newSize = clampUnit(context, panel, getUnitPixelValue(context, parseUnit(event.size)));
|
|
878
|
+
const isBigger = newSize > current;
|
|
879
|
+
const delta = isBigger ? newSize - current : current - newSize;
|
|
880
|
+
enqueue.assign(iterativelyUpdateLayout({
|
|
881
|
+
context,
|
|
882
|
+
direction: (handle.direction * (isBigger ? 1 : -1)),
|
|
883
|
+
handleId: handle.item.id,
|
|
884
|
+
delta,
|
|
885
|
+
}));
|
|
886
|
+
}),
|
|
887
|
+
},
|
|
888
|
+
});
|
|
889
|
+
// #endregion
|
|
890
|
+
//# sourceMappingURL=index.js.map
|