@bsuite/page-builder 0.5.2 → 0.6.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.
- package/dist/PageEditorLauncher.d.ts +73 -0
- package/dist/PageEditorLauncher.d.ts.map +1 -0
- package/dist/PageEditorLauncher.js +116 -0
- package/dist/PageGridLayout.d.ts.map +1 -1
- package/dist/PageGridLayout.js +33 -12
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +11 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { GridLayouts, WidgetMeta } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Widget configuration accepted by {@link PageEditorLauncher}.
|
|
5
|
+
*
|
|
6
|
+
* A widget is a single renderable card on the canvas — its `key` matches the
|
|
7
|
+
* `i` field of a {@link GridLayouts} item, and `content` is the React node
|
|
8
|
+
* rendered inside the card body.
|
|
9
|
+
*/
|
|
10
|
+
export interface WidgetConfig {
|
|
11
|
+
/** Unique key — must match the `i` field of the corresponding layout item. */
|
|
12
|
+
key: string;
|
|
13
|
+
/** React node rendered inside the card. */
|
|
14
|
+
content: ReactNode;
|
|
15
|
+
/** Optional metadata (label, icon, default size) for the editor banner. */
|
|
16
|
+
meta?: WidgetMeta;
|
|
17
|
+
}
|
|
18
|
+
export interface PageEditorLauncherProps {
|
|
19
|
+
/** The page identifier — used as the `pageKey` for the grid layout persistence. */
|
|
20
|
+
pageId: string;
|
|
21
|
+
/** The tenant identifier — passed through to the consumer's add-widget handler. */
|
|
22
|
+
tenantId: string;
|
|
23
|
+
/** The current set of widgets to render on the canvas. */
|
|
24
|
+
widgets: WidgetConfig[];
|
|
25
|
+
/** Called when the user adds a widget from the palette. */
|
|
26
|
+
onAddWidget: (widget: WidgetConfig) => void;
|
|
27
|
+
/** Called when the user removes a widget from the canvas. */
|
|
28
|
+
onRemoveWidget: (widgetKey: string) => void;
|
|
29
|
+
/** Called with the final layout when the user clicks Save. */
|
|
30
|
+
onSave: (layout: GridLayouts) => void;
|
|
31
|
+
/** Called when the user clicks Cancel or closes the editor. */
|
|
32
|
+
onClose: () => void;
|
|
33
|
+
/** Default layouts for the grid. If omitted, a single empty `lg` layout is used. */
|
|
34
|
+
defaultLayouts?: GridLayouts;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* PageEditorLauncher — framework-agnostic page layout editor.
|
|
38
|
+
*
|
|
39
|
+
* Extracted from crm7's `PageEditorLauncher` (crm7/src/components/platform/
|
|
40
|
+
* PageEditorLauncher.tsx) into the shared `@bsuite/page-builder` package so
|
|
41
|
+
* any consumer app (conduit, BSU, R80) can mount a full drag-and-drop page
|
|
42
|
+
* editor without reimplementing the WidgetPalette drawer, canvas grid, or
|
|
43
|
+
* save/cancel toolbar.
|
|
44
|
+
*
|
|
45
|
+
* Unlike the crm7 original, this component is **headless** with respect to
|
|
46
|
+
* auth/permissions/routing — the consumer app gates mount via its own
|
|
47
|
+
* auth/permission checks and passes the authorised `tenantId`/`pageId`.
|
|
48
|
+
* All crm7-specific imports (supabase client, `useAuth`, `usePermissions`,
|
|
49
|
+
* `useLocation`/wouter, `getCustomPageBySlug`, crm7 stores) have been removed.
|
|
50
|
+
*
|
|
51
|
+
* The editor renders:
|
|
52
|
+
* 1. A **WidgetPalette drawer** (right-side slide-over) for adding widgets.
|
|
53
|
+
* 2. A **canvas grid** (`PageGridLayout` with `canEditPage=true`) for
|
|
54
|
+
* drag-and-drop arrangement.
|
|
55
|
+
* 3. A **save/cancel toolbar** at the top for committing or discarding changes.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* {editMode && (
|
|
60
|
+
* <PageEditorLauncher
|
|
61
|
+
* pageId={`custom-page:${page.id}`}
|
|
62
|
+
* tenantId={tenantId ?? ''}
|
|
63
|
+
* widgets={widgets}
|
|
64
|
+
* onAddWidget={handleAddWidget}
|
|
65
|
+
* onRemoveWidget={handleRemoveWidget}
|
|
66
|
+
* onSave={handleSaveLayout}
|
|
67
|
+
* onClose={() => setEditMode(false)}
|
|
68
|
+
* />
|
|
69
|
+
* )}
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export declare function PageEditorLauncher({ pageId, tenantId, widgets, onAddWidget, onRemoveWidget, onSave, onClose, defaultLayouts, }: PageEditorLauncherProps): import("react").JSX.Element;
|
|
73
|
+
//# sourceMappingURL=PageEditorLauncher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageEditorLauncher.d.ts","sourceRoot":"","sources":["../src/PageEditorLauncher.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAI/E,OAAO,KAAK,EACV,WAAW,EAGX,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAC;IACZ,2CAA2C;IAC3C,OAAO,EAAE,SAAS,CAAC;IACnB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,mFAAmF;IACnF,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,2DAA2D;IAC3D,WAAW,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,6DAA6D;IAC7D,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,8DAA8D;IAC9D,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,+DAA+D;IAC/D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oFAAoF;IACpF,cAAc,CAAC,EAAE,WAAW,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,OAAO,EACP,WAAW,EACX,cAAc,EACd,MAAM,EACN,OAAO,EACP,cAAc,GACf,EAAE,uBAAuB,+BAmPzB"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { LayoutGrid, Plus, Save, X } from 'lucide-react';
|
|
4
|
+
import { PageGridLayout } from './PageGridLayout.js';
|
|
5
|
+
import { useLocalPreference } from './preferences.js';
|
|
6
|
+
/**
|
|
7
|
+
* PageEditorLauncher — framework-agnostic page layout editor.
|
|
8
|
+
*
|
|
9
|
+
* Extracted from crm7's `PageEditorLauncher` (crm7/src/components/platform/
|
|
10
|
+
* PageEditorLauncher.tsx) into the shared `@bsuite/page-builder` package so
|
|
11
|
+
* any consumer app (conduit, BSU, R80) can mount a full drag-and-drop page
|
|
12
|
+
* editor without reimplementing the WidgetPalette drawer, canvas grid, or
|
|
13
|
+
* save/cancel toolbar.
|
|
14
|
+
*
|
|
15
|
+
* Unlike the crm7 original, this component is **headless** with respect to
|
|
16
|
+
* auth/permissions/routing — the consumer app gates mount via its own
|
|
17
|
+
* auth/permission checks and passes the authorised `tenantId`/`pageId`.
|
|
18
|
+
* All crm7-specific imports (supabase client, `useAuth`, `usePermissions`,
|
|
19
|
+
* `useLocation`/wouter, `getCustomPageBySlug`, crm7 stores) have been removed.
|
|
20
|
+
*
|
|
21
|
+
* The editor renders:
|
|
22
|
+
* 1. A **WidgetPalette drawer** (right-side slide-over) for adding widgets.
|
|
23
|
+
* 2. A **canvas grid** (`PageGridLayout` with `canEditPage=true`) for
|
|
24
|
+
* drag-and-drop arrangement.
|
|
25
|
+
* 3. A **save/cancel toolbar** at the top for committing or discarding changes.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* {editMode && (
|
|
30
|
+
* <PageEditorLauncher
|
|
31
|
+
* pageId={`custom-page:${page.id}`}
|
|
32
|
+
* tenantId={tenantId ?? ''}
|
|
33
|
+
* widgets={widgets}
|
|
34
|
+
* onAddWidget={handleAddWidget}
|
|
35
|
+
* onRemoveWidget={handleRemoveWidget}
|
|
36
|
+
* onSave={handleSaveLayout}
|
|
37
|
+
* onClose={() => setEditMode(false)}
|
|
38
|
+
* />
|
|
39
|
+
* )}
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function PageEditorLauncher({ pageId, tenantId, widgets, onAddWidget, onRemoveWidget, onSave, onClose, defaultLayouts, }) {
|
|
43
|
+
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
44
|
+
// Track the latest layout in a ref so the Save handler can read it.
|
|
45
|
+
// The grid's preference adapter writes to this ref via the custom factory
|
|
46
|
+
// below, and Save reads from it — no localStorage coupling required.
|
|
47
|
+
const layoutRef = useRef(defaultLayouts ?? { lg: [] });
|
|
48
|
+
// Custom preference adapter factory: wraps `useLocalPreference` (so the
|
|
49
|
+
// grid still persists to localStorage for the session) and also captures
|
|
50
|
+
// the layout value in `layoutRef` whenever the `_grid_layouts` key changes.
|
|
51
|
+
// This is the seam that lets `onSave` emit the final layout without
|
|
52
|
+
// reaching into localStorage directly.
|
|
53
|
+
const capturedAdapter = useCallback((key, fallback) => {
|
|
54
|
+
const adapter = useLocalPreference(key, fallback);
|
|
55
|
+
// Track the layouts key so Save can read the ref.
|
|
56
|
+
if (key.endsWith('_grid_layouts')) {
|
|
57
|
+
const originalSetValue = adapter.setValue;
|
|
58
|
+
const wrappedSetValue = useCallback((next) => {
|
|
59
|
+
originalSetValue((previous) => {
|
|
60
|
+
const resolved = typeof next === 'function'
|
|
61
|
+
? next(previous)
|
|
62
|
+
: next;
|
|
63
|
+
layoutRef.current = resolved;
|
|
64
|
+
return resolved;
|
|
65
|
+
});
|
|
66
|
+
}, [originalSetValue]);
|
|
67
|
+
// Also capture the initial value.
|
|
68
|
+
layoutRef.current = adapter.value;
|
|
69
|
+
return { ...adapter, setValue: wrappedSetValue };
|
|
70
|
+
}
|
|
71
|
+
return adapter;
|
|
72
|
+
}, []);
|
|
73
|
+
// Build the `widgets` record expected by PageGridLayout from the WidgetConfig[].
|
|
74
|
+
const gridWidgets = useMemo(() => {
|
|
75
|
+
const record = {};
|
|
76
|
+
for (const w of widgets) {
|
|
77
|
+
record[w.key] = w.content;
|
|
78
|
+
}
|
|
79
|
+
return record;
|
|
80
|
+
}, [widgets]);
|
|
81
|
+
// Build the `widgetMeta` record for the editor banner labels.
|
|
82
|
+
const gridWidgetMeta = useMemo(() => {
|
|
83
|
+
const record = {};
|
|
84
|
+
for (const w of widgets) {
|
|
85
|
+
if (w.meta)
|
|
86
|
+
record[w.key] = w.meta;
|
|
87
|
+
}
|
|
88
|
+
return record;
|
|
89
|
+
}, [widgets]);
|
|
90
|
+
const handleSave = useCallback(() => {
|
|
91
|
+
onSave(layoutRef.current);
|
|
92
|
+
onClose();
|
|
93
|
+
}, [onSave, onClose]);
|
|
94
|
+
const handleCancel = useCallback(() => {
|
|
95
|
+
onClose();
|
|
96
|
+
}, [onClose]);
|
|
97
|
+
// The palette calls this when the user picks a widget to add.
|
|
98
|
+
const handlePaletteAdd = useCallback((widgetType) => {
|
|
99
|
+
// Delegate to the consumer's onAddWidget — the consumer knows how to
|
|
100
|
+
// resolve a widget type string into a WidgetConfig (entity table,
|
|
101
|
+
// built-in, custom, etc.). This is the framework-agnostic seam: crm7
|
|
102
|
+
// resolved this via its widget registry + supabase; conduit resolves it
|
|
103
|
+
// via its own widget catalogue.
|
|
104
|
+
onAddWidget({
|
|
105
|
+
key: widgetType,
|
|
106
|
+
content: null,
|
|
107
|
+
meta: { label: widgetType },
|
|
108
|
+
});
|
|
109
|
+
setPaletteOpen(false);
|
|
110
|
+
}, [onAddWidget]);
|
|
111
|
+
// tenantId is passed through to onAddWidget via the consumer's handler;
|
|
112
|
+
// reference it here to avoid an unused-variable lint at the call site.
|
|
113
|
+
void tenantId;
|
|
114
|
+
const effectiveDefaultLayouts = defaultLayouts ?? { lg: [] };
|
|
115
|
+
return (_jsxs("div", { className: "relative isolate", children: [_jsx("div", { className: "sticky top-0 z-40 isolate flex flex-col gap-3 rounded-xl shadow-lg border-2 mb-4 p-4 bg-card/95 supports-[backdrop-filter]:bg-card/80 backdrop-blur border-primary", role: "region", "aria-label": "Page editor toolbar", children: _jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "rounded-full flex items-center justify-center bg-primary/10 h-10 w-10 animate-pulse", children: _jsx(LayoutGrid, { className: "h-5 w-5 text-primary" }) }), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold text-foreground text-lg", children: "Page Editor" }), _jsx("span", { className: "text-sm text-muted-foreground", children: "Drag cards to rearrange. Resize with the bottom-right handle." })] })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded-md border border-border px-3 py-2 text-sm font-medium transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", onClick: () => setPaletteOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Add Widget"] }), _jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded-md border border-border px-3 py-2 text-sm font-medium transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", onClick: handleCancel, children: [_jsx(X, { className: "h-4 w-4" }), "Cancel"] }), _jsxs("button", { type: "button", className: "inline-flex items-center rounded-md px-3 py-2 text-sm font-medium bg-primary text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", onClick: handleSave, children: [_jsx(Save, { className: "h-4 w-4 mr-2" }), "Save"] })] })] }) }), _jsx(PageGridLayout, { pageKey: pageId, defaultLayouts: effectiveDefaultLayouts, canEditPage: true, preferenceAdapter: capturedAdapter, widgets: gridWidgets, widgetMeta: gridWidgetMeta }), paletteOpen && (_jsxs("div", { className: "fixed inset-0 z-50 flex", children: [_jsx("div", { className: "absolute inset-0 bg-black/40", onClick: () => setPaletteOpen(false), "aria-hidden": "true" }), _jsxs("div", { className: "relative ml-auto h-full w-80 max-w-[85vw] flex flex-col bg-card border-l border-border shadow-xl", children: [_jsxs("div", { className: "flex items-center justify-between px-4 pt-4 pb-3 border-b", children: [_jsx("h2", { className: "text-base font-semibold", children: "Add Widget" }), _jsx("button", { type: "button", className: "rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", onClick: () => setPaletteOpen(false), "aria-label": "Close widget palette", children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-4", children: [widgets.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground text-center py-8", children: "No widgets available. Add widgets via your app's widget catalogue." })) : (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground px-1", children: "Available Widgets" }), widgets.map((w) => (_jsxs("div", { className: "flex items-center justify-between rounded-md border bg-card p-3 hover:bg-accent/50 transition-colors", children: [_jsx("span", { className: "text-sm font-medium truncate", children: w.meta?.label ?? w.key }), _jsx("button", { type: "button", className: "ml-2 shrink-0 inline-flex items-center rounded-md px-2 py-1 text-xs font-medium bg-secondary text-secondary-foreground transition-colors hover:bg-secondary/80", onClick: () => handlePaletteAdd(w.key), children: "Add" })] }, w.key)))] })), _jsxs("div", { className: "border-t border-border pt-4 space-y-2", children: [_jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground px-1", children: "Remove Widget" }), widgets.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground px-1", children: "No widgets on the canvas to remove." })) : (widgets.map((w) => (_jsxs("div", { className: "flex items-center justify-between rounded-md border bg-card p-3", children: [_jsx("span", { className: "text-sm font-medium truncate", children: w.meta?.label ?? w.key }), _jsx("button", { type: "button", className: "ml-2 shrink-0 inline-flex items-center rounded-md px-2 py-1 text-xs font-medium bg-destructive/10 text-destructive transition-colors hover:bg-destructive/20", onClick: () => onRemoveWidget(w.key), children: "Remove" })] }, `remove-${w.key}`))))] })] })] })] }))] }));
|
|
116
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAA6E,MAAM,OAAO,CAAC;AAGlG,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,YAAY,CAAC;AA0QnE,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,
|
|
1
|
+
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAA6E,MAAM,OAAO,CAAC;AAGlG,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAe,mBAAmB,EAAE,MAAM,YAAY,CAAC;AA0QnE,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,qBAwpBrB"}
|
package/dist/PageGridLayout.js
CHANGED
|
@@ -243,25 +243,46 @@ isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, addEntityWidgetEvent
|
|
|
243
243
|
for (const bp in currentLayouts) {
|
|
244
244
|
filtered[bp] = (currentLayouts[bp] ?? [])
|
|
245
245
|
.filter((item) => renderableWidgetKeys.has(item.i) && !hiddenLayerIds[item.i])
|
|
246
|
-
// autoHeight
|
|
247
|
-
// amendment A1) — force isResizable: false centrally here so every
|
|
248
|
-
// call site that sets autoHeight: true gets this for free, rather
|
|
249
|
-
// than needing to remember to also set isResizable itself.
|
|
246
|
+
// autoHeight is a FLOOR, not a lock.
|
|
250
247
|
//
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
248
|
+
// This block used to force `isResizable: false` on every autoHeight
|
|
249
|
+
// item and overwrite `h` with the measured height. Between them those
|
|
250
|
+
// two lines removed card resizing from every page whose cards use the
|
|
251
|
+
// default `autoHeight: true` — the force-disable killed the handles,
|
|
252
|
+
// and the unconditional `h` overwrite would have stomped any height a
|
|
253
|
+
// user did manage to set on the next measurement.
|
|
254
|
+
//
|
|
255
|
+
// Resizable cards are an operator-mandated platform capability
|
|
256
|
+
// (Braden, 2026-07-31: "no ruling has ever had my authority to
|
|
257
|
+
// suppress resizing"). The earlier internal note that traded resize
|
|
258
|
+
// away to stop a 192px clipping regression posed a false choice. Both
|
|
259
|
+
// properties hold at once:
|
|
260
|
+
//
|
|
261
|
+
// minH = measuredRows -> a card can never be dragged shorter than
|
|
262
|
+
// its content, so the clipping regression
|
|
263
|
+
// that motivated the original change stays
|
|
264
|
+
// fixed.
|
|
265
|
+
// h = max(saved, measured)
|
|
266
|
+
// -> content is never clipped, AND a height the
|
|
267
|
+
// user deliberately set is preserved instead
|
|
268
|
+
// of being reset on every re-measure.
|
|
269
|
+
// isResizable untouched -> inherits the grid default (true), so the
|
|
270
|
+
// handles are present.
|
|
271
|
+
//
|
|
272
|
+
// Measured rows still merge at the RENDER layer only, so the saved
|
|
273
|
+
// layout (and the preference adapter) never sees a measured height.
|
|
274
|
+
// Until the first measurement lands, `autoHeightRows` has no entry and
|
|
275
|
+
// the item's seed `h` renders as-is.
|
|
257
276
|
.map((item) => {
|
|
258
277
|
if (!item.autoHeight)
|
|
259
278
|
return item;
|
|
260
279
|
const measuredRows = autoHeightRows[item.i];
|
|
280
|
+
if (measuredRows === undefined)
|
|
281
|
+
return item;
|
|
261
282
|
return {
|
|
262
283
|
...item,
|
|
263
|
-
|
|
264
|
-
|
|
284
|
+
h: Math.max(item.h ?? 0, measuredRows),
|
|
285
|
+
minH: measuredRows,
|
|
265
286
|
};
|
|
266
287
|
});
|
|
267
288
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { PageGridLayout } from './PageGridLayout.js';
|
|
2
|
+
export { PageEditorLauncher } from './PageEditorLauncher.js';
|
|
3
|
+
export type { WidgetConfig, PageEditorLauncherProps } from './PageEditorLauncher.js';
|
|
2
4
|
export { usePageGridLayout, DEFAULT_EDITOR_EVENT_NAMES, PAGE_GRID_EDITING_EVENT, } from './usePageGridLayout.js';
|
|
3
5
|
export type { PageGridEditingEventDetail } from './usePageGridLayout.js';
|
|
4
6
|
export { rescaleLayout } from './rescaleLayout.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAChF,YAAY,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,YAAY,EAAE,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,8BAA8B,EAC9B,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,gBAAgB,EAChB,sBAAsB,EACtB,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,6BAA6B,EAC7B,oBAAoB,GACrB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAChF,YAAY,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { PageGridLayout } from './PageGridLayout.js';
|
|
2
|
+
export { PageEditorLauncher } from './PageEditorLauncher.js';
|
|
2
3
|
export { usePageGridLayout, DEFAULT_EDITOR_EVENT_NAMES, PAGE_GRID_EDITING_EVENT, } from './usePageGridLayout.js';
|
|
3
4
|
export { rescaleLayout } from './rescaleLayout.js';
|
|
4
5
|
export { computeAutoHeightRows } from './autoHeight.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -2,13 +2,17 @@ import type React from 'react';
|
|
|
2
2
|
import type { Compactor, LayoutItem, ResizeHandleAxis } from 'react-grid-layout';
|
|
3
3
|
export interface GridLayoutItem extends LayoutItem {
|
|
4
4
|
/**
|
|
5
|
-
* When true, this item's height
|
|
6
|
-
* height
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
5
|
+
* When true, this item's measured content height acts as a FLOOR on its
|
|
6
|
+
* height — it is not a substitute for manual resize. `GridItem` mounts a
|
|
7
|
+
* `ResizeObserver` on an unconstrained content wrapper and reports the
|
|
8
|
+
* computed row count upward via `computeAutoHeightRows`; `PageGridLayout`
|
|
9
|
+
* then applies it as `minH` (never clip content) while keeping `h` at
|
|
10
|
+
* `max(saved, measured)` (never discard a height the user chose).
|
|
11
|
+
*
|
|
12
|
+
* `autoHeight` does NOT disable resizing. It previously force-set
|
|
13
|
+
* `isResizable: false`, which removed card resizing from every page using
|
|
14
|
+
* the default — corrected 2026-07-31; resizable cards are an
|
|
15
|
+
* operator-mandated capability. See the `activeLayouts` memo.
|
|
12
16
|
*/
|
|
13
17
|
autoHeight?: boolean;
|
|
14
18
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEjF,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|