@bettercms-ai/types 1.50.0 → 1.50.2

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
@@ -54,6 +54,11 @@ interface NumberFieldFormat {
54
54
  decimal?: "." | ",";
55
55
  /** Fraction digits always shown (`2` for `£3.20`). A value with more keeps its own, up to six. */
56
56
  decimals?: number;
57
+ /**
58
+ * How the integer digits are grouped: `"3"` (absent) in threes, `"3;2"` the Indian way, the last
59
+ * three then pairs (`₹1,20,000`). Only meaningful with a `group` mark.
60
+ */
61
+ grouping?: "3" | "3;2";
57
62
  }
58
63
  /** The format a stored `config.format` holds, with anything malformed dropped: a bad row never throws at publish. */
59
64
  declare function readNumberFormat(raw: unknown): NumberFieldFormat;
@@ -431,6 +436,11 @@ interface ContentModelField {
431
436
  * translation write that changes one is 409 `FIELD_NOT_LOCALIZED`. None marked: rows copy as before.
432
437
  */
433
438
  localized?: boolean;
439
+ /**
440
+ * Schema V2 archive: the field is out of the entry form and the delivery API. Its key and
441
+ * stored values stay, so `false` restores it with nothing lost.
442
+ */
443
+ archived?: boolean;
434
444
  /**
435
445
  * Authoring chrome — how the field PRESENTS in the editor. Never delivered, never read by a
436
446
  * renderer, and never able to move a value; the same contract as {@link placement}.
@@ -513,6 +523,11 @@ interface ContentModelFieldUi {
513
523
  };
514
524
  /** V2 `valueShape`: a link / image / button writes a plain string or the object. */
515
525
  valueShape?: "string" | "object";
526
+ /** A live reference to a vendor item (custom integrations): the integration's slug and reference key. */
527
+ reference?: {
528
+ integration: string;
529
+ key: string;
530
+ };
516
531
  /** V2 field access (D58): who sees and who changes it. The editor gates; the backend stores. */
517
532
  access?: {
518
533
  view?: "schema.view";
@@ -587,6 +602,61 @@ interface Page {
587
602
  } | null;
588
603
  }
589
604
 
605
+ /**
606
+ * A page BODY's own allow-list: which components a page accepts as sections (`pages.body_schema`,
607
+ * migration 0494). "A page accepts only the components built for that page."
608
+ *
609
+ * A third axis beside a zone's `allowedSections` and a component's `allowedOn`, judged by the same
610
+ * resolver (`resolveInsertableSections`, deny reason `not-in-body-allowlist`).
611
+ *
612
+ * 🔴 THE EMPTY-ARRAY TRAP, the same as on both other lists:
613
+ * body_schema NULL = UNRESTRICTED (every page that predates 0494; today's behaviour)
614
+ * `allowed: []` = DENY-ALL — no component is accepted. Never write `[]` to mean "unset":
615
+ * unset is the column being NULL.
616
+ */
617
+ /**
618
+ * One rule. A component is accepted when ANY rule matches it.
619
+ *
620
+ * source built for this page: `splitSourceKey(component.sourceKey).page === pageId`, read off the
621
+ * component's CURRENT source key at judge time (never a string prefix). A component with
622
+ * no source key, or one whose key names no page (a shared band, a pre-per-page key), is
623
+ * not built for any page.
624
+ * component exactly this component id.
625
+ * family any component of this section family (`sectionType`, trimmed, case-insensitive) — so a
626
+ * variant swap passes iff its TARGET passes.
627
+ * builtins the platform's built-in sections (`builtin:*`), and a project's copy of one.
628
+ * workspace the workspace's shared components (`project_id IS NULL`).
629
+ */
630
+ type AllowRule = {
631
+ kind: "source";
632
+ pageId: string;
633
+ } | {
634
+ kind: "component";
635
+ id: string;
636
+ } | {
637
+ kind: "family";
638
+ sectionType: string;
639
+ } | {
640
+ kind: "builtins";
641
+ } | {
642
+ kind: "workspace";
643
+ };
644
+ /** Who wrote the list: a lane's guess (componentize), a person's confirmation of it, or a person's own. */
645
+ type BodySchemaOrigin = "inferred" | "confirmed" | "authored";
646
+ interface BodySchema {
647
+ /** `[]` = deny-all. See the file header: unset is a NULL column, never an empty list. */
648
+ allowed: AllowRule[];
649
+ origin: BodySchemaOrigin;
650
+ }
651
+ declare const BODY_SCHEMA_ORIGINS: readonly BodySchemaOrigin[];
652
+ /** Pure. One stored rule as an `AllowRule`, or null for one this reader does not know (it matches nothing). */
653
+ declare function allowRuleOf(value: unknown): AllowRule | null;
654
+ /**
655
+ * Pure. A stored `body_schema` as a `BodySchema`, or null (unrestricted) when it is not one.
656
+ * An unknown rule is dropped, which narrows the list — never widens it.
657
+ */
658
+ declare function bodySchemaOf(value: unknown): BodySchema | null;
659
+
590
660
  /**
591
661
  * Section spacing as TOKEN STEPS — the ONE list of names and default sizes, shared by the save
592
662
  * schema and every renderer. A stored value is always a token (`section-space-large`), never a
@@ -1327,6 +1397,12 @@ interface ComponentProps {
1327
1397
  * while `bind` is; dropped with it when the instance takes its copy.
1328
1398
  */
1329
1399
  bindPaths?: Record<string, string>;
1400
+ /**
1401
+ * Phase B: the props this INSTANCE does not own — their copy stays in the page's own field, which
1402
+ * the page lane keeps binding — and why: `{ <propKey>: "RICHTEXT_HEADING" | "BUTTON_LOOK_UNMAPPED" }`.
1403
+ * The dock hides these props: an override written there renders nowhere.
1404
+ */
1405
+ kept?: Record<string, "RICHTEXT_HEADING" | "BUTTON_LOOK_UNMAPPED">;
1330
1406
  }
1331
1407
  interface ComponentBlock {
1332
1408
  type: "component";
@@ -1627,7 +1703,14 @@ declare function usesHideOn(blocks: unknown): boolean;
1627
1703
  * Returns "" for anything it does not fully trust. Twin of `safeCssUrl` in render-page.ts.
1628
1704
  */
1629
1705
  declare function safeCssUrl(raw: unknown): string;
1630
- /** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */
1706
+ /**
1707
+ * A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty.
1708
+ *
1709
+ * Surfaces (twin: `platformSectionCss` in src/lib/sites/render-page.ts): no theme and no fill set no
1710
+ * background, so the root is transparent; a `surface`/`muted` fill reads the kit's custom properties
1711
+ * (`--bcms-bg-surface`/`--bcms-bg-muted`), which a code-built page with no kit sets transparent;
1712
+ * an explicit theme Light/Dark is opaque by the author's choice; text colour inherits unless set.
1713
+ */
1631
1714
  declare function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined;
1632
1715
  /**
1633
1716
  * The content column: the declarations for the INNER box a renderer nests between a block's
@@ -3645,6 +3728,15 @@ interface DerivedLocator {
3645
3728
  groupKey: string;
3646
3729
  index: number;
3647
3730
  };
3731
+ /**
3732
+ * Each ancestor's index among ITS parent's element children, in `ancestors` order.
3733
+ *
3734
+ * The chain and the sibling index stop at one level: two price cards in one grid each hold
3735
+ * `<span>.00</span>` at `div>div>span`, index 1, and those two locators are one address. With
3736
+ * the path they are two. Minted only under the field-identity grammar (@see locatorPath), and
3737
+ * compared only where the stored side has one: a locator without it matches as it always did.
3738
+ */
3739
+ path?: number[];
3648
3740
  }
3649
3741
  /** The DOM surface `locatorFor` reads. `Element` satisfies it; so does a plain object. */
3650
3742
  interface ElementLike {
@@ -3681,6 +3773,18 @@ interface LandmarkChainElement extends ElementLike {
3681
3773
  */
3682
3774
  declare function locatorFor(el: ElementLike, region: string | null): DerivedLocator;
3683
3775
  declare function locatorFor(el: LandmarkChainElement, region: string | null, landmarks: boolean): DerivedLocator;
3776
+ /**
3777
+ * `DerivedLocator.path` for an element: its ancestors' own sibling indices, over the very chain
3778
+ * `locatorFor` walks (same stop, same order), so the two always describe one chain.
3779
+ */
3780
+ declare function locatorPath(el: ElementLike, landmarks?: false): number[];
3781
+ declare function locatorPath(el: LandmarkChainElement, landmarks: boolean): number[];
3782
+ /**
3783
+ * Where a RESOLVED locator keeps its element's `path`: a symbol, so a locator a resolver hands out
3784
+ * has no `path` of its own. Used as the stored side (a pin, a test's expectation) it compares as it
3785
+ * always did, and it serializes as it always did. `atLocator` reads it by this registry key.
3786
+ */
3787
+ declare const LOCATOR_PATH: unique symbol;
3684
3788
  /** The DOM surface `landmarkRegions` reads of each element it considers. */
3685
3789
  interface LandmarkElement {
3686
3790
  tagName: string;
@@ -3761,6 +3865,18 @@ declare function regionOf<E extends {
3761
3865
  * "Span" and "Icon".
3762
3866
  */
3763
3867
  declare const TAG_HEADS: ReadonlySet<string>;
3868
+ /**
3869
+ * The ROLES a structural key ends in (`hero-headline`, `pricing-plans[0].plan-name`): what a value
3870
+ * is FOR, never which element holds it. The same closed list as the server's `ROLE_VOCABULARY`
3871
+ * (src/lib/content/field-names.ts); this package ships alone, so the two change together.
3872
+ */
3873
+ declare const ROLE_KEYS: ReadonlySet<string>;
3874
+ /**
3875
+ * Is this WHOLE key a bare role — `headline`, `primary-button-href`, `link-2` — the key a value
3876
+ * outside any band gets? Such a key names no family. Only the whole key: `features-heading` is
3877
+ * the `features` family, and `video-h2-take-the-tour` a tag-grammar key whose family is `video`.
3878
+ */
3879
+ declare function isRoleKey(key: string): boolean;
3764
3880
  /** The top-level field key a path belongs to: `hero.title` → `hero`, `faq[0].q` → `faq`. */
3765
3881
  declare const topFieldKeyOf: (path: string) => string;
3766
3882
  /**
@@ -3813,4 +3929,4 @@ type SectionPlanItem<B> = {
3813
3929
  */
3814
3930
  declare function planSections<B>(slots: readonly string[], blocks: readonly B[] | null | undefined): SectionPlanItem<B>[];
3815
3931
 
3816
- export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BREAKPOINTS, BUTTON_ACTIONS, BUTTON_FULL_WIDTH_INVALID, 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 ButtonAction, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonLookKey, type ButtonProps, type ButtonSiteLook, type ButtonSizeName, type ButtonValue, type ButtonVariant, CODE_SLOT_PREFIX, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type ChoiceOption, type CollectionBlock, type CollectionFilter, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPreview, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentTab, 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_SIZE_ZOOM, FIELD_STYLE_KEYS, FOOTER_SECTION_ID, type FieldConfig, type FieldSize, 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, IMAGE_ASPECTS, IMAGE_FRAME_RADIUS, type ImageAspect, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, LINK_RELS, LINK_VALUE_TYPES, LIST_ITEMS_CAP, 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 LinkValue, type LinkValueType, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, type NumberFieldFormat, type NumberScale, OPTION_DESCRIPTION_MAX, type OpenMode, 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 PropTab, RESPONSIVE_CSS, type RadiusToken, type ReadButtonValue, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SIDE_SPACE_MIN_PX, SIDE_SPACE_TOKENS, SLOT_CHILD_KEYS, SLOT_ITEMS_CAP, SLOT_MAX_ITEMS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type ScaleUnit, type SectionBlock, type SectionPlanItem, type SectionProps, type SectionSpaceToken, type ShadowToken, type ShowIf, type ShowIfRule, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SlotChild, type SlotItem, type SlotShapeOptions, type SlotShapeProblem, type SlotValue, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, TABLE_COLUMN_TYPES, TABLE_JSONLD_TYPES, TABLE_LIMITS, TABLE_RESPONSIVE, TAG_HEADS, type TabItem, type TableCell, type TableCellObject, type TableCellValue, type TableCheckOptions, type TableColumn, type TableColumnType, type TableFieldOptions, type TableFootnote, type TableGroup, type TableLink, type TableProblem, type TableRef, type TableRefResolved, type TableRow, type TableValue, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, VIDEO_TRANSCRIPT_MAX, VIDEO_VALUE_KEYS, type VariantInputMapping, type VideoBlock, type VideoProps, type VideoValue, type VisibilityWindow, type WeightToken, type WindowState, type Workspace, type ZoneField, anchorTargetRel, blockStyleToColumnCss, blockStyleToCss, blockStyleToInnerCss, buttonBlockProps, buttonFullWidthProblem, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonLookValue, buttonSiteLookOf, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, derivedPairs, dockBudget, dockScreens, expandBlockBindings, fieldGroupOf, fieldStyleCssText, fieldStyleToCss, formatNumber, formatPropsAttribute, getBlockType, headingPaintCss, hiddenEverywhere, hideOnAttr, imageFrameCss, inWindow, isBlock, isButtonLookValue, isChromeLandmark, isCodeButton, isLinkObject, isScriptHref, isSlotChild, isTableValue, keyWords, landmarkRegions, linkAnchorOf, linkHref, linkRefOf, linkValueProblem, locatorFor, normalizeLinkValue, normalizeTableValue, normalizeWindow, parseNumberText, parsePropsAttribute, pickFieldStyle, placementBindOf, planSections, readButtonValue, readNumberFormat, readPath, regionOf, renderTableHtml, safeCssUrl, sideFloorApplies, sideSpaceCss, slotBindOf, slotChildValues, slotItems, slotPathString, slotShapeProblems, spaceTokenCss, splitButtonStyle, tableCellText, tablePathString, tableRefCells, tableSearchText, tableToMarkdown, tableValueProblems, topFieldKeyOf, usesHideOn, videoUrlOf, videoValueProblem, visibleBlocks, visibleDeliveredLayout, visibleLayoutStructure, windowState, withButtonLookProps };
3932
+ export { type AlignToken, type AllowRule, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, BLOCK_BINDINGS, BODY_SCHEMA_ORIGINS, BREAKPOINTS, BUTTON_ACTIONS, BUTTON_FULL_WIDTH_INVALID, 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 BodySchema, type BodySchemaOrigin, type ButtonAction, type ButtonBlock, type ButtonIcon, type ButtonLinkCandidate, type ButtonLookKey, type ButtonProps, type ButtonSiteLook, type ButtonSizeName, type ButtonValue, type ButtonVariant, CODE_SLOT_PREFIX, COMPONENT_PROP_TYPES, type CanonicalInputDefinition, type ChoiceOption, type CollectionBlock, type CollectionFilter, type CollectionProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentFormPropRef, type ComponentPreview, type ComponentPropDef, type ComponentPropType, type ComponentPropUi, type ComponentProps, type ComponentSubField, type ComponentTab, 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_SIZE_ZOOM, FIELD_STYLE_KEYS, FOOTER_SECTION_ID, type FieldConfig, type FieldSize, 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, IMAGE_ASPECTS, IMAGE_FRAME_RADIUS, type ImageAspect, type ImageBlock, type ImageProps, LANDMARK_SELECTOR, LAYOUT_SECTION_ICONS, LAYOUT_SECTION_ICON_SET, LINK_RELS, LINK_VALUE_TYPES, LIST_ITEMS_CAP, LOCATOR_PATH, 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 LinkValue, type LinkValueType, type LocatorGrammar, MAIN_SELECTOR, type ManagementLayoutCommand, type MediaAsset, type MediaCaptionTrack, type MediaFieldValue, NAVIGATION_SECTION_ID, type NavLink, type NavbarBlock, type NavbarProps, type NumberFieldFormat, type NumberScale, OPTION_DESCRIPTION_MAX, type OpenMode, 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 PropTab, RESPONSIVE_CSS, ROLE_KEYS, type RadiusToken, type ReadButtonValue, type Redirect, type ReservedLayoutSection, type ResolvedLayoutNode, type RichTextBlock, type RichTextProps, SECTION_DOCTRINE, SECTION_SPACE_TOKENS, SIDE_SPACE_MIN_PX, SIDE_SPACE_TOKENS, SLOT_CHILD_KEYS, SLOT_ITEMS_CAP, SLOT_MAX_ITEMS, SPACE_BOTTOM_TOKENS, SPACE_STEP_TOKENS, type ScaleUnit, type SectionBlock, type SectionPlanItem, type SectionProps, type SectionSpaceToken, type ShadowToken, type ShowIf, type ShowIfRule, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SlotChild, type SlotItem, type SlotShapeOptions, type SlotShapeProblem, type SlotValue, type SpaceStepToken, type SpaceToken, type SpacerBlock, type SpacerProps, TABLE_COLUMN_TYPES, TABLE_JSONLD_TYPES, TABLE_LIMITS, TABLE_RESPONSIVE, TAG_HEADS, type TabItem, type TableCell, type TableCellObject, type TableCellValue, type TableCheckOptions, type TableColumn, type TableColumnType, type TableFieldOptions, type TableFootnote, type TableGroup, type TableLink, type TableProblem, type TableRef, type TableRefResolved, type TableRow, type TableValue, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type ThemeToken, type UiBefore, type UiOrigin, VIDEO_TRANSCRIPT_MAX, VIDEO_VALUE_KEYS, type VariantInputMapping, type VideoBlock, type VideoProps, type VideoValue, type VisibilityWindow, type WeightToken, type WindowState, type Workspace, type ZoneField, allowRuleOf, anchorTargetRel, blockStyleToColumnCss, blockStyleToCss, blockStyleToInnerCss, bodySchemaOf, buttonBlockProps, buttonFullWidthProblem, buttonIconOf, buttonIconSvg, buttonLinkPairs, buttonLookValue, buttonSiteLookOf, buttonValueOfInstance, buttonValueProblem, buttonVariantOf, candidateRole, componentInstanceAddresses, componentPropTargetKey, derivedPairs, dockBudget, dockScreens, expandBlockBindings, fieldGroupOf, fieldStyleCssText, fieldStyleToCss, formatNumber, formatPropsAttribute, getBlockType, headingPaintCss, hiddenEverywhere, hideOnAttr, imageFrameCss, inWindow, isBlock, isButtonLookValue, isChromeLandmark, isCodeButton, isLinkObject, isRoleKey, isScriptHref, isSlotChild, isTableValue, keyWords, landmarkRegions, linkAnchorOf, linkHref, linkRefOf, linkValueProblem, locatorFor, locatorPath, normalizeLinkValue, normalizeTableValue, normalizeWindow, parseNumberText, parsePropsAttribute, pickFieldStyle, placementBindOf, planSections, readButtonValue, readNumberFormat, readPath, regionOf, renderTableHtml, safeCssUrl, sideFloorApplies, sideSpaceCss, slotBindOf, slotChildValues, slotItems, slotPathString, slotShapeProblems, spaceTokenCss, splitButtonStyle, tableCellText, tablePathString, tableRefCells, tableSearchText, tableToMarkdown, tableValueProblems, topFieldKeyOf, usesHideOn, videoUrlOf, videoValueProblem, visibleBlocks, visibleDeliveredLayout, visibleLayoutStructure, windowState, withButtonLookProps };
package/dist/index.js CHANGED
@@ -1,3 +1,30 @@
1
+ // src/body-schema.ts
2
+ var BODY_SCHEMA_ORIGINS = ["inferred", "confirmed", "authored"];
3
+ var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
4
+ var nonEmpty = (v) => typeof v === "string" && v.length > 0;
5
+ function allowRuleOf(value) {
6
+ if (!isRecord(value)) return null;
7
+ switch (value.kind) {
8
+ case "source":
9
+ return nonEmpty(value.pageId) ? { kind: "source", pageId: value.pageId } : null;
10
+ case "component":
11
+ return nonEmpty(value.id) ? { kind: "component", id: value.id } : null;
12
+ case "family":
13
+ return nonEmpty(value.sectionType) ? { kind: "family", sectionType: value.sectionType } : null;
14
+ case "builtins":
15
+ return { kind: "builtins" };
16
+ case "workspace":
17
+ return { kind: "workspace" };
18
+ default:
19
+ return null;
20
+ }
21
+ }
22
+ function bodySchemaOf(value) {
23
+ if (!isRecord(value) || !Array.isArray(value.allowed)) return null;
24
+ const origin = BODY_SCHEMA_ORIGINS.includes(value.origin) ? value.origin : "authored";
25
+ return { allowed: value.allowed.map(allowRuleOf).filter((r) => r !== null), origin };
26
+ }
27
+
1
28
  // src/block.ts
2
29
  var WINDOW_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
3
30
  function normalizeWindow(value) {
@@ -94,20 +121,23 @@ function readNumberFormat(raw) {
94
121
  const group = typeof o.group === "string" && GROUPS.includes(o.group) ? o.group : void 0;
95
122
  const decimal = o.decimal === "," ? "," : void 0;
96
123
  const decimals = typeof o.decimals === "number" && Number.isInteger(o.decimals) && o.decimals > 0 && o.decimals <= 6 ? o.decimals : void 0;
124
+ const grouping = o.grouping === "3;2" ? "3;2" : void 0;
97
125
  return {
98
126
  ...prefix ? { prefix } : {},
99
127
  ...suffix ? { suffix } : {},
100
128
  // A group mark that is also the decimal mark would print a number nobody can read back.
101
129
  ...group && group !== (decimal ?? ".") ? { group } : {},
102
130
  ...decimal ? { decimal } : {},
103
- ...decimals ? { decimals } : {}
131
+ ...decimals ? { decimals } : {},
132
+ ...grouping ? { grouping } : {}
104
133
  };
105
134
  }
135
+ var groupDigits = (int, mark, grouping) => grouping === "3;2" && int.length > 3 ? `${int.slice(0, -3).replace(/\B(?=(\d{2})+(?!\d))/g, mark)}${mark}${int.slice(-3)}` : int.replace(/\B(?=(\d{3})+(?!\d))/g, mark);
106
136
  function formatNumber(value, format = {}) {
107
137
  if (typeof value !== "number" || !Number.isFinite(value)) return "";
108
138
  const places = Math.max(format.decimals ?? 0, Math.min(6, fractionDigits(value)));
109
139
  const [int, frac] = Math.abs(value).toFixed(places).split(".");
110
- const grouped = format.group ? int.replace(/\B(?=(\d{3})+(?!\d))/g, format.group) : int;
140
+ const grouped = format.group ? groupDigits(int, format.group, format.grouping) : int;
111
141
  return `${value < 0 ? "-" : ""}${format.prefix ?? ""}${grouped}${frac ? `${format.decimal ?? "."}${frac}` : ""}${format.suffix ?? ""}`;
112
142
  }
113
143
  function parseNumberText(text, opts = {}) {
@@ -194,14 +224,14 @@ var BLOCK_BINDINGS = {
194
224
  ],
195
225
  tabs: [{ path: "tabs[].label", kind: "text" }]
196
226
  };
197
- var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
227
+ var isRecord2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
198
228
  function readPath(root, path) {
199
229
  let cursor = root;
200
230
  for (const segment of path.split(".")) {
201
231
  if (!segment) return void 0;
202
232
  const key = segment.replace(/\[\d+\]/g, "");
203
233
  if (key) {
204
- if (!isRecord(cursor)) return void 0;
234
+ if (!isRecord2(cursor)) return void 0;
205
235
  cursor = cursor[key];
206
236
  }
207
237
  for (const index of segment.matchAll(/\[(\d+)\]/g)) {
@@ -226,7 +256,7 @@ function expandBlockBindings(block) {
226
256
  const declared = BLOCK_BINDINGS[block.type];
227
257
  if (!declared) return [];
228
258
  const props = block.props;
229
- if (!isRecord(props)) return [];
259
+ if (!isRecord2(props)) return [];
230
260
  return declared.flatMap((binding) => expandTemplate(binding, props, binding.path)).filter((binding) => readPath(props, binding.path) !== void 0);
231
261
  }
232
262
  function formatPropsAttribute(entries) {
@@ -609,8 +639,8 @@ function slotItems(value) {
609
639
  // src/slot-child.ts
610
640
  var SLOT_CHILD_KEYS = ["_key", "_type", "_variant", "_settings"];
611
641
  var RESERVED = new Set(SLOT_CHILD_KEYS);
612
- var isRecord2 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
613
- var isSlotChild = (v) => isRecord2(v) && typeof v._type === "string" && v._type !== "";
642
+ var isRecord3 = (v) => !!v && typeof v === "object" && !Array.isArray(v);
643
+ var isSlotChild = (v) => isRecord3(v) && typeof v._type === "string" && v._type !== "";
614
644
  function slotChildValues(child) {
615
645
  const out = {};
616
646
  for (const [k, v] of Object.entries(child)) if (!RESERVED.has(k)) out[k] = v;
@@ -625,7 +655,7 @@ function slotShapeProblems(value, opts = {}) {
625
655
  if (opts.min !== void 0 && value.length < opts.min) out.push({ path: [], code: "slot_too_few", message: `slot_too_few: ${label} needs at least ${opts.min} blocks, got ${value.length}` });
626
656
  const keys = /* @__PURE__ */ new Set();
627
657
  value.forEach((child, i) => {
628
- if (!isRecord2(child)) {
658
+ if (!isRecord3(child)) {
629
659
  out.push({ path: [i], code: "slot_value_invalid", message: `slot_value_invalid: ${label}: block ${i + 1} must be an object { _key, _type, ...values }` });
630
660
  return;
631
661
  }
@@ -643,7 +673,7 @@ function slotShapeProblems(value, opts = {}) {
643
673
  }
644
674
  if (child._settings !== void 0) {
645
675
  if (!opts.settings) out.push({ path: [i, "_settings"], code: "slot_settings_undeclared", message: `slot_settings_undeclared: ${label} declares no slotSettings, so a block holds no _settings` });
646
- else if (!isRecord2(child._settings)) out.push({ path: [i, "_settings"], code: "slot_value_invalid", message: `slot_value_invalid: ${label}: _settings must be an object keyed by the slot's slotSettings` });
676
+ else if (!isRecord3(child._settings)) out.push({ path: [i, "_settings"], code: "slot_value_invalid", message: `slot_value_invalid: ${label}: _settings must be an object keyed by the slot's slotSettings` });
647
677
  }
648
678
  for (const k of Object.keys(child)) {
649
679
  if (k.startsWith("_") && !RESERVED.has(k)) {
@@ -3149,10 +3179,10 @@ function layout(fields, fieldsets, root) {
3149
3179
  const byId = new Map(fieldsets.map((s) => [s.id, s]));
3150
3180
  const tabIds = root ? fieldsets.filter((s) => s.kind === "tab").map((s) => s.id) : [];
3151
3181
  const tabOf = (s) => s?.kind === "tab" ? s.id : s?.tab !== void 0 && byId.get(s.tab)?.kind === "tab" ? s.tab : void 0;
3152
- const nonEmpty = new Set(
3182
+ const nonEmpty2 = new Set(
3153
3183
  fields.map((f) => tabOf(byId.get(f.fieldsetId ?? ""))).filter((t) => t && tabIds.includes(t))
3154
3184
  );
3155
- const strip2 = nonEmpty.size >= 2;
3185
+ const strip2 = nonEmpty2.size >= 2;
3156
3186
  const branches = /* @__PURE__ */ new Map();
3157
3187
  const nodeFor = (f, path) => {
3158
3188
  const key = `${path}${f.key}`;
@@ -3173,7 +3203,7 @@ function layout(fields, fieldsets, root) {
3173
3203
  return { kind: "leaf", key };
3174
3204
  };
3175
3205
  const pinned = [];
3176
- const panels = new Map(strip2 ? tabIds.filter((t) => nonEmpty.has(t)).map((t) => [t, []]) : []);
3206
+ const panels = new Map(strip2 ? tabIds.filter((t) => nonEmpty2.has(t)).map((t) => [t, []]) : []);
3177
3207
  const containers = /* @__PURE__ */ new Map();
3178
3208
  for (const f of fields) {
3179
3209
  const node = nodeFor(f, "");
@@ -4181,6 +4211,14 @@ function locatorFor(el, region, landmarks = false) {
4181
4211
  tag: el.tagName.toLowerCase()
4182
4212
  };
4183
4213
  }
4214
+ function locatorPath(el, landmarks = false) {
4215
+ const path = [];
4216
+ for (let parent = el.parentElement; parent && parent.tagName !== "BODY" && !isChromeLandmark(parent, landmarks); parent = parent.parentElement) {
4217
+ path.unshift(parent.parentElement ? Math.max(Array.from(parent.parentElement.children).indexOf(parent), 0) : 0);
4218
+ }
4219
+ return path;
4220
+ }
4221
+ var LOCATOR_PATH = /* @__PURE__ */ Symbol.for("bcms.locator.path");
4184
4222
  function landmarkRegions(doc, dialogs = false, landmarks = false) {
4185
4223
  const counts = /* @__PURE__ */ new Map();
4186
4224
  const out = [];
@@ -4241,9 +4279,79 @@ var TAG_HEADS = /* @__PURE__ */ new Set([
4241
4279
  "icon",
4242
4280
  "bg"
4243
4281
  ]);
4282
+ var ROLE_KEYS = /* @__PURE__ */ new Set([
4283
+ "headline",
4284
+ "heading",
4285
+ "subheading",
4286
+ "eyebrow",
4287
+ "intro",
4288
+ "paragraph",
4289
+ "text",
4290
+ "primary-button",
4291
+ "secondary-button",
4292
+ "button",
4293
+ "link",
4294
+ "home-link",
4295
+ "image",
4296
+ "icon",
4297
+ "logo",
4298
+ "background-image",
4299
+ "video-poster",
4300
+ "video",
4301
+ "embed",
4302
+ "audio",
4303
+ "body",
4304
+ "content",
4305
+ "copyright",
4306
+ "email",
4307
+ "phone",
4308
+ "price",
4309
+ "percentage",
4310
+ "number",
4311
+ "date",
4312
+ "stat-value",
4313
+ "stat-label",
4314
+ "quote",
4315
+ "attribution",
4316
+ "caption",
4317
+ "label",
4318
+ "summary",
4319
+ "address",
4320
+ "code",
4321
+ "term",
4322
+ "definition",
4323
+ "table-heading",
4324
+ "table-cell",
4325
+ "list-item",
4326
+ "title",
4327
+ "subtitle",
4328
+ "description",
4329
+ "value",
4330
+ "list",
4331
+ "plan-name",
4332
+ "cents",
4333
+ "billing-period",
4334
+ "badge",
4335
+ "features",
4336
+ "question",
4337
+ "answer",
4338
+ "author",
4339
+ "role",
4340
+ "tooltip",
4341
+ "placeholder",
4342
+ "image-description",
4343
+ "counter-target"
4344
+ ]);
4345
+ var ROLE_TAILS = /(?:-label)?(?:-[a-z])?(?:-\d+)?(?:-href)?$/;
4346
+ function isRoleKey(key) {
4347
+ if (ROLE_KEYS.has(key)) return true;
4348
+ const tail = ROLE_TAILS.exec(key);
4349
+ return !!tail && tail[0] !== "" && ROLE_KEYS.has(key.slice(0, tail.index));
4350
+ }
4244
4351
  var topFieldKeyOf = (path) => path.split(/[.[]/, 1)[0] ?? path;
4245
4352
  function fieldGroupOf(topKey, flat = false) {
4246
4353
  if (topKey.startsWith("group-")) return { groupKey: topKey, rooted: true };
4354
+ if (isRoleKey(topKey)) return { groupKey: topKey, rooted: false };
4247
4355
  const camel = flat ? /^([a-z][a-z0-9]*)[A-Z]/.exec(topKey)?.[1] : void 0;
4248
4356
  if (camel) return TAG_HEADS.has(camel) ? { groupKey: topKey, rooted: false } : { groupKey: camel, rooted: true };
4249
4357
  const head = topKey.split(/[-_]/, 1)[0] || topKey;
@@ -4297,6 +4405,7 @@ function planSections(slots, blocks) {
4297
4405
  }
4298
4406
  export {
4299
4407
  BLOCK_BINDINGS,
4408
+ BODY_SCHEMA_ORIGINS,
4300
4409
  BREAKPOINTS,
4301
4410
  BUTTON_ACTIONS,
4302
4411
  BUTTON_FULL_WIDTH_INVALID,
@@ -4323,11 +4432,13 @@ export {
4323
4432
  LINK_RELS,
4324
4433
  LINK_VALUE_TYPES,
4325
4434
  LIST_ITEMS_CAP,
4435
+ LOCATOR_PATH,
4326
4436
  MAIN_SELECTOR,
4327
4437
  NAVIGATION_SECTION_ID,
4328
4438
  OPTION_DESCRIPTION_MAX,
4329
4439
  PAGE_CONTENT_ANCHOR_ID,
4330
4440
  RESPONSIVE_CSS,
4441
+ ROLE_KEYS,
4331
4442
  SECTION_DOCTRINE,
4332
4443
  SECTION_SPACE_TOKENS,
4333
4444
  SIDE_SPACE_MIN_PX,
@@ -4344,10 +4455,12 @@ export {
4344
4455
  TAG_HEADS,
4345
4456
  VIDEO_TRANSCRIPT_MAX,
4346
4457
  VIDEO_VALUE_KEYS,
4458
+ allowRuleOf,
4347
4459
  anchorTargetRel,
4348
4460
  blockStyleToColumnCss,
4349
4461
  blockStyleToCss,
4350
4462
  blockStyleToInnerCss,
4463
+ bodySchemaOf,
4351
4464
  buttonBlockProps,
4352
4465
  buttonFullWidthProblem,
4353
4466
  buttonIconOf,
@@ -4381,6 +4494,7 @@ export {
4381
4494
  isChromeLandmark,
4382
4495
  isCodeButton,
4383
4496
  isLinkObject,
4497
+ isRoleKey,
4384
4498
  isScriptHref,
4385
4499
  isSlotChild,
4386
4500
  isTableValue,
@@ -4391,6 +4505,7 @@ export {
4391
4505
  linkRefOf,
4392
4506
  linkValueProblem,
4393
4507
  locatorFor,
4508
+ locatorPath,
4394
4509
  normalizeLinkValue,
4395
4510
  normalizeTableValue,
4396
4511
  normalizeWindow,