@bsuite/page-builder 1.0.6 → 1.1.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/CanvasCard.d.ts +8 -1
- package/dist/CanvasCard.d.ts.map +1 -1
- package/dist/DraggableCardPage.d.ts +8 -0
- package/dist/DraggableCardPage.d.ts.map +1 -1
- package/dist/PageGridLayout.d.ts +1 -1
- package/dist/PageGridLayout.d.ts.map +1 -1
- package/dist/PageGridLayout.js +20 -4
- package/dist/canvasCardLayout.d.ts +23 -1
- package/dist/canvasCardLayout.d.ts.map +1 -1
- package/dist/canvasCardLayout.js +23 -2
- package/dist/cardSurfaces.stories.d.ts +62 -0
- package/dist/cardSurfaces.stories.d.ts.map +1 -0
- package/dist/cardSurfaces.stories.js +76 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/scanner/cardSurfaceScanner.d.ts +101 -1
- package/dist/scanner/cardSurfaceScanner.d.ts.map +1 -1
- package/dist/scanner/cardSurfaceScanner.js +355 -6
- package/dist/scanner/index.d.ts +1 -1
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/scanner/index.js +1 -1
- package/dist/types.d.ts +20 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/usePageGridLayout.d.ts +8 -1
- package/dist/usePageGridLayout.d.ts.map +1 -1
- package/dist/usePageGridLayout.js +31 -70
- package/package.json +1 -1
package/dist/CanvasCard.d.ts
CHANGED
|
@@ -2,7 +2,14 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
export interface CanvasCardProps {
|
|
3
3
|
/** Stable widget key used by PageGridLayout for layout persistence. Required. */
|
|
4
4
|
cardKey: string;
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Grid width in columns on the 12-column grid.
|
|
7
|
+
*
|
|
8
|
+
* Defaults to **6** — half the grid, two cards per row. It defaulted to 12
|
|
9
|
+
* up to 1.0.7, which meant every card that omitted `w` rendered full width
|
|
10
|
+
* and stacked; 1,068 of 1,729 usages across the estate omit it. Say `w={12}`
|
|
11
|
+
* when a card genuinely wants the full row.
|
|
12
|
+
*/
|
|
6
13
|
w?: 2 | 3 | 4 | 6 | 8 | 12;
|
|
7
14
|
/** Minimum width in columns when the user resizes. Defaults to 4. */
|
|
8
15
|
minW?: 2 | 3 | 4 | 6 | 8 | 12;
|
package/dist/CanvasCard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasCard.d.ts","sourceRoot":"","sources":["../src/CanvasCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB
|
|
1
|
+
{"version":3,"file":"CanvasCard.d.ts","sourceRoot":"","sources":["../src/CanvasCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,eAAe;IAC9B,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC3B,qEAAqE;IACrE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAC9B,4FAA4F;IAC5F,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kEAAkE;IAClE,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAExD;yBAFe,UAAU"}
|
|
@@ -105,6 +105,14 @@ export type DraggableCardPageProps = Omit<PageGridLayoutProps, 'widgets' | 'defa
|
|
|
105
105
|
* the element it toggles was never mounted.
|
|
106
106
|
*/
|
|
107
107
|
onDroppedChildren?: (dropped: string[], pageKey: string) => void;
|
|
108
|
+
/**
|
|
109
|
+
* Width, in grid columns, for cards that do not set `w` themselves.
|
|
110
|
+
*
|
|
111
|
+
* Defaults to `DEFAULT_CANVAS_CARD_WIDTH` (6 — half the grid, two cards per
|
|
112
|
+
* row) as of 1.1.0. Pass 12 to restore the pre-1.1.0 full-width stack while
|
|
113
|
+
* an app migrates its pages.
|
|
114
|
+
*/
|
|
115
|
+
defaultCardWidth?: number;
|
|
108
116
|
/**
|
|
109
117
|
* CanvasCard children. Falsy entries are ignored. Fragments are flattened so
|
|
110
118
|
* a conditional multi-card branch still registers each CanvasCard.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DraggableCardPage.d.ts","sourceRoot":"","sources":["../src/DraggableCardPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,mBAAmB,EACnB,SAAS,GAAG,gBAAgB,CAC7B,GAAG;IACF;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACnD;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAgCF,wBAAgB,iBAAiB,CAAC,EAChC,WAAe,EACf,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,sBAAsB,+BA2BxB;yBAjCe,iBAAiB"}
|
|
1
|
+
{"version":3,"file":"DraggableCardPage.d.ts","sourceRoot":"","sources":["../src/DraggableCardPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AAEH,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGpE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,mBAAmB,EACnB,SAAS,GAAG,gBAAgB,CAC7B,GAAG;IACF;;;;;;;;;;;;;;;;;;;OAmBG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACnD;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjE;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAgCF,wBAAgB,iBAAiB,CAAC,EAChC,WAAe,EACf,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACR,GAAG,SAAS,EACb,EAAE,sBAAsB,+BA2BxB;yBAjCe,iBAAiB"}
|
package/dist/PageGridLayout.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import React from 'react';
|
|
|
2
2
|
import 'react-grid-layout/css/styles.css';
|
|
3
3
|
import 'react-resizable/css/styles.css';
|
|
4
4
|
import type { PageGridLayoutProps } from './types.js';
|
|
5
|
-
export declare function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className, isResizable, resizeHandles, tenantId, defaultAutoHeight, addEntityWidgetEventNames, createEntityWidget, onRegisterEntityWidget, relationshipCatalog, addRelationshipWidgetEventNames, createRelationshipWidget, onRegisterRelationshipWidget, onRelationshipWidgetRejected, }: PageGridLayoutProps): React.JSX.Element;
|
|
5
|
+
export declare function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className, isResizable, resizeHandles, tenantId, defaultAutoHeight, itemChrome, addEntityWidgetEventNames, createEntityWidget, onRegisterEntityWidget, relationshipCatalog, addRelationshipWidgetEventNames, createRelationshipWidget, onRegisterRelationshipWidget, onRelationshipWidgetRejected, }: PageGridLayoutProps): React.JSX.Element;
|
|
6
6
|
//# sourceMappingURL=PageGridLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAMxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAMxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;AA4W7F,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,EAKjB,UAAkB,EAClB,yBAAiE,EACjE,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,+BAA6E,EAC7E,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,GAC7B,EAAE,mBAAmB,qBAyzBrB"}
|
package/dist/PageGridLayout.js
CHANGED
|
@@ -84,7 +84,7 @@ const DEFAULT_ADD_RELATIONSHIP_WIDGET_EVENT_NAMES = [
|
|
|
84
84
|
const RGLResizeHandle = React.forwardRef(function RGLResizeHandle({ axis = 'se', className: injectedClassName, ...rest }, ref) {
|
|
85
85
|
return (_jsx("span", { ref: ref, "data-no-drag": true, className: `react-resizable-handle react-resizable-handle-${axis}${injectedClassName ? ' ' + injectedClassName : ''}`, ...rest }));
|
|
86
86
|
});
|
|
87
|
-
const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, isEditing, label, onHide, autoHeight, onAutoHeightChange, children: injectedChildren, className: injectedClassName, style: injectedStyle, ...rest }, ref) {
|
|
87
|
+
const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, isEditing, label, onHide, autoHeight, onAutoHeightChange, chrome = false, children: injectedChildren, className: injectedClassName, style: injectedStyle, ...rest }, ref) {
|
|
88
88
|
// Auto-height measurement (blueprint amendment A1). `measureRef` wraps
|
|
89
89
|
// `content` with NO height constraint of its own — its parent has
|
|
90
90
|
// `overflow-hidden` + `flex-1 min-h-0` (clips *painting* to the current
|
|
@@ -214,7 +214,18 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
214
214
|
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" })), 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-destructive-foreground shadow transition-colors", "data-no-drag": true, onPointerDown: (event) => event.stopPropagation(), onClick: (event) => {
|
|
215
215
|
event.stopPropagation();
|
|
216
216
|
onHide(id);
|
|
217
|
-
}, title: `Hide ${label}`, "aria-label": `Hide ${label}`, children: _jsx(EyeOff, { className: "h-3 w-3", "aria-hidden": "true" }) })), _jsx("div", {
|
|
217
|
+
}, 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', className: chrome
|
|
218
|
+
? // ONE radius token, read by the grid item AND available to any
|
|
219
|
+
// app card that opts into the same surface. Two surfaces
|
|
220
|
+
// reading the SAME var is what makes their corners align, and
|
|
221
|
+
// it is also what keeps the radius tenant-configurable —
|
|
222
|
+
// a literal here would align them and lock white-label out.
|
|
223
|
+
// `--radius-card` defaults to today's value (1.5rem =
|
|
224
|
+
// rounded-3xl), so this is byte-identical until a tenant sets
|
|
225
|
+
// one.
|
|
226
|
+
'h-full w-full rounded-[var(--radius-card,1.5rem)] transition-all flex flex-col bg-card border border-border shadow-sm dark:shadow-[var(--glow-card,none)]'
|
|
227
|
+
: // Chrome OFF: layout only. Identical box, no paint.
|
|
228
|
+
'h-full w-full transition-all flex flex-col', style: { contain: 'layout style' }, children: _jsx("div", { className: cn('flex-1 min-h-0', autoHeight ? 'overflow-hidden' : 'overflow-auto'), children: autoHeight ? _jsx("div", { ref: measureRef, children: content }) : content }) })] }), injectedChildren] }));
|
|
218
229
|
}));
|
|
219
230
|
export function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className,
|
|
220
231
|
// Resize default flipped 2026-05-12: rgl v2 dropped auto-handle rendering
|
|
@@ -222,7 +233,12 @@ export function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVer
|
|
|
222
233
|
// adapters then defaulted it back to true. With v2's handle gap fixed,
|
|
223
234
|
// the safe default is true so any consumer who forgets to set it still
|
|
224
235
|
// gets a usable canvas. Opt out per-page with isResizable={false}.
|
|
225
|
-
isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, tenantId, defaultAutoHeight,
|
|
236
|
+
isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, tenantId, defaultAutoHeight,
|
|
237
|
+
// CHROME OFF BY DEFAULT — the inversion. See `GridItemProps.chrome`.
|
|
238
|
+
// An app that is not ready to migrate its own card surfaces passes
|
|
239
|
+
// `itemChrome` to get the pre-1.1.0 behaviour back for every slot, and
|
|
240
|
+
// migrates page by page with the per-item `chrome` flag.
|
|
241
|
+
itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_NAMES, createEntityWidget, onRegisterEntityWidget, relationshipCatalog, addRelationshipWidgetEventNames = DEFAULT_ADD_RELATIONSHIP_WIDGET_EVENT_NAMES, createRelationshipWidget, onRegisterRelationshipWidget, onRelationshipWidgetRejected, }) {
|
|
226
242
|
const { currentLayouts, layoutCols, isEditing, setIsEditing, activeCols, activeCompactor, onLayoutChange, handleColumnChange, handleBreakpointChange, handleCompact, handleReset, addWidget, moveWidget, setWidgetLocked, applyAutoHeightRows, autoHeightRows, resetConfirmOpen, setResetConfirmOpen, containerRef, containerWidth, } = usePageGridLayout({
|
|
227
243
|
pageKey,
|
|
228
244
|
defaultLayouts,
|
|
@@ -693,6 +709,6 @@ isResizable = true, resizeHandles = DEFAULT_RESIZE_HANDLES, tenantId, defaultAut
|
|
|
693
709
|
const content = allWidgets[layoutItem.i];
|
|
694
710
|
if (content === undefined || content === null)
|
|
695
711
|
return null;
|
|
696
|
-
return (_jsx(GridItem, { id: layoutItem.i, content: content, isEditing: isEditing, label: layerNames[layoutItem.i] || widgetMeta?.[layoutItem.i]?.label || layoutItem.i, onHide: hideLayer, autoHeight: layoutItem.autoHeight, onAutoHeightChange: handleAutoHeightChange }, layoutItem.i));
|
|
712
|
+
return (_jsx(GridItem, { id: layoutItem.i, content: content, isEditing: isEditing, label: layerNames[layoutItem.i] || widgetMeta?.[layoutItem.i]?.label || layoutItem.i, onHide: hideLayer, autoHeight: layoutItem.autoHeight, onAutoHeightChange: handleAutoHeightChange, chrome: layoutItem.chrome ?? itemChrome }, layoutItem.i));
|
|
697
713
|
}) }) }) })] }));
|
|
698
714
|
}
|
|
@@ -12,6 +12,26 @@ import type { CanvasCardProps } from './CanvasCard.js';
|
|
|
12
12
|
import type { GridLayouts } from './types.js';
|
|
13
13
|
/** The 12-column grid every BSuite page canvas is laid out against. */
|
|
14
14
|
export declare const CANVAS_GRID_COLUMNS = 12;
|
|
15
|
+
/**
|
|
16
|
+
* The width a `CanvasCard` gets when its author does not say.
|
|
17
|
+
*
|
|
18
|
+
* SIX, i.e. half the grid — changed from twelve in 1.1.0. Twelve on a
|
|
19
|
+
* twelve-column grid means every card that omits `w` renders full width and
|
|
20
|
+
* the page becomes a single vertical stack. Measured across the estate on
|
|
21
|
+
* 2026-08-25: **1,068 of 1,729 CanvasCard usages omit `w`** (BSU and conduit
|
|
22
|
+
* omit it 100% of the time), so 62% of every card surface in BSuite was
|
|
23
|
+
* stacked by a DEFAULT, not by a layout decision. That is the operator's
|
|
24
|
+
* long-standing "the cards don't use the available space" report, and it is
|
|
25
|
+
* one number in one file rather than 1,068 page edits.
|
|
26
|
+
*
|
|
27
|
+
* Six rather than four: at a 1680px container half the grid is still ~820px,
|
|
28
|
+
* which comfortably holds a data table. Four would have traded a stacking
|
|
29
|
+
* complaint for a cramping one.
|
|
30
|
+
*
|
|
31
|
+
* A page that genuinely wants a full-width card still says `w={12}` — an
|
|
32
|
+
* explicit width always wins, and 661 usages already do exactly that.
|
|
33
|
+
*/
|
|
34
|
+
export declare const DEFAULT_CANVAS_CARD_WIDTH = 6;
|
|
15
35
|
export declare function isCanvasCardElement(node: ReactNode): node is ReactElement<CanvasCardProps>;
|
|
16
36
|
/**
|
|
17
37
|
* Best-effort display name for a node that is about to be discarded.
|
|
@@ -58,5 +78,7 @@ export interface CanvasCardLayoutResult {
|
|
|
58
78
|
* item. (This is the fact that disproves the "dynamic card lists cannot be
|
|
59
79
|
* split into static widget keys" objection recorded in several app ledgers.)
|
|
60
80
|
*/
|
|
61
|
-
export declare function buildCanvasCardLayout(children: ReactNode
|
|
81
|
+
export declare function buildCanvasCardLayout(children: ReactNode, options?: {
|
|
82
|
+
defaultWidth?: number;
|
|
83
|
+
}): CanvasCardLayoutResult;
|
|
62
84
|
//# sourceMappingURL=canvasCardLayout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvasCardLayout.d.ts","sourceRoot":"","sources":["../src/canvasCardLayout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,GACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAAC,CAKvC;AAQD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQpD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG;IACpD,KAAK,EAAE,YAAY,CAAC,eAAe,CAAC,EAAE,CAAC;IACvC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAqBA;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAI,EAAE,GAAG,SAAsB,UAE7E;AAED,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,yEAAyE;IACzE,OAAO,EAAE,WAAW,CAAC;IACrB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"canvasCardLayout.d.ts","sourceRoot":"","sources":["../src/canvasCardLayout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,GACd,IAAI,IAAI,YAAY,CAAC,eAAe,CAAC,CAKvC;AAQD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQpD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG;IACpD,KAAK,EAAE,YAAY,CAAC,eAAe,CAAC,EAAE,CAAC;IACvC,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAqBA;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAI,EAAE,GAAG,SAAsB,UAE7E;AAED,MAAM,WAAW,sBAAsB;IACrC,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,yEAAyE;IACzE,OAAO,EAAE,WAAW,CAAC;IACrB,+EAA+E;IAC/E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,EACnB,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,sBAAsB,CA2CxB"}
|
package/dist/canvasCardLayout.js
CHANGED
|
@@ -11,6 +11,26 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
11
11
|
import { Children, Fragment, isValidElement, } from 'react';
|
|
12
12
|
/** The 12-column grid every BSuite page canvas is laid out against. */
|
|
13
13
|
export const CANVAS_GRID_COLUMNS = 12;
|
|
14
|
+
/**
|
|
15
|
+
* The width a `CanvasCard` gets when its author does not say.
|
|
16
|
+
*
|
|
17
|
+
* SIX, i.e. half the grid — changed from twelve in 1.1.0. Twelve on a
|
|
18
|
+
* twelve-column grid means every card that omits `w` renders full width and
|
|
19
|
+
* the page becomes a single vertical stack. Measured across the estate on
|
|
20
|
+
* 2026-08-25: **1,068 of 1,729 CanvasCard usages omit `w`** (BSU and conduit
|
|
21
|
+
* omit it 100% of the time), so 62% of every card surface in BSuite was
|
|
22
|
+
* stacked by a DEFAULT, not by a layout decision. That is the operator's
|
|
23
|
+
* long-standing "the cards don't use the available space" report, and it is
|
|
24
|
+
* one number in one file rather than 1,068 page edits.
|
|
25
|
+
*
|
|
26
|
+
* Six rather than four: at a 1680px container half the grid is still ~820px,
|
|
27
|
+
* which comfortably holds a data table. Four would have traded a stacking
|
|
28
|
+
* complaint for a cramping one.
|
|
29
|
+
*
|
|
30
|
+
* A page that genuinely wants a full-width card still says `w={12}` — an
|
|
31
|
+
* explicit width always wins, and 661 usages already do exactly that.
|
|
32
|
+
*/
|
|
33
|
+
export const DEFAULT_CANVAS_CARD_WIDTH = 6;
|
|
14
34
|
export function isCanvasCardElement(node) {
|
|
15
35
|
return (isValidElement(node) &&
|
|
16
36
|
node.type.displayName === 'CanvasCard');
|
|
@@ -84,7 +104,8 @@ export function clampColumns(value, min = 1, max = CANVAS_GRID_COLUMNS) {
|
|
|
84
104
|
* item. (This is the fact that disproves the "dynamic card lists cannot be
|
|
85
105
|
* split into static widget keys" objection recorded in several app ledgers.)
|
|
86
106
|
*/
|
|
87
|
-
export function buildCanvasCardLayout(children) {
|
|
107
|
+
export function buildCanvasCardLayout(children, options = {}) {
|
|
108
|
+
const defaultWidth = clampColumns(options.defaultWidth ?? DEFAULT_CANVAS_CARD_WIDTH);
|
|
88
109
|
const widgets = {};
|
|
89
110
|
const lg = [];
|
|
90
111
|
let x = 0;
|
|
@@ -96,7 +117,7 @@ export function buildCanvasCardLayout(children) {
|
|
|
96
117
|
// a card explicitly opts out for a virtualized list. See CanvasCardProps.
|
|
97
118
|
const { cardKey, h = 6, minH = 2, minW = 4, autoHeight = true, children: body, } = child.props;
|
|
98
119
|
const normalizedMinW = clampColumns(minW);
|
|
99
|
-
const width = clampColumns(child.props.w ??
|
|
120
|
+
const width = clampColumns(child.props.w ?? defaultWidth, normalizedMinW);
|
|
100
121
|
if (x + width > CANVAS_GRID_COLUMNS) {
|
|
101
122
|
y += rowHeight;
|
|
102
123
|
x = 0;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The card-surface defect classes, made VISIBLE and DIFFABLE.
|
|
4
|
+
*
|
|
5
|
+
* `@bsuite/page-builder` 1.0.4, 1.0.5 and 1.0.6 each shipped GREEN AND BROKEN.
|
|
6
|
+
* Types, lint, unit tests and CI cannot see a 28px card sitting inside a 24px
|
|
7
|
+
* frame; only a rendered surface can. These stories exist so the chrome
|
|
8
|
+
* inversion has something to be checked against that is not a number.
|
|
9
|
+
*
|
|
10
|
+
* Read them in pairs: the story named "…(the defect)" is what shipped up to
|
|
11
|
+
* 1.0.7, and the one beside it is what 1.1.0 renders.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Plain CSF, no `Meta`/`StoryObj` type imports.
|
|
15
|
+
*
|
|
16
|
+
* `@storybook/react-vite` is a devDependency of `@bsuite/ui`, which owns the
|
|
17
|
+
* Storybook config; this package does not depend on Storybook and must not
|
|
18
|
+
* start to, or `pnpm typecheck` here fails on a type-only import for a tool
|
|
19
|
+
* that is not installed. CSF is a plain-object format — the indexer reads the
|
|
20
|
+
* default export and the named exports, and the types are optional sugar.
|
|
21
|
+
*/
|
|
22
|
+
type Story = {
|
|
23
|
+
name?: string;
|
|
24
|
+
render: () => ReactNode;
|
|
25
|
+
};
|
|
26
|
+
declare const _default: {
|
|
27
|
+
title: string;
|
|
28
|
+
parameters: {
|
|
29
|
+
layout: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
export default _default;
|
|
33
|
+
/**
|
|
34
|
+
* THE DEFECT, exactly as it shipped. A card inside the grid item's card:
|
|
35
|
+
* two radii, two 1px borders, two backgrounds. 316+ files render this.
|
|
36
|
+
*/
|
|
37
|
+
export declare const NestedCardDoubleFrame: Story;
|
|
38
|
+
/** The same content on 1.1.0 defaults: ONE border, ONE radius. */
|
|
39
|
+
export declare const NestedCardSingleFrame: Story;
|
|
40
|
+
/** Bare content with chrome OFF — the regression the inversion could cause. */
|
|
41
|
+
export declare const BareContentNoChrome: Story;
|
|
42
|
+
/** The same bare content opting IN per item. This is the migration for the 10%. */
|
|
43
|
+
export declare const BareContentOptsIn: Story;
|
|
44
|
+
/**
|
|
45
|
+
* Every card width side by side. `w` defaulted to 12, so 1,068 of 1,729 usages
|
|
46
|
+
* rendered like the last row here — one card per row, the rest of the screen
|
|
47
|
+
* empty. That is the "cards don't use the available space" report.
|
|
48
|
+
*/
|
|
49
|
+
export declare const WidthLadder: Story;
|
|
50
|
+
/**
|
|
51
|
+
* Card headings. `text-gradient-accent` is on 183 of 235 crm7 h1 page titles
|
|
52
|
+
* and 0 of 310 crm7 h2/h3 CARD headings — the element the operator keeps
|
|
53
|
+
* asking about. The pairing matters: the solid `text-(--role-text-heading)`
|
|
54
|
+
* sits UNDER the gradient as the fallback layer.
|
|
55
|
+
*
|
|
56
|
+
* `width: fit-content` inside the utility is load-bearing. Anything that
|
|
57
|
+
* overrides width makes a short heading sample only the first ~15% of the
|
|
58
|
+
* gradient and render flat — indistinguishable from having no gradient at all,
|
|
59
|
+
* which is why "is the class present" is not a check.
|
|
60
|
+
*/
|
|
61
|
+
export declare const CardHeadingGradient: Story;
|
|
62
|
+
//# sourceMappingURL=cardSurfaces.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cardSurfaces.stories.d.ts","sourceRoot":"","sources":["../src/cardSurfaces.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,KAAK,KAAK,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,SAAS,CAAA;CAAE,CAAA;;;;;;;AAEvD,wBAGC;AA0BD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAYnC,CAAA;AAED,kEAAkE;AAClE,eAAO,MAAM,qBAAqB,EAAE,KAWnC,CAAA;AAED,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,EAAE,KAWjC,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,EAAE,KAW/B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAyBzB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAoBjC,CAAA"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PageGridLayout } from './PageGridLayout.js';
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Page Builder/Card surfaces',
|
|
5
|
+
parameters: { layout: 'fullscreen' },
|
|
6
|
+
};
|
|
7
|
+
/** What an app renders inside a slot: its own card. Border, radius, background. */
|
|
8
|
+
function AppCard({ title, children }) {
|
|
9
|
+
return (_jsxs("div", { className: "h-full rounded-[var(--radius-card,1.5rem)] border border-border bg-card p-6 shadow-sm", children: [_jsx("h3", { className: "mb-2 text-lg font-semibold text-(--role-text-heading)", children: title }), _jsx("div", { className: "text-sm text-muted-foreground", children: children })] }));
|
|
10
|
+
}
|
|
11
|
+
/** Bare content: no surface of its own. This is the 10% that NEEDS the chrome. */
|
|
12
|
+
function BareContent({ title }) {
|
|
13
|
+
return (_jsxs("div", { className: "p-6", children: [_jsx("h3", { className: "mb-2 text-lg font-semibold text-(--role-text-heading)", children: title }), _jsx("p", { className: "text-sm text-muted-foreground", children: "No surface of its own \u2014 this slot is the one that should opt IN to chrome." })] }));
|
|
14
|
+
}
|
|
15
|
+
const oneSlot = { lg: [{ i: 'a', x: 0, y: 0, w: 6, h: 6 }] };
|
|
16
|
+
/**
|
|
17
|
+
* THE DEFECT, exactly as it shipped. A card inside the grid item's card:
|
|
18
|
+
* two radii, two 1px borders, two backgrounds. 316+ files render this.
|
|
19
|
+
*/
|
|
20
|
+
export const NestedCardDoubleFrame = {
|
|
21
|
+
name: 'Nested card — DOUBLE FRAME (the defect)',
|
|
22
|
+
render: () => (_jsx("div", { className: "p-8", children: _jsx(PageGridLayout, { pageKey: "sb/nested-defect", defaultLayouts: oneSlot, itemChrome: true, widgets: { a: _jsx(AppCard, { title: "Quick Actions", children: "Grid item chrome ON + app card." }) } }) })),
|
|
23
|
+
};
|
|
24
|
+
/** The same content on 1.1.0 defaults: ONE border, ONE radius. */
|
|
25
|
+
export const NestedCardSingleFrame = {
|
|
26
|
+
name: 'Nested card — ONE frame (1.1.0 default)',
|
|
27
|
+
render: () => (_jsx("div", { className: "p-8", children: _jsx(PageGridLayout, { pageKey: "sb/nested-fixed", defaultLayouts: oneSlot, widgets: { a: _jsx(AppCard, { title: "Quick Actions", children: "Grid item chrome OFF; the app card is the only surface." }) } }) })),
|
|
28
|
+
};
|
|
29
|
+
/** Bare content with chrome OFF — the regression the inversion could cause. */
|
|
30
|
+
export const BareContentNoChrome = {
|
|
31
|
+
name: 'Bare content, chrome OFF — the regression to watch for',
|
|
32
|
+
render: () => (_jsx("div", { className: "p-8", children: _jsx(PageGridLayout, { pageKey: "sb/bare-off", defaultLayouts: oneSlot, widgets: { a: _jsx(BareContent, { title: "Pipeline Overview" }) } }) })),
|
|
33
|
+
};
|
|
34
|
+
/** The same bare content opting IN per item. This is the migration for the 10%. */
|
|
35
|
+
export const BareContentOptsIn = {
|
|
36
|
+
name: 'Bare content, per-item chrome ON — the migration',
|
|
37
|
+
render: () => (_jsx("div", { className: "p-8", children: _jsx(PageGridLayout, { pageKey: "sb/bare-on", defaultLayouts: { lg: [{ i: 'a', x: 0, y: 0, w: 6, h: 6, chrome: true }] }, widgets: { a: _jsx(BareContent, { title: "Pipeline Overview" }) } }) })),
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Every card width side by side. `w` defaulted to 12, so 1,068 of 1,729 usages
|
|
41
|
+
* rendered like the last row here — one card per row, the rest of the screen
|
|
42
|
+
* empty. That is the "cards don't use the available space" report.
|
|
43
|
+
*/
|
|
44
|
+
export const WidthLadder = {
|
|
45
|
+
name: 'Width ladder — w = 2 / 3 / 4 / 6 / 12',
|
|
46
|
+
render: () => (_jsx("div", { className: "p-8", children: _jsx(PageGridLayout, { pageKey: "sb/widths", defaultLayouts: {
|
|
47
|
+
lg: [
|
|
48
|
+
{ i: 'w2', x: 0, y: 0, w: 2, h: 4 },
|
|
49
|
+
{ i: 'w3', x: 2, y: 0, w: 3, h: 4 },
|
|
50
|
+
{ i: 'w4', x: 5, y: 0, w: 4, h: 4 },
|
|
51
|
+
{ i: 'w6', x: 0, y: 4, w: 6, h: 4 },
|
|
52
|
+
{ i: 'w12', x: 0, y: 8, w: 12, h: 4 },
|
|
53
|
+
],
|
|
54
|
+
}, widgets: {
|
|
55
|
+
w2: _jsx(AppCard, { title: "w=2" }),
|
|
56
|
+
w3: _jsx(AppCard, { title: "w=3" }),
|
|
57
|
+
w4: _jsx(AppCard, { title: "w=4" }),
|
|
58
|
+
w6: _jsx(AppCard, { title: "w=6 \u2014 the new default" }),
|
|
59
|
+
w12: _jsx(AppCard, { title: "w=12 \u2014 the old default, one card per row" }),
|
|
60
|
+
} }) })),
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Card headings. `text-gradient-accent` is on 183 of 235 crm7 h1 page titles
|
|
64
|
+
* and 0 of 310 crm7 h2/h3 CARD headings — the element the operator keeps
|
|
65
|
+
* asking about. The pairing matters: the solid `text-(--role-text-heading)`
|
|
66
|
+
* sits UNDER the gradient as the fallback layer.
|
|
67
|
+
*
|
|
68
|
+
* `width: fit-content` inside the utility is load-bearing. Anything that
|
|
69
|
+
* overrides width makes a short heading sample only the first ~15% of the
|
|
70
|
+
* gradient and render flat — indistinguishable from having no gradient at all,
|
|
71
|
+
* which is why "is the class present" is not a check.
|
|
72
|
+
*/
|
|
73
|
+
export const CardHeadingGradient = {
|
|
74
|
+
name: 'Card headings — with and without the gradient',
|
|
75
|
+
render: () => (_jsxs("div", { className: "grid gap-8 p-8 md:grid-cols-2", children: [_jsxs("div", { className: "rounded-[var(--radius-card,1.5rem)] border border-border bg-card p-6", children: [_jsx("h3", { className: "mb-2 text-lg font-semibold text-(--role-text-heading)", children: "Quick Actions \u2014 flat (today, 0 of 310)" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "No gradient." })] }), _jsxs("div", { className: "rounded-[var(--radius-card,1.5rem)] border border-border bg-card p-6", children: [_jsx("h3", { className: "text-gradient-accent mb-2 text-lg font-semibold text-(--role-text-heading)", children: "Quick Actions \u2014 gradient (G2 target)" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "`text-gradient-accent` over the solid heading token." })] })] })),
|
|
76
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { CanvasCard } from './CanvasCard.js';
|
|
|
4
4
|
export type { CanvasCardProps } from './CanvasCard.js';
|
|
5
5
|
export { DraggableCardPage } from './DraggableCardPage.js';
|
|
6
6
|
export type { DraggableCardPageProps } from './DraggableCardPage.js';
|
|
7
|
-
export { buildCanvasCardLayout, flattenCanvasCards, isCanvasCardElement, describeNode, clampColumns, CANVAS_GRID_COLUMNS, } from './canvasCardLayout.js';
|
|
7
|
+
export { buildCanvasCardLayout, DEFAULT_CANVAS_CARD_WIDTH, flattenCanvasCards, isCanvasCardElement, describeNode, clampColumns, CANVAS_GRID_COLUMNS, } from './canvasCardLayout.js';
|
|
8
8
|
export type { CanvasCardLayoutResult } from './canvasCardLayout.js';
|
|
9
9
|
export type { WidgetConfig, PageEditorLauncherProps } from './PageEditorLauncher.js';
|
|
10
10
|
export { usePageGridLayout, DEFAULT_EDITOR_EVENT_NAMES, PAGE_GRID_EDITING_EVENT, } from './usePageGridLayout.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,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,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,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,gCAAgC,EAChC,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,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,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,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EACV,kBAAkB,EAClB,0BAA0B,EAC1B,cAAc,EACd,WAAW,EACX,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,mBAAmB,EACnB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,gCAAgC,EAChC,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export { PageGridLayout } from './PageGridLayout.js';
|
|
|
2
2
|
export { PageEditorLauncher } from './PageEditorLauncher.js';
|
|
3
3
|
export { CanvasCard } from './CanvasCard.js';
|
|
4
4
|
export { DraggableCardPage } from './DraggableCardPage.js';
|
|
5
|
-
export { buildCanvasCardLayout, flattenCanvasCards, isCanvasCardElement, describeNode, clampColumns, CANVAS_GRID_COLUMNS, } from './canvasCardLayout.js';
|
|
5
|
+
export { buildCanvasCardLayout, DEFAULT_CANVAS_CARD_WIDTH, flattenCanvasCards, isCanvasCardElement, describeNode, clampColumns, CANVAS_GRID_COLUMNS, } from './canvasCardLayout.js';
|
|
6
6
|
export { usePageGridLayout, DEFAULT_EDITOR_EVENT_NAMES, PAGE_GRID_EDITING_EVENT, } from './usePageGridLayout.js';
|
|
7
7
|
export { rescaleLayout } from './rescaleLayout.js';
|
|
8
8
|
export { computeAutoHeightRows } from './autoHeight.js';
|
|
@@ -46,7 +46,20 @@ export type CardSurfaceIdiom =
|
|
|
46
46
|
/** autoHeight opt-out on a card that is not a virtualized list. */
|
|
47
47
|
| 'autoheight-optout'
|
|
48
48
|
/** autoHeight={false} with a seed height so small the card must clip. */
|
|
49
|
-
| 'clipped-card'
|
|
49
|
+
| 'clipped-card'
|
|
50
|
+
/**
|
|
51
|
+
* V-C5. A grid item whose child re-declares card chrome — border + radius +
|
|
52
|
+
* background — inside the chrome the grid item already paints. 28px inside
|
|
53
|
+
* 24px, two 1px borders. This is the idiom V-C4 (`glued-widget`) cannot see:
|
|
54
|
+
* ONE card in ONE slot is not glue, and it is still a double frame.
|
|
55
|
+
*/
|
|
56
|
+
| 'nested-chrome'
|
|
57
|
+
/**
|
|
58
|
+
* The file could not be parsed with confidence. NOT a clean verdict. A gate
|
|
59
|
+
* that cannot tell "checked nothing" from "found nothing" is not a gate
|
|
60
|
+
* (D-92), so an unparseable file gets its own idiom and its own exit path.
|
|
61
|
+
*/
|
|
62
|
+
| 'unparseable';
|
|
50
63
|
export interface CardSurfaceFinding {
|
|
51
64
|
file: string;
|
|
52
65
|
idiom: CardSurfaceIdiom;
|
|
@@ -95,6 +108,36 @@ export interface CardSurfaceScannerConfig {
|
|
|
95
108
|
autoHeightEscapeHatch?: RegExp;
|
|
96
109
|
/** File extensions to scan. Defaults to .tsx. */
|
|
97
110
|
extensions?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Extra component names that count as CARD CHROME when they appear inside a
|
|
113
|
+
* grid slot — a component that paints its own border + radius + background.
|
|
114
|
+
* `cardTags` is always included; this is for app-local chrome components the
|
|
115
|
+
* glue check does not need (BSU `MagicCard`, conduit `CounterCard`, …).
|
|
116
|
+
*/
|
|
117
|
+
nestedChromeTags?: string[];
|
|
118
|
+
/** file -> reason. A nested-chrome file listed here is allowed. */
|
|
119
|
+
nestedChromeExclusions?: Record<string, string>;
|
|
120
|
+
/**
|
|
121
|
+
* Does the GRID ITEM paint card chrome in the version this app resolves?
|
|
122
|
+
*
|
|
123
|
+
* TRUE for `@bsuite/page-builder` <= 1.0.7, where every grid item painted
|
|
124
|
+
* `rounded-3xl bg-card border border-border` unconditionally and there was
|
|
125
|
+
* no way to turn it off. On those versions a nested card is ALWAYS a double
|
|
126
|
+
* frame, so every nesting slot is a finding.
|
|
127
|
+
*
|
|
128
|
+
* FALSE from 1.1.0, where chrome is opt-in. A nested card then becomes the
|
|
129
|
+
* CORRECT shape — it is the only surface — and the defect narrows to a slot
|
|
130
|
+
* that opts back INTO chrome (`itemChrome`, or `chrome` on the item or the
|
|
131
|
+
* CanvasCard) AND still nests a card.
|
|
132
|
+
*
|
|
133
|
+
* DEFAULTS TO TRUE, i.e. it assumes the pre-inversion package until an app
|
|
134
|
+
* says otherwise. A shared-package fix that four consumers receive and one
|
|
135
|
+
* does not is this estate's recorded failure mode (conduit sat on a
|
|
136
|
+
* minor-locked `^0.6.3` while the fix shipped in 0.8.0, and nothing
|
|
137
|
+
* reported it), so each app must DECLARE which side of the inversion it is
|
|
138
|
+
* on rather than inherit an optimistic default.
|
|
139
|
+
*/
|
|
140
|
+
gridItemPaintsChrome?: boolean;
|
|
98
141
|
}
|
|
99
142
|
export interface CardSurfaceScanResult {
|
|
100
143
|
findings: CardSurfaceFinding[];
|
|
@@ -103,6 +146,14 @@ export interface CardSurfaceScanResult {
|
|
|
103
146
|
scanRootsResolved: string[];
|
|
104
147
|
/** Exclusion-ledger keys that no longer match any finding — stale entries. */
|
|
105
148
|
staleExclusions: string[];
|
|
149
|
+
/**
|
|
150
|
+
* Files the scanner could NOT parse with confidence. These are UNKNOWN, not
|
|
151
|
+
* clean. A caller that treats an empty `findings` array as a pass while this
|
|
152
|
+
* array is non-empty has reproduced the exact defect D-92 names.
|
|
153
|
+
*/
|
|
154
|
+
unknownFiles: string[];
|
|
155
|
+
/** Distinct files carrying at least one `nested-chrome` finding. */
|
|
156
|
+
nestedChromeFiles: string[];
|
|
106
157
|
/** Human-readable account of how the verdict was reached. */
|
|
107
158
|
summary: string;
|
|
108
159
|
}
|
|
@@ -116,5 +167,54 @@ export interface CardSurfaceScanResult {
|
|
|
116
167
|
* skipped entirely. Stripping first fixes both.
|
|
117
168
|
*/
|
|
118
169
|
export declare function stripComments(source: string): string;
|
|
170
|
+
/**
|
|
171
|
+
* Every opening tag in a JSX body, with its raw attribute text.
|
|
172
|
+
*
|
|
173
|
+
* Hand-rolled rather than regex-only because an attribute value can contain
|
|
174
|
+
* `>` inside a string, a template literal or a `{…}` expression — three of the
|
|
175
|
+
* five hand-rolled copies this module replaced were defeated by exactly that.
|
|
176
|
+
*/
|
|
177
|
+
export declare function openingTags(body: string): {
|
|
178
|
+
tag: string;
|
|
179
|
+
attrs: string;
|
|
180
|
+
}[];
|
|
181
|
+
/**
|
|
182
|
+
* Does this element paint its OWN card chrome?
|
|
183
|
+
*
|
|
184
|
+
* Chrome means all three of border, radius and background, because that is
|
|
185
|
+
* exactly what `PageGridLayout` already paints on the slot. Two of the three is
|
|
186
|
+
* a tinted panel or a divider, not a second card — requiring all three is what
|
|
187
|
+
* separates BSU's `glass-card rounded-2xl border-primary/30` (a real double
|
|
188
|
+
* frame) from a `rounded-lg bg-muted` inline chip (not one).
|
|
189
|
+
*
|
|
190
|
+
* Chrome declared through `style={{ background, border, borderRadius }}` counts
|
|
191
|
+
* the same as chrome declared through classes. BSU's `Settings.tsx` is chrome
|
|
192
|
+
* entirely in inline style; a class-only detector calls that file clean, which
|
|
193
|
+
* is how a nested card hides from a gate that only reads Tailwind.
|
|
194
|
+
*/
|
|
195
|
+
export declare function elementDeclaresCardChrome(el: {
|
|
196
|
+
tag: string;
|
|
197
|
+
attrs: string;
|
|
198
|
+
}, chromeTags: Set<string>): string | null;
|
|
199
|
+
/**
|
|
200
|
+
* Does this grid slot paint chrome of its OWN, post-inversion?
|
|
201
|
+
*
|
|
202
|
+
* Three ways to opt in, and all three have to be visible to the scanner or a
|
|
203
|
+
* re-chromed slot goes unnoticed: `itemChrome` on the grid component (whole
|
|
204
|
+
* app/page), `chrome: true` on the layout item, and `chrome` on the CanvasCard.
|
|
205
|
+
*/
|
|
206
|
+
export declare function slotOptsIntoChrome(fileSource: string, slotBody: string): boolean;
|
|
207
|
+
/** The first nested-chrome element inside one grid slot, or null. */
|
|
208
|
+
export declare function findNestedChrome(slotBody: string, config: Pick<CardSurfaceScannerConfig, 'cardTags' | 'nestedChromeTags'>): string | null;
|
|
209
|
+
/**
|
|
210
|
+
* Can this file be parsed with confidence?
|
|
211
|
+
*
|
|
212
|
+
* Returns a reason when it CANNOT. Every `<CanvasCard` must pair with a
|
|
213
|
+
* `</CanvasCard>` the block regex can reach, and every `widgets={{` must close
|
|
214
|
+
* before EOF. A file that fails either is UNKNOWN — it is not reported clean,
|
|
215
|
+
* and it is not silently skipped. "Checked nothing" and "found nothing" do not
|
|
216
|
+
* share an exit code here.
|
|
217
|
+
*/
|
|
218
|
+
export declare function parseConfidence(src: string): string | null;
|
|
119
219
|
export declare function scanCardSurfaces(config: CardSurfaceScannerConfig): CardSurfaceScanResult;
|
|
120
220
|
//# sourceMappingURL=cardSurfaceScanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardSurfaceScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardSurfaceScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAKH,MAAM,MAAM,gBAAgB;AAC1B,2DAA2D;AACzD,cAAc;AAChB,6EAA6E;GAC3E,sBAAsB;AACxB,yEAAyE;GACvE,mBAAmB;AACrB,mEAAmE;GACjE,mBAAmB;AACrB,yEAAyE;GACvE,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cardSurfaceScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardSurfaceScanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,8 +55,17 @@ const DEFAULT_GRID_PRIMITIVES = [
|
|
|
55
55
|
*/
|
|
56
56
|
export function stripComments(source) {
|
|
57
57
|
return source
|
|
58
|
-
|
|
59
|
-
.
|
|
58
|
+
// {/* JSX comment */} — TEMPERED so the match cannot span a `*/` it did
|
|
59
|
+
// not open. The naive lazy form `\{\s*\/\*[\s\S]*?\*\/\s*\}` backtracks
|
|
60
|
+
// past the comment's own terminator whenever the next character is not
|
|
61
|
+
// `}` — e.g. an ordinary block comment sitting at the head of an object
|
|
62
|
+
// literal — and then matches the NEXT `*/}` anywhere later in the file,
|
|
63
|
+
// DELETING every line between. crm7 `src/pages/people/new/worker.tsx` lost
|
|
64
|
+
// 37 lines and two whole `<CanvasCard>` blocks to exactly that, which the
|
|
65
|
+
// UNKNOWN gate below caught as unbalanced tags. Code silently deleted
|
|
66
|
+
// before matching is a scanner that under-reports and calls it clean.
|
|
67
|
+
.replace(/\{\s*\/\*(?:(?!\*\/)[\s\S])*\*\/\s*\}/g, '')
|
|
68
|
+
.replace(/\/\*(?:(?!\*\/)[\s\S])*\*\//g, '') // /* block */
|
|
60
69
|
.replace(/(^|[^:])\/\/[^\n]*/g, '$1'); // // line, but not http://
|
|
61
70
|
}
|
|
62
71
|
function tagPattern(tags) {
|
|
@@ -159,6 +168,293 @@ function extractWidgetEntries(source) {
|
|
|
159
168
|
}
|
|
160
169
|
return out;
|
|
161
170
|
}
|
|
171
|
+
/* ==========================================================================
|
|
172
|
+
* V-C5 — NESTED CHROME
|
|
173
|
+
*
|
|
174
|
+
* `PageGridLayout` paints EVERY grid item as a card:
|
|
175
|
+
*
|
|
176
|
+
* h-full w-full rounded-3xl transition-all flex flex-col
|
|
177
|
+
* bg-card border border-border shadow-sm dark:shadow-[var(--glow-card,none)]
|
|
178
|
+
*
|
|
179
|
+
* When the slot's own content re-declares that surface — border + radius +
|
|
180
|
+
* background — the user sees 28px inside 24px and two 1px borders. V-C4
|
|
181
|
+
* (`glued-widget`) cannot see this: ONE card in ONE slot is not glue, and it
|
|
182
|
+
* is still a double frame. That is why 316 files across the estate render a
|
|
183
|
+
* card inside a card and every existing gate reads green.
|
|
184
|
+
* ========================================================================== */
|
|
185
|
+
/** Components that paint their own card chrome. */
|
|
186
|
+
const DEFAULT_NESTED_CHROME_TAGS = [
|
|
187
|
+
'Card',
|
|
188
|
+
'MagicCard',
|
|
189
|
+
'GlassCard',
|
|
190
|
+
'NeonCard',
|
|
191
|
+
'StatCard',
|
|
192
|
+
'SummaryCard',
|
|
193
|
+
'ServiceCard',
|
|
194
|
+
'CounterCard',
|
|
195
|
+
'MetricCard',
|
|
196
|
+
'InfoCard',
|
|
197
|
+
];
|
|
198
|
+
/**
|
|
199
|
+
* Elements that are CONTROLS, not surfaces.
|
|
200
|
+
*
|
|
201
|
+
* A bordered, rounded, tinted `<button>` is a button. A `<Badge>` is a pill.
|
|
202
|
+
* Counting them as nested chrome is how a detector inflates: throughput's
|
|
203
|
+
* `Teams.tsx` carries `border … rounded … text-…` on a filter button, which is
|
|
204
|
+
* correct styling and not a second card. Chrome on a control is never the
|
|
205
|
+
* double-frame defect, so controls are excluded BY TAG rather than by tuning
|
|
206
|
+
* the class thresholds until the number looks right.
|
|
207
|
+
*/
|
|
208
|
+
const CONTROL_TAGS = new Set([
|
|
209
|
+
'button',
|
|
210
|
+
'a',
|
|
211
|
+
'input',
|
|
212
|
+
'select',
|
|
213
|
+
'textarea',
|
|
214
|
+
'label',
|
|
215
|
+
'summary',
|
|
216
|
+
'Button',
|
|
217
|
+
'Input',
|
|
218
|
+
'Select',
|
|
219
|
+
'SelectTrigger',
|
|
220
|
+
'SelectContent',
|
|
221
|
+
'Textarea',
|
|
222
|
+
'Badge',
|
|
223
|
+
'Avatar',
|
|
224
|
+
'AvatarFallback',
|
|
225
|
+
'Switch',
|
|
226
|
+
'Checkbox',
|
|
227
|
+
'Progress',
|
|
228
|
+
'Slider',
|
|
229
|
+
'Toggle',
|
|
230
|
+
'ToggleGroup',
|
|
231
|
+
'ToggleGroupItem',
|
|
232
|
+
'TabsList',
|
|
233
|
+
'TabsTrigger',
|
|
234
|
+
'Skeleton',
|
|
235
|
+
'Tooltip',
|
|
236
|
+
'TooltipContent',
|
|
237
|
+
'DropdownMenuContent',
|
|
238
|
+
'PopoverContent',
|
|
239
|
+
]);
|
|
240
|
+
const RADIUS_CLASS = /(?:^|[\s'"`])rounded(?:-[a-z0-9[\]().\-/]+)?(?=$|[\s'"`])/;
|
|
241
|
+
const BORDER_CLASS = /(?:^|[\s'"`])border(?:-[a-z0-9[\]().\-/]+)?(?=$|[\s'"`])/;
|
|
242
|
+
const BG_CLASS = /(?:^|[\s'"`])(?:bg-[a-z0-9[\]().\-/]+|glass-card|neon-card|card-surface)(?=$|[\s'"`])/;
|
|
243
|
+
/**
|
|
244
|
+
* Composite classes that are a WHOLE card surface on their own.
|
|
245
|
+
*
|
|
246
|
+
* BSU's `.glass-card` (business-suite-unified/src/index.css:760) declares
|
|
247
|
+
* `background-color` AND `border: 1px solid` AND a shadow. `glass-card
|
|
248
|
+
* rounded-xl` is therefore already border + radius + background — the full
|
|
249
|
+
* double frame — while carrying no `border-*` utility for a class matcher to
|
|
250
|
+
* find. Requiring three separate Tailwind utilities makes every composite-class
|
|
251
|
+
* card invisible; BSU `Government.tsx` is exactly that shape.
|
|
252
|
+
*/
|
|
253
|
+
const COMPOSITE_CARD_CLASS = /(?:^|[\s'"`])(?:glass-card|neon-card|card-surface)(?=$|[\s'"`])/;
|
|
254
|
+
const RADIUS_STYLE = /\bborder-?[Rr]adius\b/;
|
|
255
|
+
const BORDER_STYLE = /\bborder(?:Color|Width|Style)?\s*:/;
|
|
256
|
+
const BG_STYLE = /\b(?:background|backgroundColor|backgroundImage)\s*:/;
|
|
257
|
+
/**
|
|
258
|
+
* Every opening tag in a JSX body, with its raw attribute text.
|
|
259
|
+
*
|
|
260
|
+
* Hand-rolled rather than regex-only because an attribute value can contain
|
|
261
|
+
* `>` inside a string, a template literal or a `{…}` expression — three of the
|
|
262
|
+
* five hand-rolled copies this module replaced were defeated by exactly that.
|
|
263
|
+
*/
|
|
264
|
+
export function openingTags(body) {
|
|
265
|
+
const out = [];
|
|
266
|
+
for (let i = 0; i < body.length; i++) {
|
|
267
|
+
if (body[i] !== '<')
|
|
268
|
+
continue;
|
|
269
|
+
const nameMatch = /^<([A-Za-z][A-Za-z0-9._-]*)/.exec(body.slice(i, i + 64));
|
|
270
|
+
if (!nameMatch)
|
|
271
|
+
continue;
|
|
272
|
+
let j = i + nameMatch[0].length;
|
|
273
|
+
let depth = 0;
|
|
274
|
+
let quote = null;
|
|
275
|
+
let closed = false;
|
|
276
|
+
for (; j < body.length; j++) {
|
|
277
|
+
const c = body[j];
|
|
278
|
+
if (quote) {
|
|
279
|
+
if (c === quote && body[j - 1] !== '\\')
|
|
280
|
+
quote = null;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
284
|
+
quote = c;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (c === '{')
|
|
288
|
+
depth++;
|
|
289
|
+
else if (c === '}')
|
|
290
|
+
depth--;
|
|
291
|
+
else if (c === '>' && depth === 0) {
|
|
292
|
+
closed = true;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (!closed)
|
|
297
|
+
continue;
|
|
298
|
+
out.push({ tag: nameMatch[1], attrs: body.slice(i + nameMatch[0].length, j) });
|
|
299
|
+
i = j;
|
|
300
|
+
}
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
/** Every className value on one element — string, template literal or `cn(...)`. */
|
|
304
|
+
function classValues(attrs) {
|
|
305
|
+
const out = [];
|
|
306
|
+
const re = /class(?:Name)?\s*=\s*(?:"([^"]*)"|'([^']*)'|\{([\s\S]*)\})/;
|
|
307
|
+
const m = re.exec(attrs);
|
|
308
|
+
if (!m)
|
|
309
|
+
return out;
|
|
310
|
+
if (m[1] !== undefined)
|
|
311
|
+
out.push(m[1]);
|
|
312
|
+
else if (m[2] !== undefined)
|
|
313
|
+
out.push(m[2]);
|
|
314
|
+
else if (m[3] !== undefined) {
|
|
315
|
+
// `{cn('a', cond && 'b')}` / `{`a ${x}`}` — take every literal inside.
|
|
316
|
+
const lit = /(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/g;
|
|
317
|
+
let l;
|
|
318
|
+
while ((l = lit.exec(m[3])) !== null)
|
|
319
|
+
out.push(l[1] ?? l[2] ?? l[3] ?? '');
|
|
320
|
+
}
|
|
321
|
+
return out;
|
|
322
|
+
}
|
|
323
|
+
/** The raw text of an inline `style={{ … }}` attribute, if present. */
|
|
324
|
+
function styleValue(attrs) {
|
|
325
|
+
const i = attrs.indexOf('style');
|
|
326
|
+
if (i < 0)
|
|
327
|
+
return null;
|
|
328
|
+
const m = /style\s*=\s*\{/.exec(attrs.slice(i));
|
|
329
|
+
if (!m)
|
|
330
|
+
return null;
|
|
331
|
+
let depth = 0;
|
|
332
|
+
const start = i + m.index + m[0].length - 1;
|
|
333
|
+
for (let j = start; j < attrs.length; j++) {
|
|
334
|
+
if (attrs[j] === '{')
|
|
335
|
+
depth++;
|
|
336
|
+
else if (attrs[j] === '}') {
|
|
337
|
+
depth--;
|
|
338
|
+
if (depth === 0)
|
|
339
|
+
return attrs.slice(start, j + 1);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Does this element paint its OWN card chrome?
|
|
346
|
+
*
|
|
347
|
+
* Chrome means all three of border, radius and background, because that is
|
|
348
|
+
* exactly what `PageGridLayout` already paints on the slot. Two of the three is
|
|
349
|
+
* a tinted panel or a divider, not a second card — requiring all three is what
|
|
350
|
+
* separates BSU's `glass-card rounded-2xl border-primary/30` (a real double
|
|
351
|
+
* frame) from a `rounded-lg bg-muted` inline chip (not one).
|
|
352
|
+
*
|
|
353
|
+
* Chrome declared through `style={{ background, border, borderRadius }}` counts
|
|
354
|
+
* the same as chrome declared through classes. BSU's `Settings.tsx` is chrome
|
|
355
|
+
* entirely in inline style; a class-only detector calls that file clean, which
|
|
356
|
+
* is how a nested card hides from a gate that only reads Tailwind.
|
|
357
|
+
*/
|
|
358
|
+
export function elementDeclaresCardChrome(el, chromeTags) {
|
|
359
|
+
if (chromeTags.has(el.tag))
|
|
360
|
+
return `<${el.tag}> paints its own card chrome`;
|
|
361
|
+
if (CONTROL_TAGS.has(el.tag))
|
|
362
|
+
return null;
|
|
363
|
+
for (const value of classValues(el.attrs)) {
|
|
364
|
+
const composite = COMPOSITE_CARD_CLASS.test(value);
|
|
365
|
+
const hasBorder = composite || BORDER_CLASS.test(value);
|
|
366
|
+
const hasBg = composite || BG_CLASS.test(value);
|
|
367
|
+
if (RADIUS_CLASS.test(value) && hasBorder && hasBg)
|
|
368
|
+
return `<${el.tag}> className declares border + radius + background ("${value.replace(/\s+/g, ' ').trim().slice(0, 80)}")`;
|
|
369
|
+
}
|
|
370
|
+
const style = styleValue(el.attrs);
|
|
371
|
+
if (style && RADIUS_STYLE.test(style) && BORDER_STYLE.test(style) && BG_STYLE.test(style))
|
|
372
|
+
return `<${el.tag}> inline style declares border + radius + background`;
|
|
373
|
+
// Mixed: radius as a class, border+background as inline style. BSU
|
|
374
|
+
// `Settings.tsx` is exactly this shape.
|
|
375
|
+
if (style) {
|
|
376
|
+
const classText = classValues(el.attrs).join(' ');
|
|
377
|
+
const composite = COMPOSITE_CARD_CLASS.test(classText);
|
|
378
|
+
const hasRadius = RADIUS_CLASS.test(classText) || RADIUS_STYLE.test(style);
|
|
379
|
+
const hasBorder = composite || BORDER_CLASS.test(classText) || BORDER_STYLE.test(style);
|
|
380
|
+
const hasBg = composite || BG_CLASS.test(classText) || BG_STYLE.test(style);
|
|
381
|
+
if (hasRadius && hasBorder && hasBg)
|
|
382
|
+
return `<${el.tag}> declares border + radius + background across className and inline style`;
|
|
383
|
+
}
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Does this grid slot paint chrome of its OWN, post-inversion?
|
|
388
|
+
*
|
|
389
|
+
* Three ways to opt in, and all three have to be visible to the scanner or a
|
|
390
|
+
* re-chromed slot goes unnoticed: `itemChrome` on the grid component (whole
|
|
391
|
+
* app/page), `chrome: true` on the layout item, and `chrome` on the CanvasCard.
|
|
392
|
+
*/
|
|
393
|
+
export function slotOptsIntoChrome(fileSource, slotBody) {
|
|
394
|
+
const openTag = /^<CanvasCard[\s\S]*?>/.exec(slotBody)?.[0] ?? '';
|
|
395
|
+
if (/\bchrome\s*(?:=\s*\{?\s*true\b|\}|[\s/>])/.test(openTag) &&
|
|
396
|
+
!/\bchrome\s*=\s*\{\s*false\s*\}/.test(openTag))
|
|
397
|
+
return true;
|
|
398
|
+
if (/\bitemChrome\b(?!\s*=\s*\{\s*false\s*\})/.test(fileSource))
|
|
399
|
+
return true;
|
|
400
|
+
if (/\bchrome\s*:\s*true\b/.test(fileSource))
|
|
401
|
+
return true;
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
404
|
+
/** The first nested-chrome element inside one grid slot, or null. */
|
|
405
|
+
export function findNestedChrome(slotBody, config) {
|
|
406
|
+
const chromeTags = new Set([
|
|
407
|
+
...config.cardTags,
|
|
408
|
+
...(config.nestedChromeTags ?? DEFAULT_NESTED_CHROME_TAGS),
|
|
409
|
+
]);
|
|
410
|
+
// Skip the slot's own opening tag — `<CanvasCard>` is the grid item, not a
|
|
411
|
+
// child of it.
|
|
412
|
+
const inner = slotBody.replace(/^<CanvasCard[\s\S]*?>/, '');
|
|
413
|
+
for (const el of openingTags(inner)) {
|
|
414
|
+
const hit = elementDeclaresCardChrome(el, chromeTags);
|
|
415
|
+
if (hit)
|
|
416
|
+
return hit;
|
|
417
|
+
}
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Can this file be parsed with confidence?
|
|
422
|
+
*
|
|
423
|
+
* Returns a reason when it CANNOT. Every `<CanvasCard` must pair with a
|
|
424
|
+
* `</CanvasCard>` the block regex can reach, and every `widgets={{` must close
|
|
425
|
+
* before EOF. A file that fails either is UNKNOWN — it is not reported clean,
|
|
426
|
+
* and it is not silently skipped. "Checked nothing" and "found nothing" do not
|
|
427
|
+
* share an exit code here.
|
|
428
|
+
*/
|
|
429
|
+
export function parseConfidence(src) {
|
|
430
|
+
const opens = (src.match(/<CanvasCard[\s/>]/g) ?? []).length;
|
|
431
|
+
const selfClosing = (src.match(/<CanvasCard[^<>]*\/>/g) ?? []).length;
|
|
432
|
+
const closes = (src.match(/<\/CanvasCard>/g) ?? []).length;
|
|
433
|
+
if (opens - selfClosing !== closes)
|
|
434
|
+
return `unbalanced CanvasCard tags: ${opens} opening (${selfClosing} self-closing) vs ${closes} closing`;
|
|
435
|
+
const blocks = extractCanvasCardBlocks(src).length;
|
|
436
|
+
if (blocks !== closes)
|
|
437
|
+
return `CanvasCard block extraction recovered ${blocks} of ${closes} blocks (nested or dynamically composed CanvasCards)`;
|
|
438
|
+
const widgetStarts = (src.match(/widgets=\{\{/g) ?? []).length;
|
|
439
|
+
if (widgetStarts > 0) {
|
|
440
|
+
const re = /widgets=\{\{/g;
|
|
441
|
+
let m;
|
|
442
|
+
while ((m = re.exec(src)) !== null) {
|
|
443
|
+
let depth = 2;
|
|
444
|
+
let i = m.index + m[0].length;
|
|
445
|
+
while (i < src.length && depth > 0) {
|
|
446
|
+
if (src[i] === '{')
|
|
447
|
+
depth++;
|
|
448
|
+
else if (src[i] === '}')
|
|
449
|
+
depth--;
|
|
450
|
+
i++;
|
|
451
|
+
}
|
|
452
|
+
if (depth !== 0)
|
|
453
|
+
return 'widgets={{ … }} object literal never closes before EOF';
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
162
458
|
function walk(dir, extensions, acc) {
|
|
163
459
|
for (const entry of readdirSync(dir)) {
|
|
164
460
|
if (entry === 'node_modules' || entry === 'dist' || entry === '.git')
|
|
@@ -177,6 +473,7 @@ export function scanCardSurfaces(config) {
|
|
|
177
473
|
const findings = [];
|
|
178
474
|
const files = [];
|
|
179
475
|
const scanRootsResolved = [];
|
|
476
|
+
const unknownFiles = [];
|
|
180
477
|
// D-92: assert the inputs were present BEFORE reporting any verdict. A
|
|
181
478
|
// missing scan root must fail loudly, not produce a confident zero.
|
|
182
479
|
for (const root of config.scanRoots) {
|
|
@@ -216,14 +513,53 @@ export function scanCardSurfaces(config) {
|
|
|
216
513
|
}
|
|
217
514
|
for (const file of files) {
|
|
218
515
|
const rel = relative(config.projectRoot, file);
|
|
219
|
-
|
|
516
|
+
let raw;
|
|
517
|
+
try {
|
|
518
|
+
raw = readFileSync(file, 'utf8');
|
|
519
|
+
}
|
|
520
|
+
catch (err) {
|
|
521
|
+
// A file we could not READ is UNKNOWN, never clean.
|
|
522
|
+
unknownFiles.push(rel);
|
|
523
|
+
findings.push({
|
|
524
|
+
file: rel,
|
|
525
|
+
idiom: 'unparseable',
|
|
526
|
+
detail: `could not be read: ${err.message}`,
|
|
527
|
+
});
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
220
530
|
const src = stripComments(raw);
|
|
531
|
+
// D-92 fail-closed: decide whether this file can be parsed with confidence
|
|
532
|
+
// BEFORE reporting any verdict about it. An UNKNOWN file is recorded as
|
|
533
|
+
// UNKNOWN and still scanned on a best-effort basis — what it must never do
|
|
534
|
+
// is contribute a silent "clean".
|
|
535
|
+
const unparseable = parseConfidence(src);
|
|
536
|
+
if (unparseable) {
|
|
537
|
+
unknownFiles.push(rel);
|
|
538
|
+
findings.push({ file: rel, idiom: 'unparseable', detail: unparseable });
|
|
539
|
+
}
|
|
221
540
|
// --- glued widget: 2+ cards inside ONE grid slot -----------------------
|
|
222
541
|
const slots = [
|
|
223
542
|
...extractCanvasCardBlocks(src).map((b, i) => ({ label: `CanvasCard#${i + 1}`, body: b })),
|
|
224
543
|
...extractWidgetEntries(src).map((e) => ({ label: `widgets.${e.key}`, body: e.body })),
|
|
225
544
|
];
|
|
545
|
+
let nestedChromeReported = false;
|
|
226
546
|
for (const slot of slots) {
|
|
547
|
+
// --- V-C5 nested chrome: ONE card inside ONE slot is still a double
|
|
548
|
+
// frame, and V-C4 below cannot see it (it needs 2+).
|
|
549
|
+
const gridItemChromed = (config.gridItemPaintsChrome ?? true) || slotOptsIntoChrome(src, slot.body);
|
|
550
|
+
if (gridItemChromed && !nestedChromeReported && !config.nestedChromeExclusions?.[rel]) {
|
|
551
|
+
const chrome = findNestedChrome(slot.body, config);
|
|
552
|
+
if (chrome) {
|
|
553
|
+
nestedChromeReported = true;
|
|
554
|
+
findings.push({
|
|
555
|
+
file: rel,
|
|
556
|
+
idiom: 'nested-chrome',
|
|
557
|
+
detail: `${slot.label} ${chrome}. The grid item already paints ` +
|
|
558
|
+
`rounded-3xl + bg-card + border-border, so this renders a card inside a card — ` +
|
|
559
|
+
`mismatched corners and a doubled 1px edge.`,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
227
563
|
const n = countCardTags(slot.body, config);
|
|
228
564
|
const mapped = hasMappedCards(slot.body, config);
|
|
229
565
|
if (n > 1 || mapped) {
|
|
@@ -280,10 +616,23 @@ export function scanCardSurfaces(config) {
|
|
|
280
616
|
...Object.keys(config.gluedExclusions ?? {}).filter((f) => !hit.has(`glued-widget:${f}`) && !hit.has(`autoheight-optout:${f}`)),
|
|
281
617
|
...Object.keys(config.ungriddedExclusions ?? {}).filter((f) => !hit.has(`ungridded-multi-card:${f}`)),
|
|
282
618
|
];
|
|
619
|
+
const nestedChromeFiles = [
|
|
620
|
+
...new Set(findings.filter((f) => f.idiom === 'nested-chrome').map((f) => f.file)),
|
|
621
|
+
];
|
|
283
622
|
const summary = `scanned ${files.length} files across ${scanRootsResolved.length} root(s) [${scanRootsResolved.join(', ')}] ` +
|
|
284
623
|
`with cardTags [${config.cardTags.join(', ')}]` +
|
|
285
624
|
`${config.classSurfaces?.length ? ` + ${config.classSurfaces.length} class surface pattern(s)` : ''}; ` +
|
|
286
|
-
`${findings.length} finding(s)
|
|
287
|
-
`${
|
|
288
|
-
|
|
625
|
+
`${findings.length} finding(s) incl. ${nestedChromeFiles.length} nested-chrome file(s); ` +
|
|
626
|
+
`${Object.keys(config.blindSpots ?? {}).length} declared blind spot(s); ` +
|
|
627
|
+
`${staleExclusions.length} stale exclusion(s); ` +
|
|
628
|
+
`${unknownFiles.length} UNKNOWN file(s) — an UNKNOWN is not a clean file.`;
|
|
629
|
+
return {
|
|
630
|
+
findings,
|
|
631
|
+
filesScanned: files.length,
|
|
632
|
+
scanRootsResolved,
|
|
633
|
+
staleExclusions,
|
|
634
|
+
unknownFiles,
|
|
635
|
+
nestedChromeFiles,
|
|
636
|
+
summary,
|
|
637
|
+
};
|
|
289
638
|
}
|
package/dist/scanner/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { scanCardSurfaces, stripComments } from './cardSurfaceScanner.js';
|
|
1
|
+
export { scanCardSurfaces, stripComments, openingTags, elementDeclaresCardChrome, findNestedChrome, parseConfidence, slotOptsIntoChrome, } from './cardSurfaceScanner.js';
|
|
2
2
|
export type { CardSurfaceScannerConfig, CardSurfaceScanResult, CardSurfaceFinding, CardSurfaceIdiom, } from './cardSurfaceScanner.js';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scanner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC"}
|
package/dist/scanner/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { scanCardSurfaces, stripComments } from './cardSurfaceScanner.js';
|
|
1
|
+
export { scanCardSurfaces, stripComments, openingTags, elementDeclaresCardChrome, findNestedChrome, parseConfidence, slotOptsIntoChrome, } from './cardSurfaceScanner.js';
|
package/dist/types.d.ts
CHANGED
|
@@ -15,6 +15,17 @@ export interface GridLayoutItem extends LayoutItem {
|
|
|
15
15
|
* operator-mandated capability. See the `activeLayouts` memo.
|
|
16
16
|
*/
|
|
17
17
|
autoHeight?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Paint THIS item as a card — border, radius, background, shadow.
|
|
20
|
+
*
|
|
21
|
+
* Undefined falls back to `PageGridLayout`'s `itemChrome`, which is FALSE.
|
|
22
|
+
* Up to 1.0.7 every grid item painted chrome unconditionally and there was
|
|
23
|
+
* no way to turn it off; 332 files across six apps render their own card
|
|
24
|
+
* inside it. Set this true on a slot whose content is BARE — a heading, a
|
|
25
|
+
* chart, a list with no surface of its own — and leave it alone everywhere
|
|
26
|
+
* the content already is a card.
|
|
27
|
+
*/
|
|
28
|
+
chrome?: boolean;
|
|
18
29
|
/**
|
|
19
30
|
* True once the user has resized this item with the SE handle.
|
|
20
31
|
*
|
|
@@ -147,6 +158,15 @@ export interface PageGridLayoutProps extends UsePageGridLayoutOptions {
|
|
|
147
158
|
widgetMeta?: Record<string, WidgetMeta>;
|
|
148
159
|
className?: string;
|
|
149
160
|
isResizable?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Paint every grid item as a card unless the item says otherwise.
|
|
163
|
+
*
|
|
164
|
+
* DEFAULT FALSE. This is the app-level migration lever for the 1.1.0 chrome
|
|
165
|
+
* inversion: an app that has not yet migrated its bare slots passes
|
|
166
|
+
* `itemChrome` and gets the pre-1.1.0 look back exactly, then flips slot by
|
|
167
|
+
* slot with `GridLayoutItem.chrome`. Per-item always wins.
|
|
168
|
+
*/
|
|
169
|
+
itemChrome?: boolean;
|
|
150
170
|
resizeHandles?: readonly ResizeHandleAxis[];
|
|
151
171
|
/**
|
|
152
172
|
* The signed-in caller's tenant. Threaded into every widget-factory call
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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":"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;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,cAAc,EAAE,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC1C,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,CAAC,KACR,yBAAyB,CAAC,CAAC,CAAC,CAAC;AAElC,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,WAAW,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;IAC9C;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA2B,SAAQ,kBAAkB;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAYD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gCAAiC,SAAQ,wBAAwB;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,wBAAwB,EAAE,CAAC;AAEtE,MAAM,WAAW,mBAAoB,SAAQ,wBAAwB;IACnE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,yBAAyB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,KAAK,CAAC,SAAS,CAAC;IAC9E,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACtF;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,+BAA+B,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpD,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,gCAAgC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1F,4BAA4B,CAAC,EAAE,CAAC,OAAO,EAAE,wBAAwB,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAClG;;;;;OAKG;IACH,4BAA4B,CAAC,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;CAC3E;AAED,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,WAAW,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,eAAe,EAAE,SAAS,CAAC;IAC3B,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnF,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C;;;;;;OAMG;IACH,sBAAsB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,SAAS,EAAE,CACT,SAAS,EAAE,MAAM,EACjB,WAAW,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,GAAG,GAAG,GAAG,MAAM,GAAG,MAAM,CAAC,CAAC,KACrE,IAAI,CAAC;IACV,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IAClE,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C;;;;;;;;;;OAUG;IACH,mBAAmB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACpE;0CACsC;IACtC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACnE,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAClD,cAAc,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -27,10 +27,17 @@ export declare const PAGE_GRID_EDITING_EVENT = "bsuite-page-grid-editing";
|
|
|
27
27
|
* was additionally polluted with frozen derived breakpoints, so all of them
|
|
28
28
|
* reset once to the corrected defaults.
|
|
29
29
|
*
|
|
30
|
+
* 1000 -> 2000 (2026-08-25, V-C5/G1): two more all-grids defaults changed in
|
|
31
|
+
* one release — the grid item no longer paints card chrome, and a `CanvasCard`
|
|
32
|
+
* that omits `w` is now half the grid rather than all of it. Every stored
|
|
33
|
+
* layout was written under the old width default, so a saved `w: 12` would
|
|
34
|
+
* fight the new default forever and the page would keep stacking. An epoch
|
|
35
|
+
* bump is the only lever that reaches every consumer at once.
|
|
36
|
+
*
|
|
30
37
|
* Per-page `layoutVersion` bumps keep working on top; this only moves the
|
|
31
38
|
* floor.
|
|
32
39
|
*/
|
|
33
|
-
export declare const PACKAGE_LAYOUT_EPOCH =
|
|
40
|
+
export declare const PACKAGE_LAYOUT_EPOCH = 2000;
|
|
34
41
|
export interface PageGridEditingEventDetail {
|
|
35
42
|
pageKey: string;
|
|
36
43
|
editing: boolean;
|
|
@@ -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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAC;AAiBzC,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,GAClB,EAAE,wBAAwB,GAAG,uBAAuB,CA2sBpD"}
|
|
@@ -37,10 +37,17 @@ export const PAGE_GRID_EDITING_EVENT = 'bsuite-page-grid-editing';
|
|
|
37
37
|
* was additionally polluted with frozen derived breakpoints, so all of them
|
|
38
38
|
* reset once to the corrected defaults.
|
|
39
39
|
*
|
|
40
|
+
* 1000 -> 2000 (2026-08-25, V-C5/G1): two more all-grids defaults changed in
|
|
41
|
+
* one release — the grid item no longer paints card chrome, and a `CanvasCard`
|
|
42
|
+
* that omits `w` is now half the grid rather than all of it. Every stored
|
|
43
|
+
* layout was written under the old width default, so a saved `w: 12` would
|
|
44
|
+
* fight the new default forever and the page would keep stacking. An epoch
|
|
45
|
+
* bump is the only lever that reaches every consumer at once.
|
|
46
|
+
*
|
|
40
47
|
* Per-page `layoutVersion` bumps keep working on top; this only moves the
|
|
41
48
|
* floor.
|
|
42
49
|
*/
|
|
43
|
-
export const PACKAGE_LAYOUT_EPOCH =
|
|
50
|
+
export const PACKAGE_LAYOUT_EPOCH = 2000;
|
|
44
51
|
/**
|
|
45
52
|
* Default for `GridLayoutItem.autoHeight` when an item does not state one.
|
|
46
53
|
*
|
|
@@ -55,57 +62,6 @@ export const PACKAGE_LAYOUT_EPOCH = 1000;
|
|
|
55
62
|
* opts out with an explicit `autoHeight: false`.
|
|
56
63
|
*/
|
|
57
64
|
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
|
-
return compare(a, b, false);
|
|
73
|
-
}
|
|
74
|
-
/** Same, but blind to the height of items whose height is MEASURED, not authored. */
|
|
75
|
-
function samePlacement(a, b) {
|
|
76
|
-
return compare(a, b, true);
|
|
77
|
-
}
|
|
78
|
-
function compare(a, b, ignoreDerivedHeight) {
|
|
79
|
-
if (!a || !b)
|
|
80
|
-
return false;
|
|
81
|
-
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
82
|
-
/*
|
|
83
|
-
* `h` is EXCLUDED for an autoHeight item, and that exclusion is the whole point.
|
|
84
|
-
*
|
|
85
|
-
* An autoHeight card's height is MEASURED, not authored: change the column count,
|
|
86
|
-
* the card gets narrower, its content rewraps taller, and the ResizeObserver
|
|
87
|
-
* emits a new `h`. That emission differs from what was rendered, so a comparison
|
|
88
|
-
* including `h` calls it a gesture — and commits the RESCALED WIDTHS riding along
|
|
89
|
-
* with it. Measured: three cards authored w=4,3,4 came back w=1,1,1 after nothing
|
|
90
|
-
* but a height re-measure.
|
|
91
|
-
*
|
|
92
|
-
* NARROWED, because the first version was too broad and two existing tests said
|
|
93
|
-
* so: a user CAN drag an autoHeight card's height, and that stamps `hUserSet`.
|
|
94
|
-
* Once stamped, the height IS a choice and must be compared like any other. So
|
|
95
|
-
* `h` is excluded only where it is purely derived — autoHeight AND not user-set.
|
|
96
|
-
* A real resize changes `w`, or stamps `hUserSet`, or both; none of those are
|
|
97
|
-
* hidden by this.
|
|
98
|
-
*/
|
|
99
|
-
const fingerprint = (items) => (items ?? [])
|
|
100
|
-
.map((i) => `${i.i}:${i.x}:${i.y}:${i.w}:${ignoreDerivedHeight && i.autoHeight ? 'auto' : i.h}`)
|
|
101
|
-
.sort()
|
|
102
|
-
.join('|');
|
|
103
|
-
for (const k of keys) {
|
|
104
|
-
if (fingerprint(a[k]) !== fingerprint(b[k]))
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
65
|
export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, layoutVersion = 1, canEditPage = true, editorEventNames = DEFAULT_EDITOR_EVENT_NAMES, preferenceAdapter = defaultPreferenceAdapter, defaultAutoHeight, }) {
|
|
110
66
|
const effectiveLayoutVersion = layoutVersion + PACKAGE_LAYOUT_EPOCH;
|
|
111
67
|
const containerRef = useRef(null);
|
|
@@ -512,28 +468,33 @@ export function usePageGridLayout({ pageKey, defaultLayouts, defaultCols = 12, l
|
|
|
512
468
|
* Identified by comparison rather than by a flag, so it needs no event
|
|
513
469
|
* ordering to be correct.
|
|
514
470
|
*/
|
|
515
|
-
const emitted = layouts;
|
|
516
|
-
/* Identical to what was just rendered: a pure reflow, nothing to commit. */
|
|
517
|
-
if (sameArrangement(emitted, currentLayouts))
|
|
518
|
-
return;
|
|
519
471
|
/*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
472
|
+
* ONLY A POINTER GESTURE MAY COMMIT A LAYOUT. Nothing else.
|
|
473
|
+
*
|
|
474
|
+
* Three attempts tried to classify the emission by SHAPE and all three
|
|
475
|
+
* shipped and all three failed on the deployed app:
|
|
476
|
+
*
|
|
477
|
+
* 1.0.4 removed the writes in handleColumnChange — the grid still emitted
|
|
478
|
+
* 1.0.5 skipped an emission equal to what we rendered
|
|
479
|
+
* 1.0.6 ...ignoring measured heights as well
|
|
480
|
+
*
|
|
481
|
+
* Shape can never work, and the reason is structural: react-grid-layout
|
|
482
|
+
* COMPACTS after a reflow. Its emission is therefore legitimately different
|
|
483
|
+
* from `currentLayouts` in x and y, so every comparison against what we
|
|
484
|
+
* rendered says "this is a gesture" and commits the rescaled arrangement.
|
|
485
|
+
* Measured on d.crm.crm7.app with 1.0.6 confirmed in the served bundle: a
|
|
486
|
+
* 12 -> 4 -> 8 -> 2 -> 12 round trip produced THIRTEEN writes and turned
|
|
487
|
+
* widths 4,4,4,7,5,5,12 into 6,6,6,6,6,6,6.
|
|
524
488
|
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
* existing caller behaving exactly as before; `PageGridLayout` passes the
|
|
528
|
-
* real answer.
|
|
489
|
+
* The grid knows what we cannot infer: whether a pointer gesture produced
|
|
490
|
+
* this emission. That is the only sound signal, so it is the whole rule.
|
|
529
491
|
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
534
|
-
* silently dropped, which is crm7#744 reopened.
|
|
492
|
+
* Every other mutation — add, remove, compact, reset — calls `commitItems`
|
|
493
|
+
* directly and is unaffected. A deliberate resize of an auto-height card
|
|
494
|
+
* (crm7#744) IS a gesture and still commits. `wasGesture` defaults to true,
|
|
495
|
+
* so any caller that does not pass it behaves exactly as before.
|
|
535
496
|
*/
|
|
536
|
-
if (!wasGesture
|
|
497
|
+
if (!wasGesture)
|
|
537
498
|
return;
|
|
538
499
|
pendingLayoutRef.current = layouts;
|
|
539
500
|
if (layoutCommitFrameRef.current !== null)
|