@bsuite/page-builder 2.7.0 → 2.7.1-next.1
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
CHANGED
|
@@ -48,3 +48,26 @@ Behaviour and guarantees:
|
|
|
48
48
|
|
|
49
49
|
When adding `autoHeight` to an existing page's layout, bump that page's
|
|
50
50
|
`layoutVersion` so stale persisted layouts (without the flag) are reset.
|
|
51
|
+
|
|
52
|
+
## Edit-mode chrome (2.7.1-next.0+)
|
|
53
|
+
|
|
54
|
+
`PAGE_GRID_EDITING_EVENT` reports committed changes from `2.7.1-next.1`.
|
|
55
|
+
Its `{ pageKey, editing }` payload and event name are unchanged. The matching
|
|
56
|
+
canvas DOM is updated before listeners run, including when Save & Exit uses
|
|
57
|
+
a React transition. Initial mounting, unchanged state and abandoned transitions
|
|
58
|
+
do not emit notifications. Consumers must match the page key and preserve
|
|
59
|
+
focus on surviving inputs when synchronizing their header controls.
|
|
60
|
+
|
|
61
|
+
While the canvas editor is open, each grid item renders an in-flow strip
|
|
62
|
+
(`[data-slot="grid-item-editor-chrome"]`) above the card content: the widget
|
|
63
|
+
name and a Hide control. The strip is **not** absolutely positioned over the
|
|
64
|
+
card heading. AutoHeight measures it with the content so the grid grows;
|
|
65
|
+
leaving edit mode removes it and restores the content-only measurement.
|
|
66
|
+
Do not restyle this in a consumer — it is the shared contract.
|
|
67
|
+
|
|
68
|
+
The label carries `min-w-0 truncate` and a `title` with the full name. That is
|
|
69
|
+
load-bearing on a narrow card, not decoration: without it the label's automatic
|
|
70
|
+
minimum size is its min-content, and a long unbroken widget name pushes the
|
|
71
|
+
`ml-auto` hide button outside the card box. Measured both ways in
|
|
72
|
+
`scripts/editor-chrome-geometry.mjs`, which reproduces the defect with the two
|
|
73
|
+
classes removed at run time.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAsBxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAsBxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;AA2pB7F,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,OAAO,EACP,UAAU,EACV,SAAS,EAMT,WAAkB,EAClB,aAAsC,EACtC,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAKhB,UAAkB,EAClB,yBAAiE,EACjE,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,+BAA6E,EAC7E,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,GAC7B,EAAE,mBAAmB,qBAu+BrB"}
|
package/dist/PageGridLayout.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { ElementScopeProvider } from './elementScope.js';
|
|
3
3
|
import { ArrowDown, ArrowUp, ChevronDown, ChevronUp, Eye, EyeOff, Layers, LayoutGrid, Lock, Plus, RotateCcw, Save, Settings2, Unlock } from 'lucide-react';
|
|
4
4
|
import React, { startTransition, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
@@ -109,6 +109,31 @@ const RGLResizeHandle = React.forwardRef(function RGLResizeHandle({ axis = 'se',
|
|
|
109
109
|
* the silent case audible in development and leaves production untouched, which
|
|
110
110
|
* is the same trade @bsuite/theme 1.3.0 made for its missing-provider warning.
|
|
111
111
|
*/
|
|
112
|
+
/**
|
|
113
|
+
* Edit-mode label + hide. These used to be `absolute top-2 left-2` /
|
|
114
|
+
* `top-2 right-2` overlays on the card (PageGridLayout GridItem, historically
|
|
115
|
+
* around the 407/415 marks). That painted the widget name and the hide control
|
|
116
|
+
* on top of the card heading — measured on the Candidates card at 1440.
|
|
117
|
+
*
|
|
118
|
+
* An earlier draft of this comment also claimed 390. Withdrawn: the instrument
|
|
119
|
+
* that produced that number never asserted its own `innerWidth`, and the cell
|
|
120
|
+
* labelled "390" reported 1560. What 390 actually looks like is now measured
|
|
121
|
+
* and recorded in `editor-chrome-geometry-390.json` — and it is a different
|
|
122
|
+
* fact: below a 480px container `buildResponsiveLayouts` stacks every card to
|
|
123
|
+
* full width, so 390 has no narrow card at all.
|
|
124
|
+
*
|
|
125
|
+
* In-flow, measured: the strip is a flex-none row. AutoHeight includes it in
|
|
126
|
+
* the unconstrained measure wrapper so the grid grows rather than overlapping.
|
|
127
|
+
* Fixed-height cards keep it *above* the overflow-auto body so hide cannot
|
|
128
|
+
* scroll away. Drag still starts from the strip (outer `.drag-handle`); hide
|
|
129
|
+
* is a `button` + `data-no-drag` so the existing cancel selector ignores it.
|
|
130
|
+
*/
|
|
131
|
+
function GridItemEditorChrome({ id, label, onHide, }) {
|
|
132
|
+
return (_jsxs("div", { "data-slot": "grid-item-editor-chrome", className: "flex min-w-0 flex-none items-center gap-1 px-2 py-1 bg-muted text-muted-foreground", children: [_jsx("span", { className: "min-w-0 truncate text-[10px] px-1.5 py-0.5 rounded-md font-medium", title: label, children: label }), _jsx("button", { type: "button", className: "ml-auto h-6 w-6 shrink-0 rounded-full flex items-center justify-center bg-destructive hover:bg-destructive text-destructive-foreground shadow transition-colors", "data-no-drag": true, onPointerDown: (event) => event.stopPropagation(), onClick: (event) => {
|
|
133
|
+
event.stopPropagation();
|
|
134
|
+
onHide(id);
|
|
135
|
+
}, title: `Hide ${label}`, "aria-label": `Hide ${label}`, children: _jsx(EyeOff, { className: "h-3 w-3", "aria-hidden": "true" }) })] }));
|
|
136
|
+
}
|
|
112
137
|
let warnedAboutCollapsedContent = false;
|
|
113
138
|
function warnOnceAboutCollapsedContent(el) {
|
|
114
139
|
if (warnedAboutCollapsedContent)
|
|
@@ -230,7 +255,9 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
230
255
|
reportRows(contentPx);
|
|
231
256
|
else
|
|
232
257
|
warnOnceAboutCollapsedContent(el);
|
|
233
|
-
|
|
258
|
+
// Re-measure when edit chrome mounts/unmounts so the strip is in the
|
|
259
|
+
// row count in edit mode and gone again on lossless return.
|
|
260
|
+
}, [autoHeight, onAutoHeightChange, reportRows, isEditing]);
|
|
234
261
|
useEffect(() => {
|
|
235
262
|
if (!autoHeight || !onAutoHeightChange)
|
|
236
263
|
return;
|
|
@@ -280,10 +307,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
280
307
|
// (buttons, inputs, textarea, select, links, [data-no-drag]) are still
|
|
281
308
|
// protected via the `cancel` selector below in the <Responsive> render.
|
|
282
309
|
const outerClass = cn('relative group overflow-visible', isEditing && 'drag-handle cursor-move', injectedClassName);
|
|
283
|
-
return (_jsxs("div", { ref: ref, className: outerClass, style: injectedStyle, ...rest, children: [_jsxs("div", { className: "h-full w-full relative", children: [isEditing && (_jsx("div", { className: "absolute inset-0 z-10 pointer-events-none rounded-3xl border-2 border-transparent group-hover:border-primary/50 transition-colors bg-primary/5" })),
|
|
284
|
-
event.stopPropagation();
|
|
285
|
-
onHide(id);
|
|
286
|
-
}, title: `Hide ${label}`, "aria-label": `Hide ${label}`, children: _jsx(EyeOff, { className: "h-3 w-3", "aria-hidden": "true" }) })), _jsx("div", { "data-slot": "grid-item-surface", "data-chrome": chrome ? 'on' : 'off', "data-grid-slot-key": id, className: chrome
|
|
310
|
+
return (_jsxs("div", { ref: ref, className: outerClass, style: injectedStyle, ...rest, children: [_jsxs("div", { className: "h-full w-full relative", children: [isEditing && (_jsx("div", { className: "absolute inset-0 z-10 pointer-events-none rounded-3xl border-2 border-transparent group-hover:border-primary/50 transition-colors bg-primary/5" })), _jsx("div", { "data-slot": "grid-item-surface", "data-chrome": chrome ? 'on' : 'off', "data-grid-slot-key": id, className: chrome
|
|
287
311
|
? // ONE radius token, read by the grid item AND available to any
|
|
288
312
|
// app card that opts into the same surface. Two surfaces
|
|
289
313
|
// reading the SAME var is what makes their corners align, and
|
|
@@ -346,7 +370,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
346
370
|
...(cardStyleVars && '--card-padding' in cardStyleVars
|
|
347
371
|
? { padding: cardStyleVars['--card-padding'] }
|
|
348
372
|
: null),
|
|
349
|
-
}, children: _jsx("div", { className:
|
|
373
|
+
}, children: autoHeight ? (_jsx("div", { "data-slot": "grid-item-body", className: "min-h-0 flex-none overflow-visible", children: _jsxs("div", { ref: measureRef, className: "flow-root", children: [isEditing ? (_jsx(GridItemEditorChrome, { id: id, label: label, onHide: onHide })) : null, scopedContent] }) })) : (_jsxs(_Fragment, { children: [isEditing ? (_jsx(GridItemEditorChrome, { id: id, label: label, onHide: onHide })) : null, _jsx("div", { "data-slot": "grid-item-body", className: "min-h-0 flex-1 overflow-auto", children: scopedContent })] })) })] }), injectedChildren] }));
|
|
350
374
|
}));
|
|
351
375
|
export function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className,
|
|
352
376
|
// Resize default flipped 2026-05-12: rgl v2 dropped auto-handle rendering
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import type { GridLayouts, LayoutMigration, UsePageGridLayoutOptions, UsePageGridLayoutResult } from './types.js';
|
|
2
2
|
export declare const DEFAULT_EDITOR_EVENT_NAMES: readonly ["bsuite-open-page-editor", "bsu-open-page-editor", "crm7-open-page-editor", "conduit-open-page-editor", "r80-open-page-editor"];
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* "Edit Page" button sits in the corner while the editor banner is visible
|
|
9
|
-
* at the top. `detail.editing` is the new state; `detail.pageKey` lets
|
|
10
|
-
* launchers scope by page if they handle multiple grids on one screen.
|
|
4
|
+
* Broadcast after a PageGridLayout commits an editing-state change. Header
|
|
5
|
+
* launchers use this to synchronize their label and restore keyboard focus
|
|
6
|
+
* after canvas controls disappear. Initial state and abandoned transitions do
|
|
7
|
+
* not publish an event. `detail.pageKey` identifies the changed canvas.
|
|
11
8
|
*/
|
|
12
9
|
export declare const PAGE_GRID_EDITING_EVENT = "bsuite-page-grid-editing";
|
|
13
10
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePageGridLayout.d.ts","sourceRoot":"","sources":["../src/usePageGridLayout.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,0BAA0B,2IAM7B,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"usePageGridLayout.d.ts","sourceRoot":"","sources":["../src/usePageGridLayout.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,0BAA0B,2IAM7B,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,6BAA6B,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAiBzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,IAAI,EACJ,EAAE,EACF,UAAU,GACX,EAAE;IACD,KAAK,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,WAAW,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,IAAI,CAAC;CACzD,GAAG,WAAW,GAAG,IAAI,CA+BrB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,cAAc,EACd,WAAgB,EAChB,aAAiB,EACjB,WAAkB,EAClB,gBAA6C,EAC7C,iBAA4C,EAC5C,iBAAiB,EACjB,gBAAgB,GACjB,EAAE,wBAAwB,GAAG,uBAAuB,CAuyBpD"}
|
|
@@ -11,13 +11,10 @@ export const DEFAULT_EDITOR_EVENT_NAMES = [
|
|
|
11
11
|
'r80-open-page-editor',
|
|
12
12
|
];
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* "Edit Page" button sits in the corner while the editor banner is visible
|
|
19
|
-
* at the top. `detail.editing` is the new state; `detail.pageKey` lets
|
|
20
|
-
* launchers scope by page if they handle multiple grids on one screen.
|
|
14
|
+
* Broadcast after a PageGridLayout commits an editing-state change. Header
|
|
15
|
+
* launchers use this to synchronize their label and restore keyboard focus
|
|
16
|
+
* after canvas controls disappear. Initial state and abandoned transitions do
|
|
17
|
+
* not publish an event. `detail.pageKey` identifies the changed canvas.
|
|
21
18
|
*/
|
|
22
19
|
export const PAGE_GRID_EDITING_EVENT = 'bsuite-page-grid-editing';
|
|
23
20
|
/**
|
|
@@ -124,19 +121,16 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
124
121
|
const effectiveLayoutVersion = layoutVersion + PACKAGE_LAYOUT_EPOCH;
|
|
125
122
|
const containerRef = useRef(null);
|
|
126
123
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
127
|
-
const [isEditing,
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return resolved;
|
|
138
|
-
});
|
|
139
|
-
}, [pageKey]);
|
|
124
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
125
|
+
const publishedEditing = useRef(false);
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
if (publishedEditing.current === isEditing)
|
|
128
|
+
return;
|
|
129
|
+
publishedEditing.current = isEditing;
|
|
130
|
+
window.dispatchEvent(new CustomEvent(PAGE_GRID_EDITING_EVENT, {
|
|
131
|
+
detail: { pageKey, editing: isEditing },
|
|
132
|
+
}));
|
|
133
|
+
}, [isEditing, pageKey]);
|
|
140
134
|
const [resetConfirmOpen, setResetConfirmOpen] = useState(false);
|
|
141
135
|
useLayoutEffect(() => {
|
|
142
136
|
const el = containerRef.current;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsuite/page-builder",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.1-next.1",
|
|
4
4
|
"description": "Shared BSuite responsive page-builder grid and layout persistence primitives",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"build": "tsc -p tsconfig.build.json",
|
|
34
34
|
"typecheck": "tsc --noEmit",
|
|
35
35
|
"test": "vitest run",
|
|
36
|
+
"test:geometry": "node scripts/editor-chrome-geometry.mjs",
|
|
36
37
|
"prepublishOnly": "pnpm build"
|
|
37
38
|
},
|
|
38
39
|
"peerDependencies": {
|