@bettercms-ai/types 1.26.0 → 1.27.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/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}`
@@ -326,43 +326,70 @@ declare const SPACE_BOTTOM_TOKENS: ("section-space-none" | "section-space-small"
326
326
  /** `var(--bcms-<token>,<px>)`, or "" for anything that is not a known token (closed set). */
327
327
  declare function spaceTokenCss(token: unknown): string;
328
328
 
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
329
  declare const BUTTON_VARIANTS: readonly ["primary", "secondary", "tertiary", "brand", "dark", "light", "outline", "link"];
338
330
  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[]];
331
+ /** Each icon's inner SVG markup (viewBox `0 0 25 25`), by name. */
332
+ declare const BUTTON_ICONS: Readonly<Record<DockIconName, string>>;
333
+ type ButtonIcon = DockIconName;
334
+ 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
335
  /** A stored variant as it renders: anything off the list is Primary. */
361
336
  declare function buttonVariantOf(value: unknown): ButtonVariant;
362
337
  /** A stored icon as it renders: anything off the list is no icon. */
363
338
  declare function buttonIconOf(value: unknown): ButtonIcon | null;
364
339
  /** One icon as inline SVG sized to the button's text, hidden from assistive tech (the label names the button). */
365
340
  declare function buttonIconSvg(name: ButtonIcon, cls: "bcms-btn-icon" | "bcms-btn-arrow"): string;
341
+ declare const BUTTON_SIZES: readonly ["sm", "md", "lg"];
342
+ type ButtonSizeName = (typeof BUTTON_SIZES)[number];
343
+ /**
344
+ * The value a `button` field stores: the words, the link and the look, as Sanity stores a button
345
+ * object. Only `label` and `href` are required; every look key is optional and absent reads as
346
+ * today's default (Primary, medium, no arrow, no icon, same tab).
347
+ */
348
+ interface ButtonValue {
349
+ label: string;
350
+ href: string;
351
+ variant?: ButtonVariant;
352
+ size?: ButtonSizeName;
353
+ arrow?: boolean;
354
+ icon?: ButtonIcon | null;
355
+ newTab?: boolean;
356
+ }
357
+ /** A stored button value as it renders: every key read through the same allow-lists as a block. */
358
+ declare function readButtonValue(value: unknown): Required<ButtonValue>;
359
+ /** Why a value is not a button, or null when it is. Look keys are checked only when present. */
360
+ declare function buttonValueProblem(value: unknown): string | null;
361
+ /** The look keys an instance of a Button component may override, beside its label and link. */
362
+ declare const BUTTON_LOOK_KEYS: readonly ["variant", "size", "arrow", "icon", "newTab"];
363
+ type ButtonLookKey = (typeof BUTTON_LOOK_KEYS)[number];
364
+ interface PropDefLike {
365
+ key: string;
366
+ label?: string;
367
+ type?: string;
368
+ target: {
369
+ blockId: string;
370
+ path: string;
371
+ };
372
+ }
373
+ interface ComponentLike<P extends PropDefLike> {
374
+ category?: string | null;
375
+ blockJson?: unknown;
376
+ props?: readonly P[] | null;
377
+ }
378
+ /**
379
+ * A component's prop declarations, plus — on a Button component (category `button`, one button
380
+ * block) — a look prop for every `BUTTON_LOOK_KEYS` key it does not declare itself, each driving
381
+ * that block's `props.<key>`. So an INSTANCE of any Button carries its own look in its overrides
382
+ * (`{ text, href, variant, arrow, … }`) with nothing to backfill: every renderer that applies
383
+ * overrides passes this instead of `props`. Any other component is returned as declared, so a
384
+ * section with one CTA never has a stray `variant` override land on its button.
385
+ */
386
+ declare function withButtonLookProps<P extends PropDefLike>(def: ComponentLike<P>): P[];
387
+ /**
388
+ * One instance of a Button component as a `ButtonValue` — the definition's button with the
389
+ * instance's overrides written onto it — for a site rendering the instance with `BcmsButton`.
390
+ * Null when the component is not a Button (not category `button`, or not exactly one button).
391
+ */
392
+ declare function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): Required<ButtonValue> | null;
366
393
 
367
394
  /**
368
395
  * ContentBlock — a discriminated union of all CMS block types.
@@ -558,6 +585,8 @@ interface ButtonProps {
558
585
  arrow?: boolean;
559
586
  /** A leading icon from `BUTTON_ICONS`. Absent, null or off the list ⇒ none. */
560
587
  icon?: ButtonIcon | null;
588
+ /** Open the link in a new tab (`target="_blank" rel="noopener noreferrer"`). Absent ⇒ false. */
589
+ newTab?: boolean;
561
590
  }
562
591
  interface ButtonBlock {
563
592
  type: "button";
@@ -2351,4 +2380,4 @@ declare function regionOf<E extends {
2351
2380
  el: E;
2352
2381
  }[], el: unknown): string | null;
2353
2382
 
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 };
2383
+ 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
@@ -2602,34 +2602,92 @@ function buttonLinkPairs(candidates) {
2602
2602
  }
2603
2603
 
2604
2604
  // src/button-look.ts
2605
+ import { ICON_MARKUP, iconSvg } from "@bettercms-ai/icons/markup";
2605
2606
  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);
2607
+ var BUTTON_ICONS = ICON_MARKUP;
2608
+ var BUTTON_ICON_NAMES = DOCK_ICON_NAMES;
2625
2609
  function buttonVariantOf(value) {
2626
2610
  return BUTTON_VARIANTS.includes(value) ? value : "primary";
2627
2611
  }
2628
2612
  function buttonIconOf(value) {
2629
- return BUTTON_ICON_NAMES.includes(value) ? value : null;
2613
+ return typeof value === "string" && DOCK_ICON_NAME_SET.has(value) ? value : null;
2630
2614
  }
2631
2615
  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>`;
2616
+ return iconSvg(name, cls);
2617
+ }
2618
+ var BUTTON_SIZES = ["sm", "md", "lg"];
2619
+ var hrefOf = (href) => typeof href === "string" ? href : href && typeof href === "object" && typeof href.href === "string" ? href.href : null;
2620
+ function readButtonValue(value) {
2621
+ const v = value && typeof value === "object" ? value : {};
2622
+ return {
2623
+ label: typeof v.label === "string" ? v.label : "",
2624
+ href: hrefOf(v.href) ?? "",
2625
+ variant: buttonVariantOf(v.variant),
2626
+ size: BUTTON_SIZES.includes(v.size) ? v.size : "md",
2627
+ arrow: v.arrow === true,
2628
+ icon: buttonIconOf(v.icon),
2629
+ newTab: v.newTab === true
2630
+ };
2631
+ }
2632
+ function buttonValueProblem(value) {
2633
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "must be a { label, href } button";
2634
+ const v = value;
2635
+ if (typeof v.label !== "string") return "needs a label";
2636
+ if (hrefOf(v.href) === null) return "needs an href";
2637
+ if (v.variant !== void 0 && !BUTTON_VARIANTS.includes(v.variant)) return `has an unknown variant "${String(v.variant)}"`;
2638
+ if (v.size !== void 0 && !BUTTON_SIZES.includes(v.size)) return `has an unknown size "${String(v.size)}"`;
2639
+ if (v.arrow !== void 0 && typeof v.arrow !== "boolean") return "arrow must be true or false";
2640
+ if (v.newTab !== void 0 && typeof v.newTab !== "boolean") return "newTab must be true or false";
2641
+ if (v.icon !== void 0 && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon "${String(v.icon)}"`;
2642
+ return null;
2643
+ }
2644
+ var BUTTON_LOOK_KEYS = ["variant", "size", "arrow", "icon", "newTab"];
2645
+ function soleButtonId(blockJson) {
2646
+ const ids = [];
2647
+ const walk = (list) => {
2648
+ if (!Array.isArray(list)) return;
2649
+ for (const b of list) {
2650
+ if (b?.type === "button" && typeof b.id === "string") ids.push(b.id);
2651
+ walk(b?.props?.children);
2652
+ if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);
2653
+ }
2654
+ };
2655
+ walk(blockJson);
2656
+ return ids.length === 1 ? ids[0] : null;
2657
+ }
2658
+ var LOOK_PROP_TYPE = { variant: "text", size: "text", arrow: "boolean", icon: "text", newTab: "boolean" };
2659
+ var LOOK_PROP_LABEL = { variant: "Style", size: "Size", arrow: "Show arrow", icon: "Leading icon", newTab: "Open in new tab" };
2660
+ function withButtonLookProps(def) {
2661
+ const props = [...def.props ?? []];
2662
+ if (def.category !== "button") return props;
2663
+ const blockId = soleButtonId(def.blockJson);
2664
+ if (!blockId) return props;
2665
+ for (const key of BUTTON_LOOK_KEYS) {
2666
+ if (props.some((p) => p.key === key)) continue;
2667
+ props.push({ key, label: LOOK_PROP_LABEL[key], type: LOOK_PROP_TYPE[key], target: { blockId, path: `props.${key}` } });
2668
+ }
2669
+ return props;
2670
+ }
2671
+ function buttonValueOfInstance(def, overrides) {
2672
+ if (def.category !== "button") return null;
2673
+ const blockId = soleButtonId(def.blockJson);
2674
+ if (!blockId) return null;
2675
+ const found = [];
2676
+ const walk = (list) => {
2677
+ if (!Array.isArray(list)) return;
2678
+ for (const b of list) {
2679
+ if (b?.id === blockId) found.push(b);
2680
+ walk(b?.props?.children);
2681
+ if (Array.isArray(b?.props?.columns)) for (const column of b.props.columns) walk(column);
2682
+ }
2683
+ };
2684
+ walk(def.blockJson);
2685
+ const props = { ...found[0]?.props ?? {} };
2686
+ for (const p of withButtonLookProps(def)) {
2687
+ if (p.target.blockId !== blockId || !p.target.path.startsWith("props.") || !overrides || !(p.key in overrides)) continue;
2688
+ props[p.target.path.slice("props.".length)] = overrides[p.key];
2689
+ }
2690
+ return readButtonValue({ ...props, label: props.text });
2633
2691
  }
2634
2692
 
2635
2693
  // src/locator.ts
@@ -2696,6 +2754,8 @@ export {
2696
2754
  BLOCK_BINDINGS,
2697
2755
  BUTTON_ICONS,
2698
2756
  BUTTON_ICON_NAMES,
2757
+ BUTTON_LOOK_KEYS,
2758
+ BUTTON_SIZES,
2699
2759
  BUTTON_VARIANTS,
2700
2760
  COMPONENT_PROP_TYPES,
2701
2761
  DIALOG_SELECTOR,
@@ -2717,6 +2777,8 @@ export {
2717
2777
  buttonIconOf,
2718
2778
  buttonIconSvg,
2719
2779
  buttonLinkPairs,
2780
+ buttonValueOfInstance,
2781
+ buttonValueProblem,
2720
2782
  buttonVariantOf,
2721
2783
  candidateRole,
2722
2784
  componentInstanceAddresses,
@@ -2732,8 +2794,10 @@ export {
2732
2794
  landmarkRegions,
2733
2795
  locatorFor,
2734
2796
  parsePropsAttribute,
2797
+ readButtonValue,
2735
2798
  readPath,
2736
2799
  regionOf,
2737
- spaceTokenCss
2800
+ spaceTokenCss,
2801
+ withButtonLookProps
2738
2802
  };
2739
2803
  //# sourceMappingURL=index.js.map