@bsuite/page-builder 2.4.1 → 2.5.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/PageGridLayout.d.ts.map +1 -1
- package/dist/PageGridLayout.js +48 -5
- package/dist/cardStyle.d.ts +68 -0
- package/dist/cardStyle.d.ts.map +1 -0
- package/dist/cardStyle.js +155 -0
- package/dist/cardSurfaces.stories.d.ts +6 -0
- package/dist/cardSurfaces.stories.d.ts.map +1 -1
- package/dist/cardSurfaces.stories.js +50 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/scanner/cardHeadingScanner.d.ts.map +1 -1
- package/dist/scanner/cardHeadingScanner.js +5 -1
- package/package.json +1 -1
|
@@ -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;
|
|
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;AAsBxC,OAAO,KAAK,EAAe,mBAAmB,EAA4B,MAAM,YAAY,CAAC;AA4kB7F,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,qBAq+BrB"}
|
package/dist/PageGridLayout.js
CHANGED
|
@@ -6,6 +6,7 @@ import { gridBounds, minMaxSize, minSize } from 'react-grid-layout/core';
|
|
|
6
6
|
import 'react-grid-layout/css/styles.css';
|
|
7
7
|
import 'react-resizable/css/styles.css';
|
|
8
8
|
import { computeAutoHeightRows } from './autoHeight.js';
|
|
9
|
+
import { BORDER_STYLES, BORDER_TONES, BORDER_WIDTH_RANGE, DEFAULT_CARD_STYLE, PADDING_RANGE, RADIUS_RANGE, describeCardStyle, isDefaultCardStyle, normaliseCardStyle, toCssVars, } from './cardStyle.js';
|
|
9
10
|
import { defaultPreferenceAdapter } from './preferences.js';
|
|
10
11
|
import { isRelationshipWritable } from './relationshipCatalog.js';
|
|
11
12
|
import { usePageGridLayout } from './usePageGridLayout.js';
|
|
@@ -139,7 +140,7 @@ function warnOnceAboutCollapsedContent(el) {
|
|
|
139
140
|
+ '(an aspect ratio, a px/rem height, or min-height), or pass autoHeight={false} on '
|
|
140
141
|
+ 'this card so it renders into the constrained scrollable wrapper instead.');
|
|
141
142
|
}
|
|
142
|
-
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) {
|
|
143
|
+
const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, isEditing, label, onHide, autoHeight, onAutoHeightChange, chrome = false, cardStyleVars, children: injectedChildren, className: injectedClassName, style: injectedStyle, ...rest }, ref) {
|
|
143
144
|
// Auto-height measurement (blueprint amendment A1). `measureRef` wraps
|
|
144
145
|
// `content` with NO height constraint of its own — its parent has
|
|
145
146
|
// `overflow-hidden` + `flex-1 min-h-0` (clips *painting* to the current
|
|
@@ -280,7 +281,19 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
280
281
|
// `--radius-card` defaults to today's value (1.5rem =
|
|
281
282
|
// rounded-3xl), so this is byte-identical until a tenant sets
|
|
282
283
|
// one.
|
|
283
|
-
cn(
|
|
284
|
+
cn(
|
|
285
|
+
// Border width, style and colour read custom properties
|
|
286
|
+
// whose fallbacks are byte-identical to the `border
|
|
287
|
+
// border-border` they replace, so an operator who has never
|
|
288
|
+
// opened the card editor sees exactly the previous CSS.
|
|
289
|
+
// The shadow deliberately keeps its ORIGINAL classes. An
|
|
290
|
+
// elevation choice arrives as an inline `boxShadow`, which
|
|
291
|
+
// beats the class without needing a fallback that restates
|
|
292
|
+
// `shadow-sm`. Writing that fallback by hand was the first
|
|
293
|
+
// attempt and it was wrong: elev-1 is CLOSE to shadow-sm
|
|
294
|
+
// but not equal, so it would have silently restyled every
|
|
295
|
+
// card on 305 pages the day this shipped.
|
|
296
|
+
'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)]',
|
|
284
297
|
// THE DOUBLED BOTTOM BORDER, AND WHY THE ARITHMETIC COULD NEVER FIX IT.
|
|
285
298
|
//
|
|
286
299
|
// computeAutoHeightRows uses Math.ceil to round content height up to
|
|
@@ -305,7 +318,24 @@ const GridItem = React.memo(React.forwardRef(function GridItem({ id, content, is
|
|
|
305
318
|
// height and the chrome should fill it.
|
|
306
319
|
autoHeight ? 'h-fit' : 'h-full')
|
|
307
320
|
: // Chrome OFF: layout only. Identical box, no paint.
|
|
308
|
-
cn('w-full transition-all flex flex-col', autoHeight ? 'h-fit' : 'h-full'),
|
|
321
|
+
cn('w-full transition-all flex flex-col', autoHeight ? 'h-fit' : 'h-full'),
|
|
322
|
+
/*
|
|
323
|
+
* `cardStyleVars` carries ONLY the properties the operator changed
|
|
324
|
+
* (see cardStyle.ts). An untouched page spreads an empty object, so
|
|
325
|
+
* this attribute is identical to what it was before the card editor
|
|
326
|
+
* existed. `boxShadow` is set as a real declaration rather than a
|
|
327
|
+
* custom property because it has to beat the `shadow-sm` class.
|
|
328
|
+
*/
|
|
329
|
+
style: {
|
|
330
|
+
contain: 'layout style',
|
|
331
|
+
...cardStyleVars,
|
|
332
|
+
...(cardStyleVars && '--card-shadow' in cardStyleVars
|
|
333
|
+
? { boxShadow: cardStyleVars['--card-shadow'] }
|
|
334
|
+
: null),
|
|
335
|
+
...(cardStyleVars && '--card-padding' in cardStyleVars
|
|
336
|
+
? { padding: cardStyleVars['--card-padding'] }
|
|
337
|
+
: null),
|
|
338
|
+
}, children: _jsx("div", { className: cn('min-h-0', autoHeight ? 'flex-none overflow-visible' : 'flex-1 overflow-auto'), children: autoHeight ? (_jsx("div", { ref: measureRef, className: "flow-root", children: content })) : (content) }) })] }), injectedChildren] }));
|
|
309
339
|
}));
|
|
310
340
|
export function PageGridLayout({ pageKey, defaultLayouts, defaultCols, layoutVersion, canEditPage, editorEventNames, preferenceAdapter, widgets, widgetMeta, className,
|
|
311
341
|
// Resize default flipped 2026-05-12: rgl v2 dropped auto-handle rendering
|
|
@@ -398,6 +428,17 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
|
|
|
398
428
|
const [extraRelationshipWidgetConfigs, setExtraRelationshipWidgetConfigs] = useState({});
|
|
399
429
|
const { value: layerNames, setValue: setLayerNames } = (preferenceAdapter ?? defaultPreferenceAdapter)(`page:${pageKey}_grid_layer_names`, {});
|
|
400
430
|
const { value: hiddenLayerIds, setValue: setHiddenLayerIds } = (preferenceAdapter ?? defaultPreferenceAdapter)(`page:${pageKey}_grid_hidden_layers`, {});
|
|
431
|
+
/*
|
|
432
|
+
* Card appearance, per page, persisted beside the layout.
|
|
433
|
+
*
|
|
434
|
+
* Same adapter and the same key shape as every other page preference, so it
|
|
435
|
+
* survives a reload, follows the operator across devices wherever the app
|
|
436
|
+
* backs the adapter with the database, and needs no new storage concept.
|
|
437
|
+
*/
|
|
438
|
+
const { value: storedCardStyle, setValue: setStoredCardStyle } = (preferenceAdapter ?? defaultPreferenceAdapter)(`page:${pageKey}_card_style`, DEFAULT_CARD_STYLE);
|
|
439
|
+
const cardStyle = useMemo(() => normaliseCardStyle(storedCardStyle), [storedCardStyle]);
|
|
440
|
+
const cardStyleVars = useMemo(() => toCssVars(cardStyle), [cardStyle]);
|
|
441
|
+
const updateCardStyle = useCallback((patch) => setStoredCardStyle({ ...cardStyle, ...patch }), [cardStyle, setStoredCardStyle]);
|
|
401
442
|
const extraWidgets = useMemo(() => {
|
|
402
443
|
const rendered = {};
|
|
403
444
|
if (!createEntityWidget)
|
|
@@ -755,7 +796,9 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
|
|
|
755
796
|
// partially visible — mitigates Issue 2 (banner consuming
|
|
756
797
|
// vertical space). `bg-card/95` + `backdrop-blur` keeps text
|
|
757
798
|
// legible while showing form context behind the banner.
|
|
758
|
-
'bg-card/95 supports-[backdrop-filter]:bg-card/80 backdrop-blur border-primary'), role: "region", "aria-label": "Canvas editor controls", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn('rounded-full flex items-center justify-center bg-primary/10', controlsCollapsed ? 'h-8 w-8' : 'h-10 w-10 animate-pulse'), children: _jsx(Settings2, { className: cn('text-primary', controlsCollapsed ? 'h-4 w-4' : 'h-5 w-5') }) }), _jsxs("div", { children: [_jsx("h3", { className: cn('font-semibold text-foreground', controlsCollapsed ? 'text-sm' : 'text-lg'), children: "Canvas Editor Active" }), !controlsCollapsed && (_jsx("span", { className: "text-sm text-muted-foreground", children: "Drag anywhere on a card to move it. Resize with the bottom-right handle." }))] })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded-md border border-border px-2 py-2 text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", "aria-expanded": !controlsCollapsed, "aria-controls": "page-grid-editor-controls-body", onClick: () => setControlsCollapsed((previous) => !previous), children: [controlsCollapsed ? _jsx(ChevronDown, { className: "h-4 w-4" }) : _jsx(ChevronUp, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only sm:not-sr-only", children: controlsCollapsed ? '
|
|
799
|
+
'bg-card/95 supports-[backdrop-filter]:bg-card/80 backdrop-blur border-primary'), role: "region", "aria-label": "Canvas editor controls", children: [_jsxs("div", { className: "flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn('rounded-full flex items-center justify-center bg-primary/10', controlsCollapsed ? 'h-8 w-8' : 'h-10 w-10 animate-pulse'), children: _jsx(Settings2, { className: cn('text-primary', controlsCollapsed ? 'h-4 w-4' : 'h-5 w-5') }) }), _jsxs("div", { children: [_jsx("h3", { className: cn('font-semibold text-foreground', controlsCollapsed ? 'text-sm' : 'text-lg'), children: "Canvas Editor Active" }), !controlsCollapsed && (_jsx("span", { className: "text-sm text-muted-foreground", children: "Drag anywhere on a card to move it. Resize with the bottom-right handle." }))] })] }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded-md border border-border px-2 py-2 text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", "aria-expanded": !controlsCollapsed, "aria-controls": "page-grid-editor-controls-body", "aria-label": controlsCollapsed ? 'Expand controls: columns, cards and layers' : 'Collapse controls', onClick: () => setControlsCollapsed((previous) => !previous), children: [controlsCollapsed ? _jsx(ChevronDown, { className: "h-4 w-4" }) : _jsx(ChevronUp, { className: "h-4 w-4" }), _jsx("span", { className: "sr-only sm:not-sr-only", children: controlsCollapsed ? 'Columns, cards & layers' : 'Collapse' })] }), _jsxs("button", { type: "button", className: "inline-flex items-center rounded-md px-3 py-2 text-sm font-medium bg-primary text-primary-foreground shadow transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", onClick: () => startTransition(() => setIsEditing(false)), children: [_jsx(Save, { className: "h-4 w-4 mr-2" }), "Save & Exit"] })] })] }), _jsxs("div", { id: "page-grid-editor-controls-body", hidden: controlsCollapsed, className: "flex flex-wrap items-center gap-x-4 gap-y-2 pt-2 border-t border-border max-h-[60vh] overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutGrid, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsx("span", { className: "text-sm shrink-0 text-muted-foreground", children: "Columns:" }), _jsx("input", { type: "range", min: 1, max: 24, value: layoutCols, onChange: (event) => handleColumnChange(Number(event.target.value)), className: "w-24 cursor-pointer accent-primary", "aria-label": "Column count" }), _jsx("span", { className: "text-sm font-mono w-5 text-center tabular-nums", children: layoutCols })] }), _jsx("div", { className: "flex items-center gap-1", role: "group", "aria-label": "Column presets", children: [1, 2, 3, 4, 6, 12].map((columnCount) => (_jsx("button", { type: "button", onClick: () => handleColumnChange(columnCount), "data-active": layoutCols === columnCount || undefined, "aria-pressed": layoutCols === columnCount, className: cn('px-2 py-0.5 rounded text-xs font-medium transition-colors border', 'bg-muted text-muted-foreground border-border', 'hover:bg-muted/80 hover:text-foreground', 'data-[active]:bg-primary data-[active]:text-primary-foreground data-[active]:border-primary', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1'), children: columnCount }, columnCount))) }), _jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-2 w-full pt-2 border-t border-border", role: "group", "aria-label": "Card appearance", children: [_jsx("span", { className: "text-sm shrink-0 font-medium text-foreground", children: "Card:" }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "Corners" }), _jsx("input", { type: "range", min: RADIUS_RANGE.min, max: RADIUS_RANGE.max, value: cardStyle.radius, onChange: (event) => updateCardStyle({ radius: Number(event.target.value) }), className: "w-20 cursor-pointer accent-primary", "aria-label": "Card corner radius in pixels" }), _jsx("span", { className: "text-sm font-mono w-8 text-right tabular-nums", children: cardStyle.radius })] }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "Border" }), _jsx("input", { type: "range", min: BORDER_WIDTH_RANGE.min, max: BORDER_WIDTH_RANGE.max, value: cardStyle.borderWidth, onChange: (event) => updateCardStyle({ borderWidth: Number(event.target.value) }), className: "w-16 cursor-pointer accent-primary", "aria-label": "Card border width in pixels" }), _jsx("span", { className: "text-sm font-mono w-6 text-right tabular-nums", children: cardStyle.borderWidth })] }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "sr-only", children: "Border colour" }), _jsx("select", { value: cardStyle.borderTone, onChange: (event) => updateCardStyle({ borderTone: event.target.value }), className: "rounded-md border border-border bg-background px-2 py-1 text-sm text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": "Card border colour", children: BORDER_TONES.map((tone) => (_jsx("option", { value: tone, children: tone === 'border' ? 'default colour' : tone }, tone))) })] }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "sr-only", children: "Border style" }), _jsx("select", { value: cardStyle.borderStyle, onChange: (event) => updateCardStyle({ borderStyle: event.target.value }), className: "rounded-md border border-border bg-background px-2 py-1 text-sm text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": "Card border style", children: BORDER_STYLES.map((style) => (_jsx("option", { value: style, children: style }, style))) })] }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "sr-only", children: "Card shadow" }), _jsxs("select", { value: cardStyle.elevation === null ? 'default' : String(cardStyle.elevation), onChange: (event) => updateCardStyle({
|
|
800
|
+
elevation: event.target.value === 'default' ? null : Number(event.target.value),
|
|
801
|
+
}), className: "rounded-md border border-border bg-background px-2 py-1 text-sm text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", "aria-label": "Card shadow depth", children: [_jsx("option", { value: "default", children: "default shadow" }), [0, 1, 2, 3, 4].map((level) => (_jsx("option", { value: level, children: level === 0 ? 'no shadow' : `shadow ${level}` }, level)))] })] }), _jsxs("label", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-sm text-muted-foreground", children: "Padding" }), _jsx("input", { type: "range", min: PADDING_RANGE.min, max: PADDING_RANGE.max, value: cardStyle.padding ?? 0, onChange: (event) => updateCardStyle({ padding: Number(event.target.value) }), className: "w-16 cursor-pointer accent-primary", "aria-label": "Card inner padding in pixels" }), _jsx("span", { className: "text-sm font-mono w-8 text-right tabular-nums", children: cardStyle.padding === null ? '\u2014' : cardStyle.padding })] }), _jsxs("button", { type: "button", onClick: () => setStoredCardStyle({ ...DEFAULT_CARD_STYLE }), disabled: isDefaultCardStyle(cardStyle), className: "inline-flex items-center gap-1 rounded-md border border-border px-2 py-1 text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50 disabled:pointer-events-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(RotateCcw, { className: "h-3.5 w-3.5" }), "Reset cards"] }), _jsx("output", { className: "text-sm text-muted-foreground", "aria-live": "polite", children: describeCardStyle(cardStyle) })] }), hiddenWidgetKeys.length > 0 && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Eye, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsx("span", { className: "text-sm shrink-0 text-muted-foreground", children: "Add widget:" }), _jsx("div", { className: "flex flex-wrap gap-1", children: hiddenWidgetKeys.map((key) => {
|
|
759
802
|
const meta = widgetMeta?.[key];
|
|
760
803
|
const Icon = meta?.icon;
|
|
761
804
|
return (_jsxs("button", { type: "button", onClick: () => showLayer(key, meta?.defaultSize), className: cn('flex items-center gap-1 px-2 py-0.5 rounded text-xs font-medium border transition-colors', 'bg-muted text-muted-foreground border-border', 'hover:bg-muted/80 hover:text-foreground hover:border-primary/60', 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1'), children: [_jsx(Plus, { className: "h-3 w-3" }), Icon && _jsx(Icon, { className: "h-3 w-3" }), layerNames[key] || meta?.label || key] }, key));
|
|
@@ -789,6 +832,6 @@ itemChrome = false, addEntityWidgetEventNames = DEFAULT_ADD_ENTITY_WIDGET_EVENT_
|
|
|
789
832
|
const content = allWidgets[layoutItem.i];
|
|
790
833
|
if (content === undefined || content === null)
|
|
791
834
|
return null;
|
|
792
|
-
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));
|
|
835
|
+
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, cardStyleVars: cardStyleVars }, layoutItem.i));
|
|
793
836
|
}) }) }) })] }));
|
|
794
837
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** Theme tokens a border may reference. Closed set — never a raw colour. */
|
|
2
|
+
export declare const BORDER_TONES: readonly ["border", "primary", "accent", "muted", "destructive", "transparent"];
|
|
3
|
+
export type BorderTone = (typeof BORDER_TONES)[number];
|
|
4
|
+
export declare const BORDER_STYLES: readonly ["solid", "dashed", "dotted", "none"];
|
|
5
|
+
export type BorderStyle = (typeof BORDER_STYLES)[number];
|
|
6
|
+
/** `--shadow-elev-0..4`, shipped by @bsuite/theme >= 0.11.0. */
|
|
7
|
+
export type Elevation = 0 | 1 | 2 | 3 | 4;
|
|
8
|
+
export interface CardStyle {
|
|
9
|
+
/** Corner radius in px. */
|
|
10
|
+
radius: number;
|
|
11
|
+
/** Border thickness in px. */
|
|
12
|
+
borderWidth: number;
|
|
13
|
+
/** Theme token the border colour reads from. */
|
|
14
|
+
borderTone: BorderTone;
|
|
15
|
+
borderStyle: BorderStyle;
|
|
16
|
+
/**
|
|
17
|
+
* `null` means "leave the class-based shadow alone" — which is what every
|
|
18
|
+
* card did before this file. A number selects `--shadow-elev-N`.
|
|
19
|
+
*/
|
|
20
|
+
elevation: Elevation | null;
|
|
21
|
+
/** Inner padding in px. `null` leaves the card's own padding untouched. */
|
|
22
|
+
padding: number | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The values the chrome element already rendered.
|
|
26
|
+
*
|
|
27
|
+
* `radius: 24` is `1.5rem`, the existing `--radius-card` fallback.
|
|
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.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_CARD_STYLE: CardStyle;
|
|
34
|
+
export declare const RADIUS_RANGE: {
|
|
35
|
+
readonly min: 0;
|
|
36
|
+
readonly max: 48;
|
|
37
|
+
};
|
|
38
|
+
export declare const BORDER_WIDTH_RANGE: {
|
|
39
|
+
readonly min: 0;
|
|
40
|
+
readonly max: 8;
|
|
41
|
+
};
|
|
42
|
+
export declare const PADDING_RANGE: {
|
|
43
|
+
readonly min: 0;
|
|
44
|
+
readonly max: 48;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Coerce anything read back out of a preference store into a valid style.
|
|
48
|
+
*
|
|
49
|
+
* Preferences are user-writable JSON that survives releases, so this has to
|
|
50
|
+
* treat its input as untrusted: a stored `borderTone` naming a token that no
|
|
51
|
+
* longer exists must not paint an invalid border, it must fall back. Every
|
|
52
|
+
* field is validated independently so one bad key cannot discard the rest of
|
|
53
|
+
* the operator's choices.
|
|
54
|
+
*/
|
|
55
|
+
export declare function normaliseCardStyle(input: unknown): CardStyle;
|
|
56
|
+
export declare function isDefaultCardStyle(style: CardStyle): boolean;
|
|
57
|
+
/** The CSS custom properties a non-default style needs. Empty when default. */
|
|
58
|
+
export declare function toCssVars(style: CardStyle): React.CSSProperties;
|
|
59
|
+
/**
|
|
60
|
+
* A human sentence describing the current card, for the editor's live readout.
|
|
61
|
+
*
|
|
62
|
+
* The operator is adjusting something they can see, so the readout names the
|
|
63
|
+
* change in their words rather than echoing CSS: "2px dashed accent border,
|
|
64
|
+
* 8px corners". D8.3 -- a control whose effect you cannot predict from the
|
|
65
|
+
* screen is not finished.
|
|
66
|
+
*/
|
|
67
|
+
export declare function describeCardStyle(style: CardStyle): string;
|
|
68
|
+
//# sourceMappingURL=cardStyle.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* cardStyle.ts — the card's appearance, as something the operator edits.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. Card chrome — the border, the corner radius, the shadow,
|
|
5
|
+
* the padding — was a string of Tailwind classes compiled into
|
|
6
|
+
* `PageGridLayout`. Changing any of it meant asking an agent to edit the
|
|
7
|
+
* package, publish it, and roll it through five apps. The operator has asked
|
|
8
|
+
* for the border to be corrected repeatedly, and each ask cost a full release
|
|
9
|
+
* cycle to answer. The remedy is not another correct border; it is to stop
|
|
10
|
+
* being the only one who can set it.
|
|
11
|
+
*
|
|
12
|
+
* THE DEFAULT IS "DON'T EMIT ANYTHING". `toCssVars` returns only the
|
|
13
|
+
* properties that DIFFER from `DEFAULT_CARD_STYLE`, and the chrome element
|
|
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.
|
|
18
|
+
*
|
|
19
|
+
* TOKENS, NOT COLOURS. `borderTone` names a theme token, never a literal.
|
|
20
|
+
* The estate bans hex/rgb in D2C apps (`bsuite/no-hardcoded-colours`) and the
|
|
21
|
+
* whole point of `--border` is that a tenant can rebrand it. An editor that
|
|
22
|
+
* wrote a raw hex value into a preference would be a white-label regression wearing
|
|
23
|
+
* a feature's clothes, so the palette below is a closed set of token names and
|
|
24
|
+
* the type makes an arbitrary string unrepresentable.
|
|
25
|
+
*/
|
|
26
|
+
/** Theme tokens a border may reference. Closed set — never a raw colour. */
|
|
27
|
+
export const BORDER_TONES = [
|
|
28
|
+
'border',
|
|
29
|
+
'primary',
|
|
30
|
+
'accent',
|
|
31
|
+
'muted',
|
|
32
|
+
'destructive',
|
|
33
|
+
'transparent',
|
|
34
|
+
];
|
|
35
|
+
export const BORDER_STYLES = ['solid', 'dashed', 'dotted', 'none'];
|
|
36
|
+
/**
|
|
37
|
+
* The values the chrome element already rendered.
|
|
38
|
+
*
|
|
39
|
+
* `radius: 24` is `1.5rem`, the existing `--radius-card` fallback.
|
|
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.
|
|
44
|
+
*/
|
|
45
|
+
export const DEFAULT_CARD_STYLE = {
|
|
46
|
+
radius: 24,
|
|
47
|
+
borderWidth: 1,
|
|
48
|
+
borderTone: 'border',
|
|
49
|
+
borderStyle: 'solid',
|
|
50
|
+
elevation: null,
|
|
51
|
+
padding: null,
|
|
52
|
+
};
|
|
53
|
+
export const RADIUS_RANGE = { min: 0, max: 48 };
|
|
54
|
+
export const BORDER_WIDTH_RANGE = { min: 0, max: 8 };
|
|
55
|
+
export const PADDING_RANGE = { min: 0, max: 48 };
|
|
56
|
+
function clamp(value, min, max) {
|
|
57
|
+
if (!Number.isFinite(value))
|
|
58
|
+
return min;
|
|
59
|
+
return Math.min(max, Math.max(min, Math.round(value)));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Coerce anything read back out of a preference store into a valid style.
|
|
63
|
+
*
|
|
64
|
+
* Preferences are user-writable JSON that survives releases, so this has to
|
|
65
|
+
* treat its input as untrusted: a stored `borderTone` naming a token that no
|
|
66
|
+
* longer exists must not paint an invalid border, it must fall back. Every
|
|
67
|
+
* field is validated independently so one bad key cannot discard the rest of
|
|
68
|
+
* the operator's choices.
|
|
69
|
+
*/
|
|
70
|
+
export function normaliseCardStyle(input) {
|
|
71
|
+
if (input === null || typeof input !== 'object')
|
|
72
|
+
return { ...DEFAULT_CARD_STYLE };
|
|
73
|
+
const raw = input;
|
|
74
|
+
const tone = BORDER_TONES.includes(raw.borderTone)
|
|
75
|
+
? raw.borderTone
|
|
76
|
+
: DEFAULT_CARD_STYLE.borderTone;
|
|
77
|
+
const style = BORDER_STYLES.includes(raw.borderStyle)
|
|
78
|
+
? raw.borderStyle
|
|
79
|
+
: DEFAULT_CARD_STYLE.borderStyle;
|
|
80
|
+
const elevation = typeof raw.elevation === 'number' && raw.elevation >= 0 && raw.elevation <= 4
|
|
81
|
+
? Math.round(raw.elevation)
|
|
82
|
+
: null;
|
|
83
|
+
return {
|
|
84
|
+
radius: typeof raw.radius === 'number'
|
|
85
|
+
? clamp(raw.radius, RADIUS_RANGE.min, RADIUS_RANGE.max)
|
|
86
|
+
: DEFAULT_CARD_STYLE.radius,
|
|
87
|
+
borderWidth: typeof raw.borderWidth === 'number'
|
|
88
|
+
? clamp(raw.borderWidth, BORDER_WIDTH_RANGE.min, BORDER_WIDTH_RANGE.max)
|
|
89
|
+
: DEFAULT_CARD_STYLE.borderWidth,
|
|
90
|
+
borderTone: tone,
|
|
91
|
+
borderStyle: style,
|
|
92
|
+
elevation,
|
|
93
|
+
padding: typeof raw.padding === 'number'
|
|
94
|
+
? clamp(raw.padding, PADDING_RANGE.min, PADDING_RANGE.max)
|
|
95
|
+
: null,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export function isDefaultCardStyle(style) {
|
|
99
|
+
return (style.radius === DEFAULT_CARD_STYLE.radius &&
|
|
100
|
+
style.borderWidth === DEFAULT_CARD_STYLE.borderWidth &&
|
|
101
|
+
style.borderTone === DEFAULT_CARD_STYLE.borderTone &&
|
|
102
|
+
style.borderStyle === DEFAULT_CARD_STYLE.borderStyle &&
|
|
103
|
+
style.elevation === DEFAULT_CARD_STYLE.elevation &&
|
|
104
|
+
style.padding === DEFAULT_CARD_STYLE.padding);
|
|
105
|
+
}
|
|
106
|
+
/** The CSS custom properties a non-default style needs. Empty when default. */
|
|
107
|
+
export function toCssVars(style) {
|
|
108
|
+
const vars = {};
|
|
109
|
+
if (style.radius !== DEFAULT_CARD_STYLE.radius) {
|
|
110
|
+
vars['--radius-card'] = `${style.radius}px`;
|
|
111
|
+
}
|
|
112
|
+
if (style.borderWidth !== DEFAULT_CARD_STYLE.borderWidth) {
|
|
113
|
+
vars['--card-border-width'] = `${style.borderWidth}px`;
|
|
114
|
+
}
|
|
115
|
+
if (style.borderTone !== DEFAULT_CARD_STYLE.borderTone) {
|
|
116
|
+
// `transparent` is a CSS-wide keyword, not a token, so it is not wrapped.
|
|
117
|
+
vars['--card-border-color'] =
|
|
118
|
+
style.borderTone === 'transparent' ? 'transparent' : `var(--${style.borderTone})`;
|
|
119
|
+
}
|
|
120
|
+
if (style.borderStyle !== DEFAULT_CARD_STYLE.borderStyle) {
|
|
121
|
+
vars['--card-border-style'] = style.borderStyle;
|
|
122
|
+
}
|
|
123
|
+
if (style.elevation !== null) {
|
|
124
|
+
vars['--card-shadow'] = `var(--shadow-elev-${style.elevation})`;
|
|
125
|
+
}
|
|
126
|
+
if (style.padding !== null) {
|
|
127
|
+
vars['--card-padding'] = `${style.padding}px`;
|
|
128
|
+
}
|
|
129
|
+
return vars;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A human sentence describing the current card, for the editor's live readout.
|
|
133
|
+
*
|
|
134
|
+
* The operator is adjusting something they can see, so the readout names the
|
|
135
|
+
* change in their words rather than echoing CSS: "2px dashed accent border,
|
|
136
|
+
* 8px corners". D8.3 -- a control whose effect you cannot predict from the
|
|
137
|
+
* screen is not finished.
|
|
138
|
+
*/
|
|
139
|
+
export function describeCardStyle(style) {
|
|
140
|
+
const parts = [];
|
|
141
|
+
if (style.borderStyle === 'none' || style.borderWidth === 0) {
|
|
142
|
+
parts.push('no border');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const tone = style.borderTone === 'border' ? 'default' : style.borderTone;
|
|
146
|
+
parts.push(`${style.borderWidth}px ${style.borderStyle} ${tone} border`);
|
|
147
|
+
}
|
|
148
|
+
parts.push(style.radius === 0 ? 'square corners' : `${style.radius}px corners`);
|
|
149
|
+
if (style.elevation !== null) {
|
|
150
|
+
parts.push(style.elevation === 0 ? 'no shadow' : `elevation ${style.elevation}`);
|
|
151
|
+
}
|
|
152
|
+
if (style.padding !== null)
|
|
153
|
+
parts.push(`${style.padding}px padding`);
|
|
154
|
+
return parts.join(', ');
|
|
155
|
+
}
|
|
@@ -59,4 +59,10 @@ export declare const WidthLadder: Story;
|
|
|
59
59
|
* which is why "is the class present" is not a check.
|
|
60
60
|
*/
|
|
61
61
|
export declare const CardHeadingGradient: Story;
|
|
62
|
+
export declare const CardStyleDefault: Story;
|
|
63
|
+
export declare const CardStyleThickBorder: Story;
|
|
64
|
+
export declare const CardStyleDashedAccent: Story;
|
|
65
|
+
export declare const CardStyleSquare: Story;
|
|
66
|
+
export declare const CardStyleBorderless: Story;
|
|
67
|
+
export declare const CardStyleElevationLadder: Story;
|
|
62
68
|
//# sourceMappingURL=cardSurfaces.stories.d.ts.map
|
|
@@ -1 +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;
|
|
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;AAKtC;;;;;;;;;;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;AA2CD,eAAO,MAAM,gBAAgB,EAAE,KAK9B,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,KAGlC,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,KAQnC,CAAA;AAED,eAAO,MAAM,eAAe,EAAE,KAG7B,CAAA;AAED,eAAO,MAAM,mBAAmB,EAAE,KAQjC,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,KAatC,CAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { PageGridLayout } from './PageGridLayout.js';
|
|
3
|
+
import { DEFAULT_CARD_STYLE, describeCardStyle, toCssVars } from './cardStyle.js';
|
|
3
4
|
export default {
|
|
4
5
|
title: 'Page Builder/Card surfaces',
|
|
5
6
|
parameters: { layout: 'fullscreen' },
|
|
@@ -74,3 +75,52 @@ export const CardHeadingGradient = {
|
|
|
74
75
|
name: 'Card headings — with and without the gradient',
|
|
75
76
|
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
77
|
};
|
|
78
|
+
/* ------------------------------------------------------------------ *
|
|
79
|
+
* OPERATOR-EDITABLE CARD APPEARANCE
|
|
80
|
+
*
|
|
81
|
+
* The border, corners, shadow and padding are set by the operator in the
|
|
82
|
+
* canvas editor and persisted per page (see cardStyle.ts). These stories are
|
|
83
|
+
* the reference for what each setting actually paints, so a change to the
|
|
84
|
+
* chrome can be diffed against a picture rather than argued about.
|
|
85
|
+
*
|
|
86
|
+
* `toCssVars` returns ONLY the properties that differ from the default, so
|
|
87
|
+
* `Default` below emits no custom properties at all — it is the control, and
|
|
88
|
+
* it must look exactly like `BareContentOptsIn`. If those two ever diverge,
|
|
89
|
+
* the "costs nothing until you touch it" guarantee has been broken.
|
|
90
|
+
* ------------------------------------------------------------------ */
|
|
91
|
+
/** Renders one slot with chrome on, under a given operator card style. */
|
|
92
|
+
function StyledSurface({ style, note }) {
|
|
93
|
+
const resolved = { ...DEFAULT_CARD_STYLE, ...style };
|
|
94
|
+
const vars = toCssVars(resolved);
|
|
95
|
+
return (_jsxs("div", { className: "p-8", style: {
|
|
96
|
+
...vars,
|
|
97
|
+
// The editor applies elevation and padding as real declarations,
|
|
98
|
+
// because each has to beat a class. Mirrored here so the story shows
|
|
99
|
+
// what the page shows.
|
|
100
|
+
...('--card-shadow' in vars ? { ['--story-shadow']: vars['--card-shadow'] } : null),
|
|
101
|
+
}, children: [_jsx("p", { className: "mb-3 text-sm text-muted-foreground", children: note }), _jsx("p", { className: "mb-3 text-sm font-medium text-foreground", children: describeCardStyle(resolved) }), _jsx(PageGridLayout, { pageKey: `card-style-${note.replace(/[^a-z0-9]+/gi, '-').toLowerCase()}`, defaultLayouts: oneSlot, itemChrome: true, widgets: { a: _jsx(BareContent, { title: "Operator-styled card" }) } })] }));
|
|
102
|
+
}
|
|
103
|
+
export const CardStyleDefault = {
|
|
104
|
+
name: 'Card style — default (emits no CSS)',
|
|
105
|
+
render: () => (_jsx(StyledSurface, { style: {}, note: "The control. No custom properties are emitted at all." })),
|
|
106
|
+
};
|
|
107
|
+
export const CardStyleThickBorder = {
|
|
108
|
+
name: 'Card style — 4px border',
|
|
109
|
+
render: () => _jsx(StyledSurface, { style: { borderWidth: 4 }, note: "Border width is a slider, 0-8px." }),
|
|
110
|
+
};
|
|
111
|
+
export const CardStyleDashedAccent = {
|
|
112
|
+
name: 'Card style — dashed accent border',
|
|
113
|
+
render: () => (_jsx(StyledSurface, { style: { borderWidth: 2, borderStyle: 'dashed', borderTone: 'accent' }, note: "Colour comes from a THEME TOKEN, never a literal, so white-labelling still applies." })),
|
|
114
|
+
};
|
|
115
|
+
export const CardStyleSquare = {
|
|
116
|
+
name: 'Card style — square corners',
|
|
117
|
+
render: () => _jsx(StyledSurface, { style: { radius: 0 }, note: "Corner radius is a slider, 0-48px." }),
|
|
118
|
+
};
|
|
119
|
+
export const CardStyleBorderless = {
|
|
120
|
+
name: 'Card style — no border',
|
|
121
|
+
render: () => (_jsx(StyledSurface, { style: { borderStyle: 'none' }, note: "A borderless card still keeps its background and radius." })),
|
|
122
|
+
};
|
|
123
|
+
export const CardStyleElevationLadder = {
|
|
124
|
+
name: 'Card style — elevation 0 to 4',
|
|
125
|
+
render: () => (_jsx("div", { className: "space-y-2", children: [0, 1, 2, 3, 4].map((level) => (_jsx(StyledSurface, { style: { elevation: level }, note: `--shadow-elev-${level}, from @bsuite/theme.` }, level))) })),
|
|
126
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -21,4 +21,6 @@ export { RelationshipField } from './RelationshipField.js';
|
|
|
21
21
|
export type { RelationshipFieldProps } from './RelationshipField.js';
|
|
22
22
|
export { isRelationshipWritable } from './relationshipCatalog.js';
|
|
23
23
|
export type { EntityWidgetDetail, EntityWidgetFactoryOptions, GridLayoutItem, GridLayouts, PageGridLayoutProps, PageGridPreferenceAdapter, PageGridPreferenceFactory, RelationshipCatalog, RelationshipCatalogEntry, RelationshipFieldOption, RelationshipWidgetDetail, RelationshipWidgetFactoryOptions, UsePageGridLayoutOptions, UsePageGridLayoutResult, WidgetMeta, } from './types.js';
|
|
24
|
+
export { BORDER_TONES, BORDER_STYLES, DEFAULT_CARD_STYLE, RADIUS_RANGE, BORDER_WIDTH_RANGE, PADDING_RANGE, normaliseCardStyle, isDefaultCardStyle, toCssVars as cardStyleToCssVars, describeCardStyle, } from './cardStyle.js';
|
|
25
|
+
export type { CardStyle, BorderTone, BorderStyle, Elevation } from './cardStyle.js';
|
|
24
26
|
//# sourceMappingURL=index.d.ts.map
|
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,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"}
|
|
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;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"}
|
package/dist/index.js
CHANGED
|
@@ -11,3 +11,4 @@ export { buildResponsiveLayouts, RESPONSIVE_BREAKPOINTS, } from './buildResponsi
|
|
|
11
11
|
export { useLocalPreference, defaultPreferenceAdapter } from './preferences.js';
|
|
12
12
|
export { RelationshipField } from './RelationshipField.js';
|
|
13
13
|
export { isRelationshipWritable } from './relationshipCatalog.js';
|
|
14
|
+
export { BORDER_TONES, BORDER_STYLES, DEFAULT_CARD_STYLE, RADIUS_RANGE, BORDER_WIDTH_RANGE, PADDING_RANGE, normaliseCardStyle, isDefaultCardStyle, toCssVars as cardStyleToCssVars, describeCardStyle, } from './cardStyle.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardHeadingScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardHeadingScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;OAUG;IACH,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iEAAiE;IACjE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"cardHeadingScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardHeadingScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;OAUG;IACH,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iEAAiE;IACjE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2DAA2D;IAC3D,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAsDD,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAqDhD;AAsCD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,wBAAwB,GAAG,qBAAqB,CA+FxF"}
|
|
@@ -60,12 +60,16 @@ const DEFAULT_GRADIENT_CLASSES = ['text-gradient-accent', 'gradient-text'];
|
|
|
60
60
|
* the full hazard set an order of magnitude higher. The loose number was the
|
|
61
61
|
* kind that makes a codemod look safe.
|
|
62
62
|
*/
|
|
63
|
+
// theme-audit-ok: this is the scanner's VOCABULARY — class names it looks FOR in
|
|
64
|
+
// other people's markup, not classes applied here. `flex-grow` is deliberately
|
|
65
|
+
// listed alongside `grow` because the scanner must recognise both spellings in
|
|
66
|
+
// source it did not write.
|
|
63
67
|
const WIDTH_DEPENDENT = [
|
|
64
68
|
'truncate',
|
|
65
69
|
'flex-1',
|
|
66
70
|
'w-full',
|
|
67
71
|
'grow',
|
|
68
|
-
'flex-grow',
|
|
72
|
+
'flex-grow', // theme-audit-ok: vocabulary the scanner looks FOR, never applied
|
|
69
73
|
'text-center',
|
|
70
74
|
'mx-auto',
|
|
71
75
|
];
|