@bettercms-ai/types 1.37.0 → 1.38.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
@@ -129,6 +129,11 @@ interface FieldConfig {
129
129
  max?: number;
130
130
  /** date / datetime */
131
131
  includeTime?: boolean;
132
+ /**
133
+ * date / datetime with a time: "site" (the project's own zone) or an IANA zone name. When set,
134
+ * a stored value must carry `Z` or a numeric offset, so it names one instant in every region.
135
+ */
136
+ timezone?: string;
132
137
  /** modular: SLUGS of the kind='block' models this field accepts. Non-empty. */
133
138
  blockSlugs?: string[];
134
139
  /** modular: bounds on how many block instances the field may hold. */
@@ -201,6 +206,20 @@ interface FieldConfig {
201
206
  * field past that gate.
202
207
  */
203
208
  type ContentModelFieldPlacement = "cover" | "title" | "excerpt" | "body" | "inline" | "panel";
209
+ /**
210
+ * Editor-only conditional visibility: the field (or component prop) shows only while the
211
+ * sibling keys its rules name hold these values. `isSet` reads no `value`: it passes once the
212
+ * source holds anything (`false` and `0` count; "", null and an empty list do not).
213
+ */
214
+ interface ShowIfRule {
215
+ field: string;
216
+ op: "eq" | "neq" | "in" | "isSet";
217
+ value?: string | string[];
218
+ }
219
+ interface ShowIf {
220
+ match: "all" | "any";
221
+ rules: ShowIfRule[];
222
+ }
204
223
  interface ContentModelField {
205
224
  key: string;
206
225
  label: string;
@@ -227,6 +246,18 @@ interface ContentModelField {
227
246
  * Field ORDER is the array index — there is deliberately no `order` property.
228
247
  */
229
248
  placement?: ContentModelFieldPlacement;
249
+ /** Editor-only conditional visibility; a hidden required field is not required. @see ShowIf */
250
+ showIf?: ShowIf;
251
+ /**
252
+ * A value another system owns (a store, job board or feed id).
253
+ * - `"developer"`: only a caller with schema authority (a key with `schema:manage`, a person
254
+ * with schema access) may change the value on an entry, or add or remove this lock. Anyone
255
+ * else is refused with 403 `FIELD_LOCKED`. Needs {@link lockReason}.
256
+ * - `true`: a marker the editor renders read-only. The API does not enforce it.
257
+ */
258
+ readOnly?: true | "developer";
259
+ /** Which system owns the value; shown on the refusal. At most 200 characters. */
260
+ lockReason?: string;
230
261
  /**
231
262
  * Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a
232
263
  * renderer, and never able to move a value; the same contract as {@link placement}.
@@ -386,6 +417,14 @@ type ButtonSizeName = (typeof BUTTON_SIZES)[number];
386
417
  * object. Only `label` and `href` are required; every look key is optional and absent reads as
387
418
  * today's default (Primary, medium, no arrow, no icon, same tab).
388
419
  */
420
+ declare const LINK_RELS: readonly ["nofollow", "sponsored", "ugc"];
421
+ type LinkRel = (typeof LINK_RELS)[number];
422
+ /**
423
+ * The target and rel attributes of an anchor, as one string. A new tab keeps the `noopener
424
+ * noreferrer` pair; a link relation joins it in the SAME rel attribute, so an anchor never
425
+ * carries two.
426
+ */
427
+ declare function anchorTargetRel(newTab: boolean, rel?: unknown): string;
389
428
  interface ButtonValue {
390
429
  label: string;
391
430
  href: string;
@@ -394,14 +433,24 @@ interface ButtonValue {
394
433
  arrow?: boolean;
395
434
  icon?: ButtonIcon | null;
396
435
  newTab?: boolean;
436
+ /** Sponsored, untrusted or user-generated destination. Absent ⇒ no rel beyond a new tab's own. */
437
+ rel?: LinkRel;
397
438
  }
439
+ /** A stored button value as it renders: `rel` stays optional, every other key is filled. */
440
+ type ReadButtonValue = Required<Omit<ButtonValue, "rel">> & Pick<ButtonValue, "rel">;
398
441
  /** A stored button value as it renders: every key read through the same allow-lists as a block. */
399
- declare function readButtonValue(value: unknown): Required<ButtonValue>;
442
+ declare function readButtonValue(value: unknown): ReadButtonValue;
400
443
  /** Why a value is not a button, or null when it is. Look keys are checked only when present. */
401
444
  declare function buttonValueProblem(value: unknown): string | null;
402
445
  /** The look keys an instance of a Button component may override, beside its label and link. */
403
446
  declare const BUTTON_LOOK_KEYS: readonly ["variant", "size", "arrow", "icon", "newTab"];
404
447
  type ButtonLookKey = (typeof BUTTON_LOOK_KEYS)[number];
448
+ /**
449
+ * A `button` PROP's value as the `button` BLOCK props it writes, for every lane that applies an
450
+ * instance's overrides. `label` lands on `text`, and only the keys the value names come back, so
451
+ * an override carrying a label alone keeps the definition's href and look.
452
+ */
453
+ declare function buttonBlockProps(value: unknown): Record<string, unknown>;
405
454
  interface PropDefLike {
406
455
  key: string;
407
456
  label?: string;
@@ -430,7 +479,7 @@ declare function withButtonLookProps<P extends PropDefLike>(def: ComponentLike<P
430
479
  * instance's overrides written onto it — for a site rendering the instance with `BcmsButton`.
431
480
  * Null when the component is not a Button (not category `button`, or not exactly one button).
432
481
  */
433
- declare function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): Required<ButtonValue> | null;
482
+ declare function buttonValueOfInstance<P extends PropDefLike>(def: ComponentLike<P>, overrides: Record<string, unknown> | null | undefined): ReadButtonValue | null;
434
483
 
435
484
  /**
436
485
  * ContentBlock — a discriminated union of all CMS block types.
@@ -629,6 +678,8 @@ interface ButtonProps {
629
678
  icon?: ButtonIcon | null;
630
679
  /** Open the link in a new tab (`target="_blank" rel="noopener noreferrer"`). Absent ⇒ false. */
631
680
  newTab?: boolean;
681
+ /** `nofollow`, `sponsored` or `ugc`; joins the anchor's rel. Absent ⇒ none. */
682
+ rel?: "nofollow" | "sponsored" | "ugc";
632
683
  }
633
684
  interface ButtonBlock {
634
685
  type: "button";
@@ -832,6 +883,29 @@ interface CollectionProps {
832
883
  /** "newest" (default) reverses the reader's created_at ordering. */
833
884
  order?: "newest" | "oldest";
834
885
  emptyText?: string;
886
+ /**
887
+ * List the published entries of ANOTHER model, on any page ("latest posts" on the home page).
888
+ * Absent: the entries of the page this block sits on, as above. A model of another project or
889
+ * workspace lists nothing. A sourced block is always a card list, on a detail URL too.
890
+ */
891
+ source?: {
892
+ modelId: string;
893
+ };
894
+ /** Sourced lists only. The Delivery API's filter grammar; field keys are the model's own. */
895
+ filters?: CollectionFilter[];
896
+ /** Sourced lists only. The Delivery API's sort grammar (`-publishedAt,title`); wins over `order`. */
897
+ sort?: string;
898
+ /** Sourced lists only. Entry ids rendered first, in this order; counted against `limit`. */
899
+ pinnedIds?: string[];
900
+ /** Sourced lists only. On an entry's detail URL, leave that entry out ("related posts"). */
901
+ excludeCurrent?: boolean;
902
+ }
903
+ interface CollectionFilter {
904
+ /** A field key of the source model, or `slug`, `publishedAt`, `locale`. */
905
+ field: string;
906
+ op: "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "contains" | "in";
907
+ /** `in` takes a comma-separated list. */
908
+ value: string | number | boolean;
835
909
  }
836
910
  interface CollectionBlock {
837
911
  type: "collection";
@@ -1555,7 +1629,7 @@ type ComponentCategory = "navbar" | "footer" | "button" | "section" | "slider" |
1555
1629
  *
1556
1630
  * Order is not semantic; append rather than re-sort, so a diff stays readable.
1557
1631
  */
1558
- declare const COMPONENT_PROP_TYPES: readonly ["text", "richtext", "image", "url", "boolean", "number", "select", "group", "table", "slot", "form"];
1632
+ declare const COMPONENT_PROP_TYPES: readonly ["text", "richtext", "image", "url", "boolean", "number", "select", "group", "table", "slot", "form", "link", "button", "date", "color", "file", "icon", "multiselect"];
1559
1633
  type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];
1560
1634
  /**
1561
1635
  * The value a `form` prop STORES: just the id. The form itself is a Form document and stays the
@@ -1597,6 +1671,14 @@ interface ComponentPropDef {
1597
1671
  * select → one string from `config.options`
1598
1672
  * group → an object keyed by `config.fields`
1599
1673
  * table → an array of such objects (slider.slides)
1674
+ * link → an href string (URL, internal path or #fragment)
1675
+ * button → ONE `ButtonValue` (button-look.ts): label, href and look as a unit, never a text prop plus
1676
+ * a url prop that drift apart. Targets the `props` of a `button` block.
1677
+ * date → `YYYY-MM-DD`
1678
+ * color → a hex colour (`#RGB`, `#RRGGBB`, `#RRGGBBAA`)
1679
+ * file → `{ url, name?, size? }`, or a bare URL string
1680
+ * icon → a BetterCMS icon name (`DOCK_ICON_NAMES`), or an uploaded icon as an image value
1681
+ * multiselect → a `string[]`, each one of `config.options`
1600
1682
  *
1601
1683
  * `reference` is absent on purpose: nothing resolves a content-entry id at component render
1602
1684
  * time, so such a prop would save cleanly and render as nothing.
@@ -1619,12 +1701,23 @@ interface ComponentPropDef {
1619
1701
  helpSource?: "auto" | "human" | "agent";
1620
1702
  /** Ghost text inside a text-ish control. */
1621
1703
  placeholder?: string;
1704
+ /**
1705
+ * Editor-only conditional visibility: show this prop's control only while sibling props (by
1706
+ * key) hold these values. The save schema refuses a key no prop of the component declares.
1707
+ */
1708
+ showIf?: ShowIf;
1709
+ /**
1710
+ * The content-model field's `readOnly` / `lockReason` pair, as STORED MARKERS only: the
1711
+ * editor may render the prop read-only, and no write of a prop value is refused for them.
1712
+ */
1713
+ readOnly?: true | "developer";
1714
+ lockReason?: string;
1622
1715
  /** Per-type settings; the save schema enforces that each is present on the type needing it. */
1623
1716
  config?: {
1624
1717
  /** `slot` — a pick allowlist. */
1625
1718
  componentIds?: string[];
1626
1719
  /**
1627
- * `select` — the choices. Required, and a default must be one of them. `{ label, value }`
1720
+ * `select` / `multiselect` — the choices. Required, and a default must be one of them. `{ label, value }`
1628
1721
  * when the stored value is not what an author should read (a component id, for instance).
1629
1722
  */
1630
1723
  options?: Array<string | {
@@ -2587,4 +2680,4 @@ declare function regionOf<E extends {
2587
2680
  el: E;
2588
2681
  }[], el: unknown): string | null;
2589
2682
 
2590
- 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_PLACEMENT_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 DockInputRef, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FIELD_STYLE_KEYS, FOOTER_SECTION_ID, type FieldConfig, type FieldStyle, type FieldStyleKey, type FieldStyles, 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, blockStyleToColumnCss, blockStyleToCss, blockStyleToInnerCss, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, derivedPairs, dockBudget, dockScreens, expandBlockBindings, fieldStyleCssText, fieldStyleToCss, formatPropsAttribute, getBlockType, headingPaintCss, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, pickFieldStyle, readButtonValue, readPath, regionOf, safeCssUrl, spaceTokenCss, splitButtonStyle, withButtonLookProps };
2683
+ 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_PLACEMENT_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 CollectionFilter, 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 DockInputRef, type DockLane, type DockNode, type DockPropGroupLike, type DockScreen, type ElementLike, type ExpandedBinding, FIELD_STYLE_KEYS, FOOTER_SECTION_ID, type FieldConfig, type FieldStyle, type FieldStyleKey, type FieldStyles, 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, LINK_RELS, 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 LinkRel, 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 ReadButtonValue, 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 ShowIf, type ShowIfRule, 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, anchorTargetRel, blockStyleToColumnCss, blockStyleToCss, blockStyleToInnerCss, buttonBlockProps, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, derivedPairs, dockBudget, dockScreens, expandBlockBindings, fieldStyleCssText, fieldStyleToCss, formatPropsAttribute, getBlockType, headingPaintCss, isBlock, isChromeLandmark, keyWords, landmarkRegions, locatorFor, parsePropsAttribute, pickFieldStyle, readButtonValue, readPath, regionOf, safeCssUrl, spaceTokenCss, splitButtonStyle, withButtonLookProps };
package/dist/index.js CHANGED
@@ -335,7 +335,16 @@ var COMPONENT_PROP_TYPES = [
335
335
  "group",
336
336
  "table",
337
337
  "slot",
338
- "form"
338
+ "form",
339
+ // The seven below each store what the same-named content-model FIELD stores (`icon` and
340
+ // `multiselect` have no field twin; see the value notes on ComponentPropDef.type).
341
+ "link",
342
+ "button",
343
+ "date",
344
+ "color",
345
+ "file",
346
+ "icon",
347
+ "multiselect"
339
348
  ];
340
349
 
341
350
  // src/layout-lucide-icons.ts
@@ -2810,6 +2819,11 @@ function buttonIconSvg(name, cls) {
2810
2819
  return iconSvg(name, cls);
2811
2820
  }
2812
2821
  var BUTTON_SIZES = ["sm", "md", "lg"];
2822
+ var LINK_RELS = ["nofollow", "sponsored", "ugc"];
2823
+ function anchorTargetRel(newTab, rel) {
2824
+ const tokens = [...newTab ? ["noopener", "noreferrer"] : [], ...LINK_RELS.includes(rel) ? [rel] : []];
2825
+ return `${newTab ? ' target="_blank"' : ""}${tokens.length ? ` rel="${tokens.join(" ")}"` : ""}`;
2826
+ }
2813
2827
  var hrefOf = (href) => typeof href === "string" ? href : href && typeof href === "object" && typeof href.href === "string" ? href.href : null;
2814
2828
  function readButtonValue(value) {
2815
2829
  const v = value && typeof value === "object" ? value : {};
@@ -2820,7 +2834,8 @@ function readButtonValue(value) {
2820
2834
  size: BUTTON_SIZES.includes(v.size) ? v.size : "md",
2821
2835
  arrow: v.arrow === true,
2822
2836
  icon: buttonIconOf(v.icon),
2823
- newTab: v.newTab === true
2837
+ newTab: v.newTab === true,
2838
+ ...LINK_RELS.includes(v.rel) ? { rel: v.rel } : {}
2824
2839
  };
2825
2840
  }
2826
2841
  function buttonValueProblem(value) {
@@ -2832,10 +2847,21 @@ function buttonValueProblem(value) {
2832
2847
  if (v.size !== void 0 && !BUTTON_SIZES.includes(v.size)) return `has an unknown size "${String(v.size)}"`;
2833
2848
  if (v.arrow !== void 0 && typeof v.arrow !== "boolean") return "arrow must be true or false";
2834
2849
  if (v.newTab !== void 0 && typeof v.newTab !== "boolean") return "newTab must be true or false";
2850
+ if (v.rel !== void 0 && !LINK_RELS.includes(v.rel)) return `has an unknown rel "${String(v.rel)}" (nofollow, sponsored or ugc)`;
2835
2851
  if (v.icon !== void 0 && v.icon !== null && buttonIconOf(v.icon) === null) return `has an unknown icon "${String(v.icon)}"`;
2836
2852
  return null;
2837
2853
  }
2838
2854
  var BUTTON_LOOK_KEYS = ["variant", "size", "arrow", "icon", "newTab"];
2855
+ function buttonBlockProps(value) {
2856
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
2857
+ const v = value;
2858
+ const out = {};
2859
+ if (typeof v.label === "string") out.text = v.label;
2860
+ const href = hrefOf(v.href);
2861
+ if (href !== null) out.href = href;
2862
+ for (const key of BUTTON_LOOK_KEYS) if (key in v) out[key] = v[key];
2863
+ return out;
2864
+ }
2839
2865
  function soleButtonId(blockJson) {
2840
2866
  const ids = [];
2841
2867
  const walk = (list) => {
@@ -2878,8 +2904,9 @@ function buttonValueOfInstance(def, overrides) {
2878
2904
  walk(def.blockJson);
2879
2905
  const props = { ...found[0]?.props ?? {} };
2880
2906
  for (const p of withButtonLookProps(def)) {
2881
- if (p.target.blockId !== blockId || !p.target.path.startsWith("props.") || !overrides || !(p.key in overrides)) continue;
2882
- props[p.target.path.slice("props.".length)] = overrides[p.key];
2907
+ if (p.target.blockId !== blockId || !overrides || !(p.key in overrides)) continue;
2908
+ if (p.type === "button") Object.assign(props, buttonBlockProps(overrides[p.key]));
2909
+ else if (p.target.path.startsWith("props.")) props[p.target.path.slice("props.".length)] = overrides[p.key];
2883
2910
  }
2884
2911
  return readButtonValue({ ...props, label: props.text });
2885
2912
  }
@@ -2962,6 +2989,7 @@ export {
2962
2989
  LANDMARK_SELECTOR,
2963
2990
  LAYOUT_SECTION_ICONS,
2964
2991
  LAYOUT_SECTION_ICON_SET,
2992
+ LINK_RELS,
2965
2993
  MAIN_SELECTOR,
2966
2994
  NAVIGATION_SECTION_ID,
2967
2995
  PAGE_CONTENT_ANCHOR_ID,
@@ -2969,9 +2997,11 @@ export {
2969
2997
  SECTION_SPACE_TOKENS,
2970
2998
  SPACE_BOTTOM_TOKENS,
2971
2999
  SPACE_STEP_TOKENS,
3000
+ anchorTargetRel,
2972
3001
  blockStyleToColumnCss,
2973
3002
  blockStyleToCss,
2974
3003
  blockStyleToInnerCss,
3004
+ buttonBlockProps,
2975
3005
  buttonIconOf,
2976
3006
  buttonIconSvg,
2977
3007
  buttonLinkPairs,