@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.
@@ -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,qBAooBrB"}
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"}
@@ -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 items are measured, not manually resized (blueprint
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
- // Measured rows (quality-review design ruling, 2026-07-14) merge
252
- // over the saved/base `h`/`minH` HERE — the render layer — so the
253
- // grid renders full-height cards for every viewer while the saved
254
- // layout (and thus the preference adapter) never sees a measured
255
- // height. Until the first measurement lands, `autoHeightRows` has
256
- // no entry and the item's seed `h` renders as-is.
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
- isResizable: false,
264
- ...(measuredRows !== undefined ? { h: measuredRows, minH: measuredRows } : {}),
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';
@@ -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 is driven by its own measured content
6
- * height rather than manual resize (blueprint amendment A1). `GridItem`
7
- * mounts a `ResizeObserver` on an unconstrained content wrapper and
8
- * reports the computed row count upward via `computeAutoHeightRows`;
9
- * `PageGridLayout` force-sets `isResizable: false` for any item with
10
- * `autoHeight: true` (see the `activeLayouts` memo) so callers don't need
11
- * to remember to set both fields.
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsuite/page-builder",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "description": "Shared BSuite responsive page-builder grid and layout persistence primitives",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",