@bsuite/page-builder 2.7.1-next.3 → 2.7.1-next.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,6 +58,19 @@ a React transition. Initial mounting, unchanged state and abandoned transitions
58
58
  do not emit notifications. Consumers must match the page key and preserve
59
59
  focus on surviving inputs when synchronizing their header controls.
60
60
 
61
+ From `2.7.1-next.5`, a header Save & exit dispatches `PAGE_GRID_SAVE_EVENT`
62
+ with `{ pageKey }`. The canvas waits for all preference adapters, keeps its
63
+ controls and error visible on failure, and emits the existing committed editing
64
+ notification on success. Headers wait for that notification before clearing
65
+ edit mode. Existing open/close events remain available for route navigation.
66
+
67
+ Selected depths expose separate resting, light-interaction and dark-interaction
68
+ shadow variables. Light interaction adds neutral elevation; dark interaction
69
+ adds the role-bound glow while retaining the selected depth. Explicit zero
70
+ stays flat. Consumers must read all three variables; chrome-owning grid items
71
+ already do. Default painted grid cards now use neutral elevation 2, with
72
+ interaction feedback, matching the D2C card recovery.
73
+
61
74
  While the canvas editor is open, each grid item renders an in-flow strip
62
75
  (`[data-slot="grid-item-editor-chrome"]`) above the card content: the widget
63
76
  name and a Hide control. The strip is **not** absolutely positioned over the
@@ -2,5 +2,10 @@ 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
+ /** Ask one mounted canvas to acknowledge its preferences before closing. */
6
+ export declare const PAGE_GRID_SAVE_EVENT = "bsuite-page-grid-save";
7
+ export interface PageGridSaveEventDetail {
8
+ pageKey: string;
9
+ }
5
10
  export declare function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className, isResizable, resizeHandles, tenantId, defaultAutoHeight, layoutMigrations, itemChrome, addEntityWidgetEventNames, createEntityWidget, onRegisterEntityWidget, relationshipCatalog, addRelationshipWidgetEventNames, createRelationshipWidget, onRegisterRelationshipWidget, onRelationshipWidgetRejected, }: PageGridLayoutProps): React.JSX.Element;
6
11
  //# sourceMappingURL=PageGridLayout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAsBxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;AA4pB7F,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,OAAO,EACP,UAAU,EACV,SAAS,EAMT,WAAkB,EAClB,aAAsC,EACtC,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAKhB,UAAkB,EAClB,yBAAiE,EACjE,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,+BAA6E,EAC7E,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,GAC7B,EAAE,mBAAmB,qBAmgCrB"}
1
+ {"version":3,"file":"PageGridLayout.d.ts","sourceRoot":"","sources":["../src/PageGridLayout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAQN,MAAM,OAAO,CAAC;AAGf,OAAO,kCAAkC,CAAC;AAC1C,OAAO,gCAAgC,CAAC;AAsBxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;AAE7F,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAC5D,MAAM,WAAW,uBAAuB;IAAG,OAAO,EAAE,MAAM,CAAA;CAAE;AAiqB5D,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,OAAO,EACP,UAAU,EACV,SAAS,EAMT,WAAkB,EAClB,aAAsC,EACtC,QAAQ,EACR,iBAAiB,EACjB,gBAAgB,EAKhB,UAAkB,EAClB,yBAAiE,EACjE,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,+BAA6E,EAC7E,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,GAC7B,EAAE,mBAAmB,qBAkhCrB"}
@@ -12,6 +12,8 @@ import { defaultPreferenceAdapter } from './preferences.js';
12
12
  import { isRelationshipWritable } from './relationshipCatalog.js';
13
13
  import { usePageGridLayout } from './usePageGridLayout.js';
14
14
  import { cn } from './utils.js';
15
+ /** Ask one mounted canvas to acknowledge its preferences before closing. */
16
+ export const PAGE_GRID_SAVE_EVENT = 'bsuite-page-grid-save';
15
17
  /**
16
18
  * Single source of truth for the grid's pixel geometry — read by both the
17
19
  * `<Responsive>` props below AND `GridItem`'s auto-height measurement
@@ -187,6 +189,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
187
189
  */
188
190
  const scopedContent = (_jsx(ElementScopeProvider, { scope: { pageKey, cardKey: id, cardLabel: label, isEditing }, children: content }));
189
191
  const measureRef = useRef(null);
192
+ const surfaceRef = useRef(null);
190
193
  const lastReportedRowsRef = useRef(null);
191
194
  const measureRafRef = useRef(null);
192
195
  /**
@@ -216,9 +219,17 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
216
219
  const reportRows = useCallback((contentPx) => {
217
220
  if (!onAutoHeightChange)
218
221
  return;
222
+ // Chrome lives outside the observed content box. Count its actual
223
+ // padding and borders so appearance changes cannot overlap the next
224
+ // card. A consumer-owned Card is already inside the measured content.
225
+ const surfaceStyle = chrome && surfaceRef.current ? getComputedStyle(surfaceRef.current) : null;
226
+ const cardChromePx = surfaceStyle
227
+ ? [surfaceStyle.paddingTop, surfaceStyle.paddingBottom, surfaceStyle.borderTopWidth, surfaceStyle.borderBottomWidth]
228
+ .reduce((total, value) => total + (Number.parseFloat(value) || 0), 0)
229
+ : DEFAULT_CARD_CHROME_PX;
219
230
  const rows = computeAutoHeightRows({
220
231
  contentPx,
221
- cardChromePx: DEFAULT_CARD_CHROME_PX,
232
+ cardChromePx,
222
233
  rowHeightPx: DEFAULT_ROW_HEIGHT,
223
234
  marginYPx: DEFAULT_MARGIN[1],
224
235
  });
@@ -226,7 +237,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
226
237
  return;
227
238
  lastReportedRowsRef.current = rows;
228
239
  onAutoHeightChange(id, rows);
229
- }, [id, onAutoHeightChange]);
240
+ }, [chrome, id, onAutoHeightChange]);
230
241
  /**
231
242
  * First measurement BEFORE paint (second half of D-76).
232
243
  *
@@ -257,7 +268,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
257
268
  warnOnceAboutCollapsedContent(el);
258
269
  // Re-measure when edit chrome mounts/unmounts so the strip is in the
259
270
  // row count in edit mode and gone again on lossless return.
260
- }, [autoHeight, onAutoHeightChange, reportRows, isEditing]);
271
+ }, [autoHeight, onAutoHeightChange, reportRows, isEditing, cardStyleVars]);
261
272
  useEffect(() => {
262
273
  if (!autoHeight || !onAutoHeightChange)
263
274
  return;
@@ -307,7 +318,7 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
307
318
  // (buttons, inputs, textarea, select, links, [data-no-drag]) are still
308
319
  // protected via the `cancel` selector below in the <Responsive> render.
309
320
  const outerClass = cn('relative group overflow-visible', isEditing && 'drag-handle cursor-move', injectedClassName);
310
- return (_jsxs("div", { ref: ref, className: outerClass, style: injectedStyle, ...rest, children: [_jsxs("div", { className: "h-full w-full relative", children: [isEditing && (_jsx("div", { className: "absolute inset-0 z-10 pointer-events-none rounded-3xl border-2 border-transparent group-hover:border-primary/50 transition-colors bg-primary/5" })), _jsx("div", { "data-slot": "grid-item-surface", "data-chrome": chrome ? 'on' : 'off', "data-grid-slot-key": id, className: chrome
321
+ return (_jsxs("div", { ref: ref, className: outerClass, style: injectedStyle, ...rest, children: [_jsxs("div", { className: "h-full w-full relative", children: [isEditing && (_jsx("div", { className: "absolute inset-0 z-10 pointer-events-none rounded-3xl border-2 border-transparent group-hover:border-primary/50 transition-colors bg-primary/5" })), _jsx("div", { "data-slot": "grid-item-surface", "data-chrome": chrome ? 'on' : 'off', "data-grid-slot-key": id, ref: surfaceRef, "data-card-padding": !chrome && cardStyleVars && '--card-padding' in cardStyleVars ? '' : undefined, className: chrome
311
322
  ? // ONE radius token, read by the grid item AND available to any
312
323
  // app card that opts into the same surface. Two surfaces
313
324
  // reading the SAME var is what makes their corners align, and
@@ -321,14 +332,9 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
321
332
  // whose fallbacks are byte-identical to the `border
322
333
  // border-border` they replace, so an operator who has never
323
334
  // opened the card editor sees exactly the previous CSS.
324
- // The shadow deliberately keeps its ORIGINAL classes. An
325
- // elevation choice arrives as an inline `boxShadow`, which
326
- // beats the class without needing a fallback that restates
327
- // `shadow-sm`. Writing that fallback by hand was the first
328
- // attempt and it was wrong: elev-1 is CLOSE to shadow-sm
329
- // but not equal, so it would have silently restyled every
330
- // card on 305 pages the day this shipped.
331
- 'w-full rounded-[var(--radius-card,1.5rem)] transition-all flex flex-col bg-card border-[length:var(--card-border-width,1px)] border-[color:var(--card-border-color,var(--border))] [border-style:var(--card-border-style,solid)] shadow-sm dark:shadow-[var(--glow-card,none)]',
335
+ // Resting elevation and interaction feedback are separate:
336
+ // a selected depth must not suppress hover/focus feedback.
337
+ 'w-full rounded-[var(--radius-card,1.5rem)] transition-all flex flex-col bg-card border-[length:var(--card-border-width,1px)] border-[color:var(--card-border-color,var(--border))] [border-style:var(--card-border-style,solid)] shadow-[var(--card-shadow,var(--shadow-elev-2))] hover:shadow-[var(--card-shadow-interaction,var(--shadow-elev-3))] focus-within:shadow-[var(--card-shadow-interaction,var(--shadow-elev-3))] dark:hover:shadow-[var(--card-shadow-interaction-dark,var(--glow-card-hover))] dark:focus-within:shadow-[var(--card-shadow-interaction-dark,var(--glow-card-hover))]',
332
338
  // THE DOUBLED BOTTOM BORDER, AND WHY THE ARITHMETIC COULD NEVER FIX IT.
333
339
  //
334
340
  // computeAutoHeightRows uses Math.ceil to round content height up to
@@ -358,17 +364,16 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
358
364
  * `cardStyleVars` carries ONLY the properties the operator changed
359
365
  * (see cardStyle.ts). An untouched page spreads an empty object, so
360
366
  * this attribute is identical to what it was before the card editor
361
- * existed. A chrome-owning surface applies `boxShadow` directly
362
- * to beat its default class. Layout-only wrappers pass the token
363
- * to the painted consumer without drawing a second shadow.
367
+ * existed. A chrome-owning surface reads shadow tokens in its
368
+ * resting and interaction classes. Layout-only wrappers pass them
369
+ * to the painted consumer without drawing a second shadow. The
370
+ * padding marker lets consumer Cards distinguish an explicit page
371
+ * inset from an app's unrelated default --card-padding token.
364
372
  */
365
373
  style: {
366
374
  contain: 'layout style',
367
375
  ...cardStyleVars,
368
- ...(chrome && cardStyleVars && '--card-shadow' in cardStyleVars
369
- ? { boxShadow: cardStyleVars['--card-shadow'] }
370
- : null),
371
- ...(cardStyleVars && '--card-padding' in cardStyleVars
376
+ ...(chrome && cardStyleVars && '--card-padding' in cardStyleVars
372
377
  ? { padding: cardStyleVars['--card-padding'] }
373
378
  : null),
374
379
  }, children: autoHeight ? (_jsx("div", { "data-slot": "grid-item-body", className: "min-h-0 flex-none overflow-visible", children: _jsxs("div", { ref: measureRef, className: "flow-root", children: [isEditing ? (_jsx(GridItemEditorChrome, { id: id, label: label, onHide: onHide })) : null, scopedContent] }) })) : (_jsxs(_Fragment, { children: [isEditing ? (_jsx(GridItemEditorChrome, { id: id, label: label, onHide: onHide })) : null, _jsx("div", { "data-slot": "grid-item-body", className: "min-h-0 flex-1 overflow-auto", children: scopedContent })] })) })] }), injectedChildren] }));
@@ -400,7 +405,11 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
400
405
  const isSaving = saveState?.pageKey === pageKey && saveState.status === 'saving';
401
406
  const saveFailed = saveState?.pageKey === pageKey && saveState.status === 'failed';
402
407
  const saveAttempt = useRef(0);
403
- useLayoutEffect(() => () => { saveAttempt.current += 1; }, [pageKey, isEditing]);
408
+ const savingAttempt = useRef(null);
409
+ useLayoutEffect(() => () => {
410
+ saveAttempt.current += 1;
411
+ savingAttempt.current = null;
412
+ }, [pageKey, isEditing]);
404
413
  // Auto-height dispatcher (blueprint amendment A1, hardened per quality
405
414
  // review 2026-07-14). `GridItem`'s ResizeObserver calls this per-widget
406
415
  // whenever its measured content height changes; we rAF-batch and flush ALL
@@ -482,9 +491,10 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
482
491
  const cardStyleVars = useMemo(() => toCssVars(cardStyle), [cardStyle]);
483
492
  const updateCardStyle = useCallback((patch) => setStoredCardStyle((previous) => ({ ...normaliseCardStyle(previous), ...patch })), [setStoredCardStyle]);
484
493
  const saveAndExit = useCallback(async () => {
485
- if (isSaving)
494
+ if (canEditPage === false || !isEditing || savingAttempt.current !== null)
486
495
  return;
487
496
  const attempt = ++saveAttempt.current;
497
+ savingAttempt.current = attempt;
488
498
  setSaveState({ pageKey, status: 'saving' });
489
499
  try {
490
500
  await Promise.all([flushPreferences(), flushLayerNames?.(), flushHiddenLayers?.(), flushCardStyle?.()]);
@@ -497,7 +507,20 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
497
507
  if (attempt === saveAttempt.current)
498
508
  setSaveState({ pageKey, status: 'failed' });
499
509
  }
500
- }, [isSaving, pageKey, flushPreferences, flushLayerNames, flushHiddenLayers, flushCardStyle, setIsEditing]);
510
+ finally {
511
+ if (savingAttempt.current === attempt)
512
+ savingAttempt.current = null;
513
+ }
514
+ }, [canEditPage, isEditing, pageKey, flushPreferences, flushLayerNames, flushHiddenLayers, flushCardStyle, setIsEditing]);
515
+ useEffect(() => {
516
+ const onSaveRequest = (event) => {
517
+ const detail = event.detail;
518
+ if (detail?.pageKey === pageKey)
519
+ void saveAndExit();
520
+ };
521
+ window.addEventListener(PAGE_GRID_SAVE_EVENT, onSaveRequest);
522
+ return () => window.removeEventListener(PAGE_GRID_SAVE_EVENT, onSaveRequest);
523
+ }, [pageKey, saveAndExit]);
501
524
  const extraWidgets = useMemo(() => {
502
525
  const rendered = {};
503
526
  if (!createEntityWidget)
@@ -26,9 +26,8 @@ export interface CardStyle {
26
26
  *
27
27
  * `radius: 24` is `1.5rem`, the existing `--radius-card` fallback.
28
28
  * `borderWidth: 1` + `borderTone: 'border'` is the existing `border
29
- * border-border`. `elevation: null` preserves `shadow-sm` and the dark-mode
30
- * `--glow-card` rule rather than replacing them with an elevation token that
31
- * is close but not equal.
29
+ * border-border`. `elevation: null` leaves the component's resting and
30
+ * interaction defaults in place; an explicit zero opts out of both.
32
31
  */
33
32
  export declare const DEFAULT_CARD_STYLE: CardStyle;
34
33
  export declare const RADIUS_RANGE: {
@@ -1 +1 @@
1
- {"version":3,"file":"cardStyle.d.ts","sourceRoot":"","sources":["../src/cardStyle.ts"],"names":[],"mappings":"AA0BA,4EAA4E;AAC5E,eAAO,MAAM,YAAY,iFAOf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,aAAa,gDAAiD,CAAC;AAC5E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE1C,MAAM,WAAW,SAAS;IACxB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB;;;OAGG;IACH,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAOhC,CAAC;AAEF,eAAO,MAAM,YAAY;;;CAA+B,CAAC;AACzD,eAAO,MAAM,kBAAkB;;;CAA8B,CAAC;AAC9D,eAAO,MAAM,aAAa;;;CAA+B,CAAC;AAO1D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CA8B5D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAS5D;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,aAAa,CAuB/D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAc1D"}
1
+ {"version":3,"file":"cardStyle.d.ts","sourceRoot":"","sources":["../src/cardStyle.ts"],"names":[],"mappings":"AA0BA,4EAA4E;AAC5E,eAAO,MAAM,YAAY,iFAOf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,aAAa,gDAAiD,CAAC;AAC5E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,gEAAgE;AAChE,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE1C,MAAM,WAAW,SAAS;IACxB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB;;;OAGG;IACH,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAOhC,CAAC;AAEF,eAAO,MAAM,YAAY;;;CAA+B,CAAC;AACzD,eAAO,MAAM,kBAAkB;;;CAA8B,CAAC;AAC9D,eAAO,MAAM,aAAa;;;CAA+B,CAAC;AAO1D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CA8B5D;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAS5D;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,aAAa,CA8B/D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAc1D"}
package/dist/cardStyle.js CHANGED
@@ -12,9 +12,9 @@
12
12
  * THE DEFAULT IS "DON'T EMIT ANYTHING". `toCssVars` returns only the
13
13
  * properties that DIFFER from `DEFAULT_CARD_STYLE`, and the chrome element
14
14
  * falls back to exactly the values it used before this file existed. A page
15
- * whose operator has never opened the editor therefore renders byte-identical
16
- * CSS — this is a capability, not a restyle, and it must not show up as a
17
- * visual diff on 305 pages the day it ships.
15
+ * whose operator has never opened the editor uses the component defaults.
16
+ * The September 2026 recovery intentionally makes those defaults visibly
17
+ * elevated; appearance settings do not have to be entered to enable shadows.
18
18
  *
19
19
  * TOKENS, NOT COLOURS. `borderTone` names a theme token, never a literal.
20
20
  * The estate bans hex/rgb in D2C apps (`bsuite/no-hardcoded-colours`) and the
@@ -38,9 +38,8 @@ export const BORDER_STYLES = ['solid', 'dashed', 'dotted', 'none'];
38
38
  *
39
39
  * `radius: 24` is `1.5rem`, the existing `--radius-card` fallback.
40
40
  * `borderWidth: 1` + `borderTone: 'border'` is the existing `border
41
- * border-border`. `elevation: null` preserves `shadow-sm` and the dark-mode
42
- * `--glow-card` rule rather than replacing them with an elevation token that
43
- * is close but not equal.
41
+ * border-border`. `elevation: null` leaves the component's resting and
42
+ * interaction defaults in place; an explicit zero opts out of both.
44
43
  */
45
44
  export const DEFAULT_CARD_STYLE = {
46
45
  radius: 24,
@@ -121,7 +120,14 @@ export function toCssVars(style) {
121
120
  vars['--card-border-style'] = style.borderStyle;
122
121
  }
123
122
  if (style.elevation !== null) {
124
- vars['--card-shadow'] = `var(--shadow-elev-${style.elevation})`;
123
+ const resting = `var(--shadow-elev-${style.elevation})`;
124
+ vars['--card-shadow'] = resting;
125
+ // Preserve the selected depth while adding visible feedback, including
126
+ // at the top of the ramp. Explicit zero remains flat in every state.
127
+ vars['--card-shadow-interaction'] = style.elevation === 0
128
+ ? resting : `${resting}, var(--shadow-elev-1)`;
129
+ vars['--card-shadow-interaction-dark'] = style.elevation === 0
130
+ ? resting : `${resting}, var(--glow-card-hover)`;
125
131
  }
126
132
  if (style.padding !== null) {
127
133
  vars['--card-padding'] = `${style.padding}px`;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { PageGridLayout } from './PageGridLayout.js';
1
+ export { PageGridLayout, PAGE_GRID_SAVE_EVENT } from './PageGridLayout.js';
2
+ export type { PageGridSaveEventDetail } from './PageGridLayout.js';
2
3
  export { PageEditorLauncher } from './PageEditorLauncher.js';
3
4
  export { CanvasCard } from './CanvasCard.js';
4
5
  export type { CanvasCardProps } from './CanvasCard.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,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwB7C,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,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,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,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,IAAI,kBAAkB,EAC/B,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQpF,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,UAAU,EACV,eAAe,EACf,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,YAAY,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwB7C,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,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,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,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,IAAI,kBAAkB,EAC/B,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQpF,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,UAAU,EACV,eAAe,EACf,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { PageGridLayout } from './PageGridLayout.js';
1
+ export { PageGridLayout, PAGE_GRID_SAVE_EVENT } from './PageGridLayout.js';
2
2
  export { PageEditorLauncher } from './PageEditorLauncher.js';
3
3
  export { CanvasCard } from './CanvasCard.js';
4
4
  export { DraggableCardPage } from './DraggableCardPage.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsuite/page-builder",
3
- "version": "2.7.1-next.3",
3
+ "version": "2.7.1-next.5",
4
4
  "description": "Shared BSuite responsive page-builder grid and layout persistence primitives",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",