@bsuite/page-builder 0.3.0 → 0.4.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAIA,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAIxC,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAIA,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAIxC,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,YAAY,CAAC;AA+KnE,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,yBAAiE,EACjE,kBAAkB,EAClB,sBAAsB,GACvB,EAAE,mBAAmB,2CA+frB"}
|
package/dist/PageGridLayout.js
CHANGED
|
@@ -2,24 +2,31 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { ArrowDown, ArrowUp, Eye, EyeOff, Layers, LayoutGrid, Lock, Plus, RotateCcw, Save, Settings2, Unlock } from 'lucide-react';
|
|
3
3
|
import React, { startTransition, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
4
|
import { Responsive } from 'react-grid-layout';
|
|
5
|
-
import { gridBounds,
|
|
5
|
+
import { gridBounds, minMaxSize, minSize } from 'react-grid-layout/core';
|
|
6
6
|
import 'react-grid-layout/css/styles.css';
|
|
7
7
|
import 'react-resizable/css/styles.css';
|
|
8
8
|
import { defaultPreferenceAdapter } from './preferences.js';
|
|
9
9
|
import { usePageGridLayout } from './usePageGridLayout.js';
|
|
10
10
|
import { cn } from './utils.js';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Default resize bounds applied as a *global* constraint to ALL grid items.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
14
|
+
* History
|
|
15
|
+
* -------
|
|
16
|
+
* - 0.2.x: maxH=16 (≈512px) — clipped data tables.
|
|
17
|
+
* - 0.3.0: bumped to maxH=48 (≈1536px) — still a hard ceiling. Operators
|
|
18
|
+
* reported "the handle hits a wall before all my data fits" on tall
|
|
19
|
+
* data-table cards even after the bump.
|
|
20
|
+
* - 0.4.0 (this version): **removed the global maxW and maxH ceilings
|
|
21
|
+
* entirely.** Width is bounded by `gridBounds` (the active column count)
|
|
22
|
+
* so no separate global `maxSize(...)` is needed; per-item
|
|
23
|
+
* `LayoutItem.maxW` / `maxH` is honoured via `minMaxSize`. Combined
|
|
24
|
+
* with the new internal scroll wrapper around `{content}` (see GridItem
|
|
25
|
+
* render below), cards now grow to their bounds and content scrolls
|
|
26
|
+
* inside. Per-item `maxH` on `LayoutItem` remains the right knob for
|
|
27
|
+
* "this widget shouldn't grow past N rows".
|
|
21
28
|
*/
|
|
22
|
-
const DEFAULT_RESIZE_BOUNDS = { minW: 2, minH: 1
|
|
29
|
+
const DEFAULT_RESIZE_BOUNDS = { minW: 2, minH: 1 };
|
|
23
30
|
const DEFAULT_RESIZE_HANDLES = ['se'];
|
|
24
31
|
const DEFAULT_ADD_ENTITY_WIDGET_EVENT_NAMES = ['bsu-add-entity-widget', 'crm7-add-entity-widget'];
|
|
25
32
|
/**
|
|
@@ -62,11 +69,11 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
62
69
|
// the GridItem has it as an ancestor → drag fires. Interactive elements
|
|
63
70
|
// (buttons, inputs, textarea, select, links, [data-no-drag]) are still
|
|
64
71
|
// protected via the `cancel` selector below in the <Responsive> render.
|
|
65
|
-
const outerClass = cn('relative group', isEditing && 'drag-handle cursor-move', injectedClassName);
|
|
72
|
+
const outerClass = cn('relative group overflow-visible', isEditing && 'drag-handle cursor-move', injectedClassName);
|
|
66
73
|
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-black/5" })), isEditing && (_jsx("div", { className: "absolute top-2 left-2 z-30 flex items-center gap-1 pointer-events-none", children: _jsx("span", { className: "text-[10px] px-1.5 py-0.5 rounded-md opacity-80 font-medium bg-muted text-muted-foreground", children: label }) })), isEditing && (_jsx("button", { className: "absolute top-2 right-2 z-30 h-6 w-6 rounded-full flex items-center justify-center bg-destructive/80 hover:bg-destructive text-white shadow transition-colors", "data-no-drag": true, onPointerDown: (event) => event.stopPropagation(), onClick: (event) => {
|
|
67
74
|
event.stopPropagation();
|
|
68
75
|
onHide(id);
|
|
69
|
-
}, title: `Hide ${label}`, "aria-label": `Hide ${label}`, children: _jsx(EyeOff, { className: "h-3 w-3", "aria-hidden": "true" }) })), _jsx("div", { className: "h-full w-full rounded-3xl transition-all flex flex-col bg-card shadow-sm", style: { contain: '
|
|
76
|
+
}, title: `Hide ${label}`, "aria-label": `Hide ${label}`, children: _jsx(EyeOff, { className: "h-3 w-3", "aria-hidden": "true" }) })), _jsx("div", { className: "h-full w-full rounded-3xl transition-all flex flex-col bg-card shadow-sm", style: { contain: 'layout style' }, children: _jsx("div", { className: "flex-1 min-h-0 overflow-auto", children: content }) })] }), injectedChildren] }));
|
|
70
77
|
}));
|
|
71
78
|
export function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className,
|
|
72
79
|
// Resize default flipped 2026-05-12: rgl v2 dropped auto-handle rendering
|
|
@@ -86,10 +93,13 @@ isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, addEntityWidgetEvent
|
|
|
86
93
|
});
|
|
87
94
|
const resizeEnabled = isEditing && isResizable;
|
|
88
95
|
const resizeConstraints = useMemo(() => [
|
|
96
|
+
// `gridBounds` caps width at the active column count, so we don't need
|
|
97
|
+
// a global maxSize(...). Width and height are unbounded by default;
|
|
98
|
+
// consumers cap individual widgets via LayoutItem.maxW / maxH which
|
|
99
|
+
// `minMaxSize` reads per-item.
|
|
89
100
|
gridBounds,
|
|
90
101
|
minMaxSize,
|
|
91
102
|
minSize(DEFAULT_RESIZE_BOUNDS.minW, DEFAULT_RESIZE_BOUNDS.minH),
|
|
92
|
-
maxSize(DEFAULT_RESIZE_BOUNDS.maxW, DEFAULT_RESIZE_BOUNDS.maxH),
|
|
93
103
|
], []);
|
|
94
104
|
const [extraWidgetConfigs, setExtraWidgetConfigs] = useState({});
|
|
95
105
|
const { value: layerNames, setValue: setLayerNames } = (preferenceAdapter ?? defaultPreferenceAdapter)(`page:${pageKey}_grid_layer_names`, {});
|
|
@@ -244,12 +254,12 @@ isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, addEntityWidgetEvent
|
|
|
244
254
|
previousActiveElement?.focus?.();
|
|
245
255
|
};
|
|
246
256
|
}, [resetConfirmOpen]);
|
|
247
|
-
return (_jsxs("div", { className: className, children: [isEditing && (_jsxs("div", { className: cn(
|
|
257
|
+
return (_jsxs("div", { className: cn('relative', isEditing && 'isolate', className), children: [isEditing && (_jsxs("div", { "data-page-grid-editor-controls": true, className: cn(
|
|
248
258
|
// Sticky overlay banner — sits at the top of the scroll container
|
|
249
259
|
// without pushing the form down. `top-0` anchors to the nearest
|
|
250
|
-
// scrolling ancestor; `z-
|
|
260
|
+
// scrolling ancestor; `z-40` keeps it above grid items but below
|
|
251
261
|
// app-level overlays (toaster, dialogs are z-50+).
|
|
252
|
-
'sticky top-0 z-
|
|
262
|
+
'sticky top-0 z-40 isolate flex flex-col gap-3 p-4 rounded-xl shadow-lg border-2 mb-4',
|
|
253
263
|
// Subtle translucent background so the form behind it stays
|
|
254
264
|
// partially visible — mitigates Issue 2 (banner consuming
|
|
255
265
|
// vertical space). `bg-card/95` + `backdrop-blur` keeps text
|
|
@@ -261,7 +271,7 @@ isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, addEntityWidgetEvent
|
|
|
261
271
|
}) })] })), layerItems.length > 0 && (_jsxs("div", { className: "basis-full rounded-md border border-border bg-background/80 p-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: [_jsx(Layers, { className: "h-3.5 w-3.5" }), "Layers"] }), _jsx("div", { className: "flex flex-col gap-1", children: layerItems.map((layer) => (_jsxs("div", { className: "flex items-center gap-1 rounded border border-border bg-card px-2 py-1", children: [_jsx("input", { type: "text", value: layer.label, onChange: (event) => handleLayerRename(layer.id, event.target.value), className: "min-w-0 flex-1 bg-transparent text-xs text-foreground outline-none", "aria-label": `Rename ${layer.label}` }), _jsx("button", { type: "button", onClick: () => moveWidget(layer.id, 'up'), disabled: !layer.canMoveUp, "aria-label": `Move ${layer.label} up`, className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40", children: _jsx(ArrowUp, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", onClick: () => moveWidget(layer.id, 'down'), disabled: !layer.canMoveDown, "aria-label": `Move ${layer.label} down`, className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-40", children: _jsx(ArrowDown, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", onClick: () => setWidgetLocked(layer.id, !layer.locked), "aria-label": `${layer.locked ? 'Unlock' : 'Lock'} ${layer.label}`, className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", children: layer.locked ? _jsx(Lock, { className: "h-3.5 w-3.5" }) : _jsx(Unlock, { className: "h-3.5 w-3.5" }) }), _jsx("button", { type: "button", onClick: () => hideLayer(layer.id), "aria-label": `Hide ${layer.label}`, className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", children: _jsx(EyeOff, { className: "h-3.5 w-3.5" }) })] }, layer.id))) })] })), _jsxs("button", { type: "button", onClick: handleCompact, className: cn('ml-auto inline-flex items-center rounded-md border border-border px-2 py-1 text-sm transition-colors', 'text-muted-foreground hover:bg-muted hover:text-foreground', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1'), children: [_jsx(Layers, { className: "h-4 w-4 mr-1" }), "Compact Layout"] }), _jsxs("button", { type: "button", onClick: () => setResetConfirmOpen(true), className: cn('inline-flex items-center rounded-md border border-border px-2 py-1 text-sm transition-colors', 'text-muted-foreground hover:bg-muted hover:text-foreground', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1'), children: [_jsx(RotateCcw, { className: "h-4 w-4 mr-1" }), "Reset to Default"] })] })] })), resetConfirmOpen && (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", role: "dialog", "aria-modal": "true", "aria-labelledby": "page-grid-reset-title", "aria-describedby": "page-grid-reset-description", children: _jsxs("div", { className: "max-w-md rounded-lg bg-card p-5 shadow-lg border border-border", children: [_jsx("h2", { id: "page-grid-reset-title", className: "text-lg font-semibold", children: "Reset page layout?" }), _jsx("p", { id: "page-grid-reset-description", className: "mt-2 text-sm text-muted-foreground", children: "This will discard your current layout and restore all widgets to their default positions." }), _jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [_jsx("button", { type: "button", ref: resetCancelButtonRef, onClick: () => setResetConfirmOpen(false), className: cn('inline-flex items-center rounded-md border border-border px-3 py-2 text-sm transition-colors', 'bg-card text-foreground hover:bg-muted hover:text-foreground', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1'), children: "Cancel" }), _jsx("button", { type: "button", ref: resetConfirmButtonRef, onClick: () => {
|
|
262
272
|
handleReset();
|
|
263
273
|
setResetConfirmOpen(false);
|
|
264
|
-
}, className: cn('inline-flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors', 'bg-destructive text-white shadow hover:bg-destructive/90', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive/40 focus-visible:ring-offset-1'), children: "Reset to Default" })] })] }) })), _jsx("div", { ref: containerRef, className: isEditing
|
|
274
|
+
}, className: cn('inline-flex items-center rounded-md px-3 py-2 text-sm font-medium transition-colors', 'bg-destructive text-white shadow hover:bg-destructive/90', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive/40 focus-visible:ring-offset-1'), children: "Reset to Default" })] })] }) })), _jsx("div", { ref: containerRef, className: cn('relative z-0 overflow-visible', isEditing && 'min-h-[200px] bg-muted/30'), "data-page-grid-editing": isEditing || undefined, children: _jsx("div", { className: "relative z-0", style: { opacity: containerWidth > 0 ? 1 : 0 }, "aria-busy": containerWidth <= 0, children: _jsx(Responsive, { width: Math.max(containerWidth, 1), className: "layout page-grid-canvas", layouts: activeLayouts, breakpoints: { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }, rowHeight: 32, onLayoutChange: onLayoutChange, dragConfig: {
|
|
265
275
|
enabled: isEditing,
|
|
266
276
|
handle: '.drag-handle',
|
|
267
277
|
bounded: false,
|
package/package.json
CHANGED
|
@@ -14,11 +14,24 @@
|
|
|
14
14
|
|
|
15
15
|
.react-grid-layout {
|
|
16
16
|
position: relative;
|
|
17
|
+
isolation: isolate;
|
|
17
18
|
transition: height 200ms ease;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
.react-grid-item {
|
|
22
|
+
overflow: visible;
|
|
21
23
|
transition: transform 200ms ease, width 200ms ease, height 200ms ease;
|
|
24
|
+
z-index: 1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.react-grid-layout .react-grid-item.react-draggable-dragging,
|
|
28
|
+
.react-grid-layout .react-grid-item.resizing {
|
|
29
|
+
z-index: 20;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.react-grid-layout .react-grid-item.react-grid-placeholder {
|
|
33
|
+
z-index: 0;
|
|
34
|
+
pointer-events: none;
|
|
22
35
|
}
|
|
23
36
|
|
|
24
37
|
.react-grid-item.react-grid-placeholder {
|