@bettercms-ai/types 1.26.0 → 1.27.1

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/index.d.ts CHANGED
@@ -48,7 +48,7 @@ interface ContentModel {
48
48
  * by the API but normalized to `array` + zones on write, so stored/delivered
49
49
  * content never contains them.
50
50
  */
51
- type ContentModelFieldType = "text" | "richtext" | "document" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref" | "modular" | "sections" | "location";
51
+ type ContentModelFieldType = "text" | "richtext" | "document" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref" | "modular" | "sections" | "location" | "button";
52
52
  type ContentModelKind = "model" | "block";
53
53
  /**
54
54
  * How a fieldset renders in the dock. ABSENT ≡ today's flat list (V2): a legacy `{id, name}`
@@ -83,6 +83,8 @@ interface FieldsetUiBefore {
83
83
  icon?: DockIconName;
84
84
  collapsed?: boolean;
85
85
  };
86
+ /** Its index among the model's fieldsets before the agent's change; absent on older snapshots. */
87
+ position?: number;
86
88
  }
87
89
  /** A named, UI-only grouping of a model's fields. Order is the array index. */
88
90
  interface Fieldset {
@@ -326,43 +328,70 @@ declare const SPACE_BOTTOM_TOKENS: ("section-space-none" | "section-space-small"
326
328
  /** `var(--bcms-<token>,<px>)`, or "" for anything that is not a known token (closed set). */
327
329
  declare function spaceTokenCss(token: unknown): string;
328
330
 
329
- /**
330
- * A button block's LOOK beyond size: its variant, an optional leading icon and an optional
331
- * trailing arrow. The ONE source of the names and the icon markup: the renderer draws from it,
332
- * the validation schema allow-lists from it, and the dashboard's copy is pinned to it by a
333
- * parity test.
334
- *
335
- * <a class="bcms-btn bcms-btn-{variant}">[<svg class="bcms-btn-icon">]Text[<svg class="bcms-btn-arrow">]</a>
336
- */
337
331
  declare const BUTTON_VARIANTS: readonly ["primary", "secondary", "tertiary", "brand", "dark", "light", "outline", "link"];
338
332
  type ButtonVariant = (typeof BUTTON_VARIANTS)[number];
339
- /** Inner markup of each icon: lucide-react 1.8.0 paths (ISC), 24×24, stroke-drawn. */
340
- declare const BUTTON_ICONS: {
341
- readonly "arrow-right": "<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>";
342
- readonly "arrow-up-right": "<path d=\"M7 7h10v10\"/><path d=\"M7 17 17 7\"/>";
343
- readonly "chevron-right": "<path d=\"m9 18 6-6-6-6\"/>";
344
- readonly plus: "<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>";
345
- readonly check: "<path d=\"M20 6 9 17l-5-5\"/>";
346
- readonly download: "<path d=\"M12 15V3\"/><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"/><path d=\"m7 10 5 5 5-5\"/>";
347
- readonly "external-link": "<path d=\"M15 3h6v6\"/><path d=\"M10 14 21 3\"/><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/>";
348
- readonly mail: "<path d=\"m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"/><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"/>";
349
- readonly phone: "<path d=\"M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384\"/>";
350
- readonly calendar: "<path d=\"M8 2v4\"/><path d=\"M16 2v4\"/><rect width=\"18\" height=\"18\" x=\"3\" y=\"4\" rx=\"2\"/><path d=\"M3 10h18\"/>";
351
- readonly play: "<path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/>";
352
- readonly search: "<path d=\"m21 21-4.34-4.34\"/><circle cx=\"11\" cy=\"11\" r=\"8\"/>";
353
- readonly "shopping-cart": "<circle cx=\"8\" cy=\"21\" r=\"1\"/><circle cx=\"19\" cy=\"21\" r=\"1\"/><path d=\"M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12\"/>";
354
- readonly star: "<path d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z\"/>";
355
- readonly sparkles: "<path d=\"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z\"/><path d=\"M20 2v4\"/><path d=\"M22 4h-4\"/><circle cx=\"4\" cy=\"20\" r=\"2\"/>";
356
- readonly zap: "<path d=\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\"/>";
357
- };
358
- type ButtonIcon = keyof typeof BUTTON_ICONS;
359
- declare const BUTTON_ICON_NAMES: [ButtonIcon, ...ButtonIcon[]];
333
+ /** Each icon's inner SVG markup (viewBox `0 0 25 25`), by name. */
334
+ declare const BUTTON_ICONS: Readonly<Record<DockIconName, string>>;
335
+ type ButtonIcon = DockIconName;
336
+ declare const BUTTON_ICON_NAMES: readonly ["access-denied", "activity", "add", "add-circle", "add-comment", "add-document", "add-user", "api", "archive", "arrow-down", "arrow-left", "arrow-right", "arrow-top-right", "arrow-up", "asterisk", "bar-chart", "basket", "bell", "bill", "binary-document", "block-content", "block-element", "blockquote", "bold", "bolt", "book", "bookmark", "bookmark-filled", "bottle", "bug", "bulb-filled", "bulb-outline", "calendar", "case", "chart-upward", "checkmark", "checkmark-circle", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "circle", "clipboard", "clipboard-image", "clock", "close", "close-circle", "code", "code-block", "cog", "collapse", "color-wheel", "comment", "component", "compose", "compose-sparkles", "confetti", "controls", "copy", "credit-card", "crop", "cube", "dashboard", "database", "desktop", "diamond", "document", "document-pdf", "document-remove", "document-sheet", "document-text", "document-video", "document-word", "document-zip", "documents", "dot", "double-chevron-down", "double-chevron-left", "double-chevron-right", "double-chevron-up", "double-quote", "download", "drag-handle", "drop", "earth-americas", "earth-globe", "edit", "ellipsis-horizontal", "ellipsis-vertical", "empty", "enter", "enter-right", "envelope", "equal", "error-filled", "error-outline", "error-screen", "expand", "eye-closed", "eye-open", "face-happy", "face-indifferent", "face-sad", "feedback", "filter", "folder", "generate", "github", "groq", "hash", "heart", "heart-filled", "help-circle", "highlight", "home", "ice-cream", "image", "image-remove", "images", "inbox", "info-filled", "info-outline", "inline", "inline-element", "insert-above", "insert-below", "italic", "joystick", "json", "launch", "leave", "lemon", "link", "link-removed", "linkedin", "list", "lock", "logo-js", "logo-ts", "marker", "marker-removed", "master-detail", "menu", "microphone", "microphone-slash", "mobile-device", "moon", "number", "ok-hand", "olist", "overage", "package", "panel-left", "panel-right", "pause", "pin", "pin-filled", "pin-removed", "play", "plug", "presentation", "progress-50", "progress-75", "projects", "publish", "read-only", "redo", "refresh", "remove", "remove-circle", "reset", "restore", "retrieve", "retry", "revert", "robot", "rocket", "schema", "search", "select", "share", "sort", "sparkle", "sparkles", "spinner", "split-horizontal", "split-vertical", "square", "stack", "stack-compact", "star", "star-filled", "stop", "strikethrough", "string", "sun", "sync", "tablet-device", "tag", "tags", "target", "task", "terminal", "text", "th-large", "th-list", "thumbs-down", "thumbs-up", "tiers", "timeline", "toggle-arrow-right", "token", "transfer", "translate", "trash", "trend-upward", "triangle-outline", "trolley", "truncate", "twitter", "ulist", "unarchive", "underline", "undo", "unknown", "unlink", "unlock", "unpublish", "upload", "user", "users", "versions", "video", "warning-filled", "warning-outline", "wrench"];
360
337
  /** A stored variant as it renders: anything off the list is Primary. */
361
338
  declare function buttonVariantOf(value: unknown): ButtonVariant;
362
339
  /** A stored icon as it renders: anything off the list is no icon. */
363
340
  declare function buttonIconOf(value: unknown): ButtonIcon | null;
364
341
  /** One icon as inline SVG sized to the button's text, hidden from assistive tech (the label names the button). */
365
342
  declare function buttonIconSvg(name: ButtonIcon, cls: "bcms-btn-icon" | "bcms-btn-arrow"): string;
343
+ declare const BUTTON_SIZES: readonly ["sm", "md", "lg"];
344
+ type ButtonSizeName = (typeof BUTTON_SIZES)[number];
345
+ /**
346
+ * The value a `button` field stores: the words, the link and the look, as Sanity stores a button
347
+ * object. Only `label` and `href` are required; every look key is optional and absent reads as
348
+ * today's default (Primary, medium, no arrow, no icon, same tab).
349
+ */
350
+ interface ButtonValue {
351
+ label: string;
352
+ href: string;
353
+ variant?: ButtonVariant;
354
+ size?: ButtonSizeName;
355
+ arrow?: boolean;
356
+ icon?: ButtonIcon | null;
357
+ newTab?: boolean;
358
+ }
359
+ /** A stored button value as it renders: every key read through the same allow-lists as a block. */
360
+ declare function readButtonValue(value: unknown): Required<ButtonValue>;
361
+ /** Why a value is not a button, or null when it is. Look keys are checked only when present. */
362
+ declare function buttonValueProblem(value: unknown): string | null;
363
+ /** The look keys an instance of a Button component may override, beside its label and link. */
364
+ declare const BUTTON_LOOK_KEYS: readonly ["variant", "size", "arrow", "icon", "newTab"];
365
+ type ButtonLookKey = (typeof BUTTON_LOOK_KEYS)[number];
366
+ interface PropDefLike {
367
+ key: string;
368
+ label?: string;
369
+ type?: string;
370
+ target: {
371
+ blockId: string;
372
+ path: string;
373
+ };
374
+ }
375
+ interface ComponentLike<P extends PropDefLike> {
376
+ category?: string | null;
377
+ blockJson?: unknown;
378
+ props?: readonly P[] | null;
379
+ }
380
+ /**
381
+ * A component's prop declarations, plus — on a Button component (category `button`, one button
382
+ * block) — a look prop for every `BUTTON_LOOK_KEYS` key it does not declare itself, each driving
383
+ * that block's `props.<key>`. So an INSTANCE of any Button carries its own look in its overrides
384
+ * (`{ text, href, variant, arrow, … }`) with nothing to backfill: every renderer that applies
385
+ * overrides passes this instead of `props`. Any other component is returned as declared, so a
386
+ * section with one CTA never has a stray `variant` override land on its button.
387
+ */
388
+ declare function withButtonLookProps<P extends PropDefLike>(def: ComponentLike<P>): P[];
389
+ /**
390
+ * One instance of a Button component as a `ButtonValue` — the definition's button with the
391
+ * instance's overrides written onto it — for a site rendering the instance with `BcmsButton`.
392
+ * Null when the component is not a Button (not category `button`, or not exactly one button).
393
+ */
394
+ declare function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): Required<ButtonValue> | null;
366
395
 
367
396
  /**
368
397
  * ContentBlock — a discriminated union of all CMS block types.
@@ -558,6 +587,8 @@ interface ButtonProps {
558
587
  arrow?: boolean;
559
588
  /** A leading icon from `BUTTON_ICONS`. Absent, null or off the list ⇒ none. */
560
589
  icon?: ButtonIcon | null;
590
+ /** Open the link in a new tab (`target="_blank" rel="noopener noreferrer"`). Absent ⇒ false. */
591
+ newTab?: boolean;
561
592
  }
562
593
  interface ButtonBlock {
563
594
  type: "button";
@@ -1611,7 +1642,8 @@ interface DeliveryComponent {
1611
1642
  * - `item` one item of that list, a second hop. `modular` has no item screen: its items are
1612
1643
  * other models.
1613
1644
  * A non-repeatable zone (`group`, `array` + zones.nonRepeatable, a `group` prop) is NOT a screen.
1614
- * It renders inline as a group, collapsed only when its own `ui.collapsed` is true.
1645
+ * It renders inline as a group, collapsed only when its own `ui.collapsed` is true. An array with
1646
+ * BOTH zones is that group with one more row, the branch that opens its list.
1615
1647
  *
1616
1648
  * On a screen:
1617
1649
  * - fieldsets with no `kind` are FLAT (V2): members render ungrouped, in document order;
@@ -2351,4 +2383,4 @@ declare function regionOf<E extends {
2351
2383
  el: E;
2352
2384
  }[], el: unknown): string | null;
2353
2385
 
2354
- export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BUTTON_ICONS, BUTTON_ICON_NAMES, BUTTON_VARIANTS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonProps, type ButtonVariant, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, DOCK_BUDGET, DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type DockBudget, type DockFieldLike, type DockFieldsetLike, type DockIconName, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type Fieldset, type FieldsetKind, type FieldsetUiBefore, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type PropGroup, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, dockBudget, dockScreens, expandBlockBindings, formatPropsAttribute, getBlockType, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, readPath, regionOf, spaceTokenCss };
2386
+ export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BUTTON_ICONS, BUTTON_ICON_NAMES, BUTTON_LOOK_KEYS, BUTTON_SIZES, BUTTON_VARIANTS, type BetterCMSErrorCode, type BgToken, type BindingKind, type BlockBinding, type BlockHoverStyle, type BlockStyle, type BlockType, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonLookKey, type ButtonProps, type ButtonSizeName, type ButtonValue, type ButtonVariant, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type CollectionBlock, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentVariantGroup, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentModelFieldUi, type ContentPageResult, type ContentResponse, type ContentWidthToken, type CornerToken, DIALOG_SELECTOR, DOCK_BUDGET, DOCK_ICON_NAMES, DOCK_ICON_NAME_SET, type DeepReadonly, type DeliveredLayout, type DeliveryComponent, type DeliveryEntry, type DeliveryEntrySeo, type DeliveryList, type DeliveryPage, type DerivedLocator, type DockBudget, type DockFieldLike, type DockFieldsetLike, type DockIconName, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FOOTER_SECTION_ID, type FieldConfig, type Fieldset, type FieldsetKind, type FieldsetUiBefore, type FontSizeToken, type FooterBlock, type FooterColumn, type FooterProps, type Form, type FormBlock, type FormField, type FormProps, type FormSubmission, type HeadingBlock, type HeadingProps, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, type LandmarkChainElement, type LandmarkElement, type LayoutComponentItem, type LayoutDataDocument, type LayoutFieldDefinition, type LayoutFieldItem, type LayoutFieldType, type LayoutScalarFieldType, type LayoutSection, type LayoutSectionIcon, type LayoutSectionItem, type LayoutStructureDocument, type LayoutZone, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, PAGE_CONTENT_ANCHOR_ID, type Page, type PageLayoutOverrideDataDocument, type PageLayoutOverrideDocument, type PageLayoutOverrideState, type PageLayoutOverrideStructureDocument, type PageLayoutSectionOverride, type PageLayoutSectionStructureOverride, type PageMetaJson, type PageOnlyLayoutSection, type PageSectionPlacement, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type PropGroup, type RadiusToken, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type SectionBlock, type SectionProps, type SectionSpaceToken, type ShadowToken, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, type VariantInputMapping, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, dockBudget, dockScreens, expandBlockBindings, formatPropsAttribute, getBlockType, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, readButtonValue, readPath, regionOf, spaceTokenCss, withButtonLookProps };
package/dist/index.js CHANGED
@@ -2425,10 +2425,15 @@ function layout(fields, fieldsets, root) {
2425
2425
  const nodeFor = (f, path) => {
2426
2426
  const key = `${path}${f.key}`;
2427
2427
  const zone = zoneFields(f);
2428
+ const items = listItems(f);
2428
2429
  if (zone) {
2429
- return { kind: "group", id: key, collapsed: f.ui?.collapsed === true, nodes: zone.map((z) => nodeFor(z, `${key}.`)) };
2430
+ const nodes = zone.map((z) => nodeFor(z, `${key}.`));
2431
+ if (zone.length > 0 && items?.length) {
2432
+ branches.set(key, { key, field: f, items });
2433
+ nodes.push({ kind: "branch", key });
2434
+ }
2435
+ return { kind: "group", id: key, collapsed: f.ui?.collapsed === true, nodes };
2430
2436
  }
2431
- const items = listItems(f);
2432
2437
  if (items !== void 0) {
2433
2438
  branches.set(key, { key, field: f, items });
2434
2439
  return { kind: "branch", key };
@@ -2602,34 +2607,92 @@ function buttonLinkPairs(candidates) {
2602
2607
  }
2603
2608
 
2604
2609
  // src/button-look.ts
2610
+ import { ICON_MARKUP, iconSvg } from "@bettercms-ai/icons/markup";
2605
2611
  var BUTTON_VARIANTS = ["primary", "secondary", "tertiary", "brand", "dark", "light", "outline", "link"];
2606
- var BUTTON_ICONS = {
2607
- "arrow-right": '<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>',
2608
- "arrow-up-right": '<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',
2609
- "chevron-right": '<path d="m9 18 6-6-6-6"/>',
2610
- plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
2611
- check: '<path d="M20 6 9 17l-5-5"/>',
2612
- download: '<path d="M12 15V3"/><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/>',
2613
- "external-link": '<path d="M15 3h6v6"/><path d="M10 14 21 3"/><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>',
2614
- mail: '<path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"/><rect x="2" y="4" width="20" height="16" rx="2"/>',
2615
- phone: '<path d="M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384"/>',
2616
- calendar: '<path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/>',
2617
- play: '<path d="M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"/>',
2618
- search: '<path d="m21 21-4.34-4.34"/><circle cx="11" cy="11" r="8"/>',
2619
- "shopping-cart": '<circle cx="8" cy="21" r="1"/><circle cx="19" cy="21" r="1"/><path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/>',
2620
- star: '<path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"/>',
2621
- sparkles: '<path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/><path d="M20 2v4"/><path d="M22 4h-4"/><circle cx="4" cy="20" r="2"/>',
2622
- zap: '<path d="M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z"/>'
2623
- };
2624
- var BUTTON_ICON_NAMES = Object.keys(BUTTON_ICONS);
2612
+ var BUTTON_ICONS = ICON_MARKUP;
2613
+ var BUTTON_ICON_NAMES = DOCK_ICON_NAMES;
2625
2614
  function buttonVariantOf(value) {
2626
2615
  return BUTTON_VARIANTS.includes(value) ? value : "primary";
2627
2616
  }
2628
2617
  function buttonIconOf(value) {
2629
- return BUTTON_ICON_NAMES.includes(value) ? value : null;
2618
+ return typeof value === "string" && DOCK_ICON_NAME_SET.has(value) ? value : null;
2630
2619
  }
2631
2620
  function buttonIconSvg(name, cls) {
2632
- return `<svg class="${cls}" viewBox="0 0 24 24" width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${BUTTON_ICONS[name]}</svg>`;
2621
+ return iconSvg(name, cls);
2622
+ }
2623
+ var BUTTON_SIZES = ["sm", "md", "lg"];
2624
+ var hrefOf = (href) => typeof href === "string" ? href : href && typeof href === "object" && typeof href.href === "string" ? href.href : null;
2625
+ function readButtonValue(value) {
2626
+ const v = value && typeof value === "object" ? value : {};
2627
+ return {
2628
+ label: typeof v.label === "string" ? v.label : "",
2629
+ href: hrefOf(v.href) ?? "",
2630
+ variant: buttonVariantOf(v.variant),
2631
+ size: BUTTON_SIZES.includes(v.size) ? v.size : "md",
2632
+ arrow: v.arrow === true,
2633
+ icon: buttonIconOf(v.icon),
2634
+ newTab: v.newTab === true
2635
+ };
2636
+ }
2637
+ function buttonValueProblem(value) {
2638
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "must be a { label, href } button";
2639
+ const v = value;
2640
+ if (typeof v.label !== "string") return "needs a label";
2641
+ if (hrefOf(v.href) === null) return "needs an href";
2642
+ if (v.variant !== void 0 && !BUTTON_VARIANTS.includes(v.variant)) return `has an unknown variant "${String(v.variant)}"`;
2643
+ if (v.size !== void 0 && !BUTTON_SIZES.includes(v.size)) return `has an unknown size "${String(v.size)}"`;
2644
+ if (v.arrow !== void 0 && typeof v.arrow !== "boolean") return "arrow must be true or false";
2645
+ if (v.newTab !== void 0 && typeof v.newTab !== "boolean") return "newTab must be true or false";
2646
+ if (v.icon !== void 0 && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon "${String(v.icon)}"`;
2647
+ return null;
2648
+ }
2649
+ var BUTTON_LOOK_KEYS = ["variant", "size", "arrow", "icon", "newTab"];
2650
+ function soleButtonId(blockJson) {
2651
+ const ids = [];
2652
+ const walk = (list) => {
2653
+ if (!Array.isArray(list)) return;
2654
+ for (const b of list) {
2655
+ if (b?.type === "button" && typeof b.id === "string") ids.push(b.id);
2656
+ walk(b?.props?.children);
2657
+ if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);
2658
+ }
2659
+ };
2660
+ walk(blockJson);
2661
+ return ids.length === 1 ? ids[0] : null;
2662
+ }
2663
+ var LOOK_PROP_TYPE = { variant: "text", size: "text", arrow: "boolean", icon: "text", newTab: "boolean" };
2664
+ var LOOK_PROP_LABEL = { variant: "Style", size: "Size", arrow: "Show arrow", icon: "Leading icon", newTab: "Open in new tab" };
2665
+ function withButtonLookProps(def) {
2666
+ const props = [...def.props ?? []];
2667
+ if (def.category !== "button") return props;
2668
+ const blockId = soleButtonId(def.blockJson);
2669
+ if (!blockId) return props;
2670
+ for (const key of BUTTON_LOOK_KEYS) {
2671
+ if (props.some((p) => p.key === key)) continue;
2672
+ props.push({ key, label: LOOK_PROP_LABEL[key], type: LOOK_PROP_TYPE[key], target: { blockId, path: `props.${key}` } });
2673
+ }
2674
+ return props;
2675
+ }
2676
+ function buttonValueOfInstance(def, overrides) {
2677
+ if (def.category !== "button") return null;
2678
+ const blockId = soleButtonId(def.blockJson);
2679
+ if (!blockId) return null;
2680
+ const found = [];
2681
+ const walk = (list) => {
2682
+ if (!Array.isArray(list)) return;
2683
+ for (const b of list) {
2684
+ if (b?.id === blockId) found.push(b);
2685
+ walk(b?.props?.children);
2686
+ if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);
2687
+ }
2688
+ };
2689
+ walk(def.blockJson);
2690
+ const props = { ...found[0]?.props ?? {} };
2691
+ for (const p of withButtonLookProps(def)) {
2692
+ if (p.target.blockId !== blockId || !p.target.path.startsWith("props.") || !overrides || !(p.key in overrides)) continue;
2693
+ props[p.target.path.slice("props.".length)] = overrides[p.key];
2694
+ }
2695
+ return readButtonValue({ ...props, label: props.text });
2633
2696
  }
2634
2697
 
2635
2698
  // src/locator.ts
@@ -2696,6 +2759,8 @@ export {
2696
2759
  BLOCK_BINDINGS,
2697
2760
  BUTTON_ICONS,
2698
2761
  BUTTON_ICON_NAMES,
2762
+ BUTTON_LOOK_KEYS,
2763
+ BUTTON_SIZES,
2699
2764
  BUTTON_VARIANTS,
2700
2765
  COMPONENT_PROP_TYPES,
2701
2766
  DIALOG_SELECTOR,
@@ -2717,6 +2782,8 @@ export {
2717
2782
  buttonIconOf,
2718
2783
  buttonIconSvg,
2719
2784
  buttonLinkPairs,
2785
+ buttonValueOfInstance,
2786
+ buttonValueProblem,
2720
2787
  buttonVariantOf,
2721
2788
  candidateRole,
2722
2789
  componentInstanceAddresses,
@@ -2732,8 +2799,10 @@ export {
2732
2799
  landmarkRegions,
2733
2800
  locatorFor,
2734
2801
  parsePropsAttribute,
2802
+ readButtonValue,
2735
2803
  readPath,
2736
2804
  regionOf,
2737
- spaceTokenCss
2805
+ spaceTokenCss,
2806
+ withButtonLookProps
2738
2807
  };
2739
2808
  //# sourceMappingURL=index.js.map