@bsuite/page-builder 1.0.3 → 1.0.5
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePageGridLayout.d.ts","sourceRoot":"","sources":["../src/usePageGridLayout.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAGV,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,0BAA0B,2IAM7B,CAAC;AAEX;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAiBzC,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"usePageGridLayout.d.ts","sourceRoot":"","sources":["../src/usePageGridLayout.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAGV,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,0BAA0B,2IAM7B,CAAC;AAEX;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAiBzC,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AA6BD,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,cAAc,EACd,WAAgB,EAChB,aAAiB,EACjB,WAAkB,EAClB,gBAA6C,EAC7C,iBAA4C,EAC5C,iBAAiB,GAClB,EAAE,wBAAwB,GAAG,uBAAuB,CAirBpD"}
|
|
@@ -55,6 +55,33 @@ export const PACKAGE_LAYOUT_EPOCH = 1000;
|
|
|
55
55
|
* opts out with an explicit `autoHeight: false`.
|
|
56
56
|
*/
|
|
57
57
|
const DEFAULT_ITEM_AUTO_HEIGHT = true;
|
|
58
|
+
/**
|
|
59
|
+
* Do two layout SETS describe the same arrangement, at every breakpoint?
|
|
60
|
+
*
|
|
61
|
+
* Compares only the five fields that place an item. Anything else react-grid-layout
|
|
62
|
+
* attaches (`moved`, `static`, `isDraggable`, measured heights) is noise here, and
|
|
63
|
+
* comparing it would make every reflow look like a change.
|
|
64
|
+
*
|
|
65
|
+
* EVERY breakpoint, not just `lg`. A gesture made while the canvas is at `md`
|
|
66
|
+
* leaves `lg` untouched, so an `lg`-only comparison reads that real gesture as a
|
|
67
|
+
* reflow and silently drops it. That is not hypothetical — it broke the D-75
|
|
68
|
+
* "folds a gesture made at md back onto lg" test the moment the comparison was
|
|
69
|
+
* introduced.
|
|
70
|
+
*/
|
|
71
|
+
function sameArrangement(a, b) {
|
|
72
|
+
if (!a || !b)
|
|
73
|
+
return false;
|
|
74
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
75
|
+
const fingerprint = (items) => (items ?? [])
|
|
76
|
+
.map((i) => `${i.i}:${i.x}:${i.y}:${i.w}:${i.h}`)
|
|
77
|
+
.sort()
|
|
78
|
+
.join('|');
|
|
79
|
+
for (const k of keys) {
|
|
80
|
+
if (fingerprint(a[k]) !== fingerprint(b[k]))
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
58
85
|
export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, layoutVersion = 1, canEditPage = true, editorEventNames = DEFAULT_EDITOR_EVENT_NAMES, preferenceAdapter = defaultPreferenceAdapter, defaultAutoHeight, }) {
|
|
59
86
|
const effectiveLayoutVersion = layoutVersion + PACKAGE_LAYOUT_EPOCH;
|
|
60
87
|
const containerRef = useRef(null);
|
|
@@ -184,13 +211,24 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
184
211
|
}
|
|
185
212
|
return resolved;
|
|
186
213
|
}, [rawLayouts, baseCols, layoutCols, defaultAutoHeight]);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
214
|
+
/*
|
|
215
|
+
* THERE IS DELIBERATELY NO EFFECT HERE.
|
|
216
|
+
*
|
|
217
|
+
* This used to rescale the stored layout to the new column count and write it
|
|
218
|
+
* back, which made a column change DESTRUCTIVE and unrecoverable. Measured on
|
|
219
|
+
* `rescaleLayout` directly: an 11 -> 2 -> 11 round trip takes
|
|
220
|
+
*
|
|
221
|
+
* a(w4 @x0) b(w3 @x4) c(w4 @x7) / d(w6 @x0) e(w5 @x6)
|
|
222
|
+
*
|
|
223
|
+
* to five items of w6 stacked one per row at x0. Everything narrows to the
|
|
224
|
+
* one-column minimum on the way down, the row-packer puts one item per row,
|
|
225
|
+
* and coming back up cannot recover an arrangement that no longer exists.
|
|
226
|
+
* That is what flattened the operator's dashboard.
|
|
227
|
+
*
|
|
228
|
+
* `currentLayouts` above already derives the DISPLAY at `layoutCols` from the
|
|
229
|
+
* authored layout at `baseCols`. Leaving storage alone makes the column
|
|
230
|
+
* control a view, and the round trip exact.
|
|
231
|
+
*/
|
|
194
232
|
const activeCols = useMemo(() => ({ lg: layoutCols, md: layoutCols, sm: layoutCols, xs: layoutCols, xxs: layoutCols }), [layoutCols]);
|
|
195
233
|
/**
|
|
196
234
|
* The compactor handed to react-grid-layout — the SAME one in edit mode and
|
|
@@ -413,15 +451,45 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
413
451
|
}
|
|
414
452
|
return next;
|
|
415
453
|
}, []);
|
|
454
|
+
/**
|
|
455
|
+
* Persist a layout the USER authored, and re-base the column count to the one
|
|
456
|
+
* they authored it at.
|
|
457
|
+
*
|
|
458
|
+
* Re-basing belongs here and ONLY here. A column-count change is a view
|
|
459
|
+
* operation and must not touch storage — see `handleColumnChange`. An edit is
|
|
460
|
+
* the one moment the stored arrangement and the stored column count are known
|
|
461
|
+
* to agree, so it is the one moment `baseCols` may move.
|
|
462
|
+
*/
|
|
416
463
|
const commitLayout = useCallback((layouts) => {
|
|
417
464
|
const canonical = canonicaliseLayoutForPersist(layouts);
|
|
418
465
|
if (!canonical)
|
|
419
466
|
return;
|
|
420
467
|
setSavedLayout(stripAutoHeightRows(canonical));
|
|
421
|
-
|
|
468
|
+
setBaseCols(layoutCols);
|
|
469
|
+
}, [canonicaliseLayoutForPersist, layoutCols, setBaseCols, setSavedLayout, stripAutoHeightRows]);
|
|
422
470
|
const onLayoutChange = useCallback((_layout, layouts) => {
|
|
423
471
|
if (!isEditing)
|
|
424
472
|
return;
|
|
473
|
+
/*
|
|
474
|
+
* A COLUMN-COUNT CHANGE MAKES REACT-GRID-LAYOUT REFLOW AND EMIT HERE, and
|
|
475
|
+
* that emission is not a user gesture. Committing it copies the rescaled
|
|
476
|
+
* DISPLAY back over the authored layout — which is the data loss this
|
|
477
|
+
* whole path exists to prevent, arriving through the back door.
|
|
478
|
+
*
|
|
479
|
+
* Removing the writes from `handleColumnChange` was not enough, and the
|
|
480
|
+
* unit tests did not catch it because they call the handler directly with
|
|
481
|
+
* no grid attached. Driving the deployed app is what found it: the
|
|
482
|
+
* persisted widths still marched 2,2,2 -> 4,4,4 -> 1,1,1 with the
|
|
483
|
+
* handler already inert.
|
|
484
|
+
*
|
|
485
|
+
* A reflow emits exactly `currentLayouts`, because that is what was just
|
|
486
|
+
* rendered. Any real gesture differs from it — and a gesture that does
|
|
487
|
+
* NOT differ has nothing to commit anyway, so this cannot swallow one.
|
|
488
|
+
* Identified by comparison rather than by a flag, so it needs no event
|
|
489
|
+
* ordering to be correct.
|
|
490
|
+
*/
|
|
491
|
+
if (sameArrangement(layouts, currentLayouts))
|
|
492
|
+
return;
|
|
425
493
|
pendingLayoutRef.current = layouts;
|
|
426
494
|
if (layoutCommitFrameRef.current !== null)
|
|
427
495
|
return;
|
|
@@ -438,7 +506,7 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
438
506
|
commitLayout(pending);
|
|
439
507
|
}
|
|
440
508
|
});
|
|
441
|
-
}, [commitLayout, isEditing]);
|
|
509
|
+
}, [commitLayout, currentLayouts, isEditing]);
|
|
442
510
|
useEffect(() => {
|
|
443
511
|
return () => {
|
|
444
512
|
if (layoutCommitFrameRef.current !== null &&
|
|
@@ -448,12 +516,18 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
448
516
|
}
|
|
449
517
|
};
|
|
450
518
|
}, []);
|
|
519
|
+
/**
|
|
520
|
+
* Change how many columns the canvas is DISPLAYED at.
|
|
521
|
+
*
|
|
522
|
+
* This writes nothing to storage. `currentLayouts` rescales the authored
|
|
523
|
+
* layout for display on every render, so switching 11 -> 2 -> 11 returns the
|
|
524
|
+
* user to exactly what they authored. The previous version persisted the
|
|
525
|
+
* rescale, which destroyed the arrangement at the narrow end and offered no
|
|
526
|
+
* undo. Storage moves only when the user actually edits — see `commitLayout`.
|
|
527
|
+
*/
|
|
451
528
|
const handleColumnChange = useCallback((newCols) => {
|
|
452
|
-
const rescaled = rescaleLayout(currentLayouts, layoutCols, newCols);
|
|
453
|
-
setSavedLayout(rescaled);
|
|
454
529
|
setLayoutCols(newCols);
|
|
455
|
-
|
|
456
|
-
}, [currentLayouts, layoutCols, setBaseCols, setLayoutCols, setSavedLayout]);
|
|
530
|
+
}, [setLayoutCols]);
|
|
457
531
|
/**
|
|
458
532
|
* Build the object handed to the preference adapter from a new `lg` array.
|
|
459
533
|
*
|
|
@@ -471,6 +545,11 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
471
545
|
}
|
|
472
546
|
return next;
|
|
473
547
|
}, [currentLayouts]);
|
|
548
|
+
/** Persist a bare `lg` item list from a mutator, re-basing the same way. */
|
|
549
|
+
const commitItems = useCallback((items) => {
|
|
550
|
+
setSavedLayout(layoutsWithLg(items));
|
|
551
|
+
setBaseCols(layoutCols);
|
|
552
|
+
}, [layoutCols, layoutsWithLg, setBaseCols, setSavedLayout]);
|
|
474
553
|
const handleCompact = useCallback(() => {
|
|
475
554
|
if (!currentLayouts.lg)
|
|
476
555
|
return;
|
|
@@ -487,8 +566,8 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
487
566
|
placed.push(compacted);
|
|
488
567
|
return compacted;
|
|
489
568
|
});
|
|
490
|
-
startTransition(() =>
|
|
491
|
-
}, [currentLayouts,
|
|
569
|
+
startTransition(() => commitItems(result));
|
|
570
|
+
}, [currentLayouts, commitItems]);
|
|
492
571
|
const handleReset = useCallback(() => {
|
|
493
572
|
startTransition(() => {
|
|
494
573
|
setSavedLayout(defaultLayouts);
|
|
@@ -507,7 +586,7 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
507
586
|
minW: initialSize?.minW,
|
|
508
587
|
minH: initialSize?.minH,
|
|
509
588
|
};
|
|
510
|
-
startTransition(() =>
|
|
589
|
+
startTransition(() => commitItems([...(currentLayouts.lg ?? []), newItem]));
|
|
511
590
|
}, [currentLayouts, layoutCols, layoutsWithLg, setSavedLayout]);
|
|
512
591
|
const moveWidget = useCallback((widgetKey, direction) => {
|
|
513
592
|
const items = [...(currentLayouts.lg ?? [])];
|
|
@@ -524,7 +603,7 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
524
603
|
moved,
|
|
525
604
|
...withoutMoved.slice(targetIndex),
|
|
526
605
|
];
|
|
527
|
-
startTransition(() =>
|
|
606
|
+
startTransition(() => commitItems(nextItems));
|
|
528
607
|
}, [currentLayouts, layoutsWithLg, setSavedLayout]);
|
|
529
608
|
const setWidgetLocked = useCallback((widgetKey, locked) => {
|
|
530
609
|
const nextItems = (currentLayouts.lg ?? []).map((item) => {
|
|
@@ -537,11 +616,11 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
537
616
|
isResizable: !locked,
|
|
538
617
|
};
|
|
539
618
|
});
|
|
540
|
-
startTransition(() =>
|
|
619
|
+
startTransition(() => commitItems(nextItems));
|
|
541
620
|
}, [currentLayouts, layoutsWithLg, setSavedLayout]);
|
|
542
621
|
const removeWidget = useCallback((widgetKey) => {
|
|
543
622
|
const nextItems = (currentLayouts.lg ?? []).filter((item) => item.i !== widgetKey);
|
|
544
|
-
startTransition(() =>
|
|
623
|
+
startTransition(() => commitItems(nextItems));
|
|
545
624
|
}, [currentLayouts, layoutsWithLg, setSavedLayout]);
|
|
546
625
|
/**
|
|
547
626
|
* Measured auto-height overrides (widgetKey -> rows). DERIVED, in-memory-
|