@bettercms-ai/types 1.5.0 → 1.7.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
@@ -40,6 +40,11 @@ type AlignToken = "left" | "center" | "right";
40
40
  type FontSizeToken = "sm" | "base" | "lg" | "xl" | "2xl";
41
41
  type WeightToken = "normal" | "medium" | "semibold" | "bold";
42
42
  type RadiusToken = "none" | "sm" | "md" | "lg" | "full";
43
+ type ThemeToken = "inherit" | "light" | "dark";
44
+ type BgToken = "none" | "surface" | "muted" | "accent" | "dark" | "custom";
45
+ type ContentWidthToken = "narrow" | "default" | "wide" | "full";
46
+ type CornerToken = "0" | "s" | "m" | "l" | "xl" | "2xl";
47
+ type ShadowToken = "0" | "s" | "m" | "l" | "xl";
43
48
  interface BlockStyle {
44
49
  paddingY?: SpaceToken;
45
50
  paddingX?: SpaceToken;
@@ -51,6 +56,24 @@ interface BlockStyle {
51
56
  fontSize?: FontSizeToken;
52
57
  weight?: WeightToken;
53
58
  radius?: RadiusToken;
59
+ theme?: ThemeToken;
60
+ bg?: BgToken;
61
+ /** Only read when `bg === "custom"`. Hex only. */
62
+ bgCustom?: string;
63
+ /** Padding sliders, in px (0–240). */
64
+ paddingTop?: number;
65
+ paddingBottom?: number;
66
+ paddingSides?: number;
67
+ contentWidth?: ContentWidthToken;
68
+ fullHeight?: boolean;
69
+ /** 0–100. */
70
+ opacity?: number;
71
+ corner?: CornerToken;
72
+ shadow?: ShadowToken;
73
+ borderTop?: boolean;
74
+ borderBottom?: boolean;
75
+ /** 🔴 The one free-form string. MUST go through `safeCssUrl()` before reaching CSS. */
76
+ bgImage?: string;
54
77
  }
55
78
  interface HeadingProps {
56
79
  text: string;
@@ -71,6 +94,67 @@ interface TextBlock {
71
94
  style?: BlockStyle;
72
95
  props: TextProps;
73
96
  }
97
+ /**
98
+ * A rich-text block: the same HTML payload as `text`, authored through a real editor.
99
+ *
100
+ * WHY A SEPARATE TYPE RATHER THAN CHANGING `text`. Every `text` block already on a live page
101
+ * holds an HTML string that the delivery renderer injects as-is. Repurposing that type would
102
+ * mean migrating published content, and getting it wrong renders visible markup to visitors.
103
+ * A new type costs nothing at rest and leaves existing pages untouched.
104
+ *
105
+ * The payload is deliberately IDENTICAL to TextProps (an HTML string) so the two are
106
+ * interchangeable at the renderer: delivery treats them the same, and the difference is
107
+ * entirely in how an author edits them — `text` is a plain field, `richtext` gets the
108
+ * formatting surface.
109
+ */
110
+ /**
111
+ * A Portable Text node — the structured form of rich text.
112
+ *
113
+ * Kept alongside `html` rather than replacing it, so nothing already published moves. The
114
+ * structure exists because an HTML string cannot carry INTENT: a colour is a hex with no
115
+ * notion of which brand token produced it, an embedded component is a div with no reference
116
+ * to resolve, and neither can be read back by tooling. Nodes can carry all of that.
117
+ */
118
+ interface PortableTextNode {
119
+ _type: string;
120
+ _key?: string;
121
+ /** Block style — "normal", "h2", "blockquote". */
122
+ style?: string;
123
+ text?: string;
124
+ children?: PortableTextNode[];
125
+ /** Marks on a span: "strong", "em", or a token reference like "color:brand-accent". */
126
+ marks?: string[];
127
+ /** An embedded component or reference resolves through these. */
128
+ schemaKey?: string;
129
+ _ref?: string;
130
+ fields?: Record<string, unknown>;
131
+ }
132
+ interface PortableTextDocument {
133
+ version: 1;
134
+ content: PortableTextNode[];
135
+ }
136
+ interface RichTextProps {
137
+ /**
138
+ * The RENDERED CACHE. Delivery reads this, so the fast path stays a string interpolation
139
+ * and every page published before `content` existed keeps rendering byte-identically.
140
+ */
141
+ html: string;
142
+ /**
143
+ * The SOURCE OF TRUTH, when present — `content` always wins over `html`.
144
+ *
145
+ * Optional on purpose: this is the same envelope the field values already use
146
+ * (`{ format, value, html }`), where `html` is likewise derived. Any writer that sets
147
+ * `html` alone on a block that HAS `content` must delete `content` in the same write, or
148
+ * the stale string silently shadows the newer structure.
149
+ */
150
+ content?: PortableTextDocument;
151
+ }
152
+ interface RichTextBlock {
153
+ type: "richtext";
154
+ id: string;
155
+ style?: BlockStyle;
156
+ props: RichTextProps;
157
+ }
74
158
  interface ImageProps {
75
159
  src: string;
76
160
  alt: string;
@@ -223,7 +307,7 @@ interface ComponentBlock {
223
307
  style?: BlockStyle;
224
308
  props: ComponentProps;
225
309
  }
226
- type ContentBlock = HeadingBlock | TextBlock | ImageBlock | ButtonBlock | SpacerBlock | ColumnsBlock | VideoBlock | FormBlock | SectionBlock | NavbarBlock | FooterBlock | SliderBlock | TabsBlock | ComponentBlock;
310
+ type ContentBlock = HeadingBlock | TextBlock | RichTextBlock | ImageBlock | ButtonBlock | SpacerBlock | ColumnsBlock | VideoBlock | FormBlock | SectionBlock | NavbarBlock | FooterBlock | SliderBlock | TabsBlock | ComponentBlock;
227
311
  /** Literal union of all block type discriminators. */
228
312
  type BlockType = ContentBlock["type"];
229
313
  /**
@@ -249,7 +333,7 @@ declare function getBlockType(value: unknown): BlockType | null;
249
333
  /**
250
334
  * FLO-264 — bounded block-style tokens → CSS. Framework-agnostic (returns a plain
251
335
  * declaration object, no React types) so every renderer shares ONE mapping: the
252
- * headless @betttercms/next adapter, @betttercms/ui, and (string form) the hosted
336
+ * headless @bettercms-ai/next adapter, @bettercms-ai/ui, and (string form) the hosted
253
337
  * render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.
254
338
  */
255
339
 
@@ -264,8 +348,12 @@ declare function blockStyleToCss(style: BlockStyle | undefined): Record<string,
264
348
  * `props` declares a flat allowlist of values an instance may override.
265
349
  */
266
350
 
267
- /** The category a component belongs to (drives library grouping + icons). */
268
- type ComponentCategory = "navbar" | "footer" | "button" | "section" | "slider" | "tabs" | "form" | "custom";
351
+ /**
352
+ * The category a component belongs to (drives library grouping + icons). The first eight
353
+ * are structural (what the component IS); the last four are the "Add a section" library
354
+ * tabs (where it appears). One varchar column, not a PG enum — widening is code-only.
355
+ */
356
+ type ComponentCategory = "navbar" | "footer" | "button" | "section" | "slider" | "tabs" | "form" | "custom" | "hero" | "content" | "social-proof" | "conversion";
269
357
  /**
270
358
  * A single overridable field on a component. `target` points at the block + JSON
271
359
  * path inside `blockJson` the override writes to (e.g. blockId "cta", path
@@ -289,6 +377,12 @@ interface Component {
289
377
  name: string;
290
378
  slug: string;
291
379
  category: ComponentCategory;
380
+ /**
381
+ * Section library: the family this component is a LAYOUT of, e.g. "Hero". `name` is the
382
+ * layout label ("Centered"), so components sharing a sectionType are selectable variants
383
+ * of one section. Null/absent = an ordinary component, not shown in the section library.
384
+ */
385
+ sectionType?: string | null;
292
386
  description?: string | null;
293
387
  blockJson: ContentBlock[];
294
388
  props: ComponentPropDef[];
@@ -302,6 +396,7 @@ interface DeliveryComponent {
302
396
  name: string;
303
397
  slug: string;
304
398
  category: ComponentCategory;
399
+ sectionType?: string | null;
305
400
  blockJson: ContentBlock[];
306
401
  props: ComponentPropDef[];
307
402
  }
@@ -338,7 +433,7 @@ interface ContentModel {
338
433
  * by the API but normalized to `array` + zones on write, so stored/delivered
339
434
  * content never contains them.
340
435
  */
341
- type ContentModelFieldType = "text" | "richtext" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "array" | "date" | "datetime";
436
+ type ContentModelFieldType = "text" | "richtext" | "image" | "boolean" | "number" | "select" | "reference" | "multi-reference" | "multiReference" | "array" | "date" | "datetime" | "longtext" | "slug" | "email" | "phone" | "link" | "color" | "json" | "file" | "component-ref";
342
437
  /**
343
438
  * Nested-content config for an `array` field. A zone holds ordinary fields, and a
344
439
  * zone field may itself be an `array` with its own zones, so nesting is recursive
@@ -369,6 +464,31 @@ interface FieldConfig {
369
464
  includeTime?: boolean;
370
465
  [key: string]: unknown;
371
466
  }
467
+ /**
468
+ * Where a field renders in the entry editor.
469
+ *
470
+ * AUTHORING ONLY — this has no delivery or storage effect. It does not change the
471
+ * shape of `data`, is not read by any renderer in @bettercms-ai/next or /astro, and
472
+ * cannot move a value onto or off a published page. It decides one thing: where the
473
+ * control sits while somebody is writing.
474
+ *
475
+ * Granularity is REGION-level, never interleaved between body blocks: the canvas is
476
+ * `[hero slots] → [free block flow] → [inline fields] → [panel fields in the drawer]`.
477
+ * A field cannot be positioned "between two paragraphs" — there is no coordinate space
478
+ * for that, and inventing one would mean mounting form controls inside the Lexical tree.
479
+ *
480
+ * - `cover` / `title` / `excerpt` / `body` — the four hero slots, rendered unlabelled
481
+ * and typographically native. SCHEMA-LEVEL ONLY: a per-entry override may never
482
+ * claim one, or one author's click renders anonymous 40px text over anonymous text
483
+ * on that entry alone.
484
+ * - `inline` — in the canvas, below the block flow, labelled.
485
+ * - `panel` — in the drawer.
486
+ *
487
+ * ABSENT is meaningful and is the default for every model that predates this: the
488
+ * editor falls back to its title-gated heuristic. Only an explicit value promotes a
489
+ * field past that gate.
490
+ */
491
+ type ContentModelFieldPlacement = "cover" | "title" | "excerpt" | "body" | "inline" | "panel";
372
492
  interface ContentModelField {
373
493
  key: string;
374
494
  label: string;
@@ -378,6 +498,11 @@ interface ContentModelField {
378
498
  options?: string[];
379
499
  /** Per-type config. For `array`: either `itemType` (primitive) or `zones` (nested). */
380
500
  config?: FieldConfig | null;
501
+ /**
502
+ * Authoring-only editor placement. See {@link ContentModelFieldPlacement}.
503
+ * Field ORDER is the array index — there is deliberately no `order` property.
504
+ */
505
+ placement?: ContentModelFieldPlacement;
381
506
  }
382
507
  /**
383
508
  * A field inside an array zone — identical to a top-level {@link ContentModelField}.
@@ -428,6 +553,26 @@ interface DeliveryEntry<T = Record<string, unknown>> {
428
553
  depth: number;
429
554
  cached?: boolean;
430
555
  preview?: boolean;
556
+ /**
557
+ * The model's field list as an authoring HINT — optional, additive, and safe to
558
+ * ignore. Present so a consumer CAN lay an entry out generically instead of
559
+ * hand-writing every field; nothing requires it, and every existing template that
560
+ * reads `entry.data.title` keeps working untouched.
561
+ *
562
+ * `order` is the field's index in the model's own array — the schema has no separate
563
+ * order property, so there is nothing here that can drift out of sync with it.
564
+ * `slot` is present only where the model explicitly placed a field, and reflects
565
+ * where it sits in the BetterCMS editor. It does not describe, and must not be read
566
+ * as, where the value belongs on your page: placement is authoring-only.
567
+ *
568
+ * Treat this as changeable. It is a hint, not part of the payload contract.
569
+ */
570
+ fields?: Array<{
571
+ key: string;
572
+ type: string;
573
+ order: number;
574
+ slot?: "cover" | "title" | "excerpt" | "body" | "inline" | "panel";
575
+ }>;
431
576
  };
432
577
  }
433
578
  /**
@@ -496,25 +641,42 @@ interface DeliveryList<T> {
496
641
 
497
642
  /**
498
643
  * Form — a CMS form that renders on a page and accepts submissions.
644
+ *
645
+ * Mirrors the authoring row in `packages/db/src/schema/forms.ts`. That file is the source
646
+ * of truth; this is the public, Drizzle-free restatement of it. The two MUST stay in step —
647
+ * a consumer that types a form off this file and writes it back through the API silently
648
+ * drops whatever this file forgot to declare.
499
649
  */
500
650
  interface Form {
501
651
  id: string;
502
652
  workspaceId: string;
653
+ /** Scopes the form to a project. Null for workspace-level forms. */
654
+ projectId: string | null;
503
655
  name: string;
504
656
  fields: FormField[];
657
+ /** Draft forms reject submissions at every ingress (403). New forms start as drafts. */
658
+ status: FormStatus;
505
659
  submitLabel?: string;
506
660
  successMessage?: string;
507
661
  redirectUrl?: string;
508
662
  createdAt: string;
509
663
  updatedAt: string;
510
664
  }
665
+ type FormStatus = "draft" | "published";
511
666
  interface FormField {
512
667
  key: string;
513
668
  label: string;
514
- type: "text" | "email" | "textarea" | "select" | "checkbox";
669
+ type: "text" | "email" | "textarea" | "select" | "checkbox" | "checkboxes" | "radio" | "number" | "phone" | "date" | "url" | "consent" | "hidden";
515
670
  placeholder?: string;
671
+ helpText?: string;
516
672
  required?: boolean;
517
673
  options?: string[];
674
+ hidden?: boolean;
675
+ defaultValue?: string;
676
+ showIf?: {
677
+ field: string;
678
+ equals: string;
679
+ };
518
680
  }
519
681
  /**
520
682
  * FormSubmission — a single form submission submitted by a visitor.
@@ -649,4 +811,4 @@ type DeepReadonly<T> = T extends Function ? T : T extends object ? {
649
811
  */
650
812
  type AssertEqual<L, R> = [L] extends [R] ? ([R] extends [L] ? true : false) : false;
651
813
 
652
- export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, type BetterCMSErrorCode, type BlockStyle, type BlockType, type ButtonBlock, type ButtonProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentPropDef, type ComponentProps, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentPageResult, type ContentResponse, type DeepReadonly, type DeliveryComponent, type DeliveryEntry, type DeliveryList, type DeliveryPage, type FieldConfig, 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, type MediaAsset, type NavLink, type NavbarBlock, type NavbarProps, type Page, type PageMetaJson, type PaginatedResult, type Perspective, type RadiusToken, type Redirect, type SectionBlock, type SectionProps, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, getBlockType, isBlock };
814
+ export { type AlignToken, type ApiError, type ApiKey, type ApiKeyPermission, type ApiKeyTokenType, type ArrayZoneConfig, type AssertEqual, type AuthResponse, type AuthSession, type AuthUser, type BetterCMSErrorCode, type BlockStyle, type BlockType, type ButtonBlock, type ButtonProps, type ColorToken, type ColumnsBlock, type ColumnsProps, type Component, type ComponentBlock, type ComponentCategory, type ComponentPropDef, type ComponentProps, type Content, type ContentBlock, type ContentEntry, type ContentModel, type ContentModelField, type ContentModelFieldType, type ContentPageResult, type ContentResponse, type DeepReadonly, type DeliveryComponent, type DeliveryEntry, type DeliveryList, type DeliveryPage, type FieldConfig, 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, type MediaAsset, type NavLink, type NavbarBlock, type NavbarProps, type Page, type PageMetaJson, type PaginatedResult, type Perspective, type PortableTextDocument, type PortableTextNode, type RadiusToken, type Redirect, type RichTextBlock, type RichTextProps, type SectionBlock, type SectionProps, type SignInInput, type SignUpInput, type SiteSeoDefaults, type SlideItem, type SliderBlock, type SliderProps, type SpaceToken, type SpacerBlock, type SpacerProps, type TabItem, type TabsBlock, type TabsProps, type TextBlock, type TextProps, type VideoBlock, type VideoProps, type WeightToken, type Workspace, type ZoneField, blockStyleToCss, getBlockType, isBlock };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/block.ts","../src/blockStyle.ts"],"sourcesContent":["/**\n * ContentBlock — a discriminated union of all CMS block types.\n * Each block has a `type` discriminator and a `props` object\n * whose shape matches the block type.\n */\n\n// ── Block style (FLO-264) ──────────────────────────────────────────────────────\n// A uniform, BOUNDED set of design tokens any block may carry (sibling to `props`).\n// Tokens map to fixed CSS values in the renderer (`styleTokensToCss`) so styling\n// reaches the live site WITHOUT arbitrary CSS. Additive + fully optional.\n\nexport type SpaceToken = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ColorToken = \"none\" | \"white\" | \"black\" | \"muted\" | \"mutedBg\" | \"primary\" | \"accent\";\nexport type AlignToken = \"left\" | \"center\" | \"right\";\nexport type FontSizeToken = \"sm\" | \"base\" | \"lg\" | \"xl\" | \"2xl\";\nexport type WeightToken = \"normal\" | \"medium\" | \"semibold\" | \"bold\";\nexport type RadiusToken = \"none\" | \"sm\" | \"md\" | \"lg\" | \"full\";\n\nexport interface BlockStyle {\n paddingY?: SpaceToken;\n paddingX?: SpaceToken;\n marginTop?: SpaceToken;\n marginBottom?: SpaceToken;\n background?: ColorToken;\n textColor?: ColorToken;\n align?: AlignToken;\n fontSize?: FontSizeToken;\n weight?: WeightToken;\n radius?: RadiusToken;\n}\n\n// ── Heading ──────────────────────────────────────────────────────────────────\n\nexport interface HeadingProps {\n text: string;\n level?: 1 | 2 | 3;\n}\n\nexport interface HeadingBlock {\n type: \"heading\";\n id: string;\n style?: BlockStyle;\n props: HeadingProps;\n}\n\n// ── Text ─────────────────────────────────────────────────────────────────────\n\nexport interface TextProps {\n html: string;\n}\n\nexport interface TextBlock {\n type: \"text\";\n id: string;\n style?: BlockStyle;\n props: TextProps;\n}\n\n// ── Image ────────────────────────────────────────────────────────────────────\n\nexport interface ImageProps {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n caption?: string;\n}\n\nexport interface ImageBlock {\n type: \"image\";\n id: string;\n style?: BlockStyle;\n props: ImageProps;\n}\n\n// ── Button ───────────────────────────────────────────────────────────────────\n\nexport interface ButtonProps {\n text: string;\n href: string;\n variant?: \"primary\" | \"secondary\";\n}\n\nexport interface ButtonBlock {\n type: \"button\";\n id: string;\n style?: BlockStyle;\n props: ButtonProps;\n}\n\n// ── Spacer ───────────────────────────────────────────────────────────────────\n\nexport interface SpacerProps {\n height: number; // in px\n}\n\nexport interface SpacerBlock {\n type: \"spacer\";\n id: string;\n style?: BlockStyle;\n props: SpacerProps;\n}\n\n// ── Columns ───────────────────────────────────────────────────────────────────\n\nexport interface ColumnsProps {\n columns: ContentBlock[][]; // array of column slots, each slot is an array of blocks\n gap?: number; // in px\n}\n\nexport interface ColumnsBlock {\n type: \"columns\";\n id: string;\n style?: BlockStyle;\n props: ColumnsProps;\n}\n\n// ── Video ────────────────────────────────────────────────────────────────────\n\nexport interface VideoProps {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n}\n\nexport interface VideoBlock {\n type: \"video\";\n id: string;\n style?: BlockStyle;\n props: VideoProps;\n}\n\n// ── Form ─────────────────────────────────────────────────────────────────────\n\nexport interface FormProps {\n formId: string; // references forms.id (a nanoid). Resolved against delivered forms at render time.\n}\n\nexport interface FormBlock {\n type: \"form\";\n id: string;\n style?: BlockStyle;\n props: FormProps;\n}\n\n// ── Section (recursive container) ──────────────────────────────────────────────\n\nexport interface SectionProps {\n children: ContentBlock[];\n background?: string;\n paddingY?: number; // in px\n maxWidth?: number; // in px\n}\n\nexport interface SectionBlock {\n type: \"section\";\n id: string;\n style?: BlockStyle;\n props: SectionProps;\n}\n\n// ── Navbar ─────────────────────────────────────────────────────────────────────\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavbarProps {\n logo?: { src: string; alt: string; href?: string };\n links: NavLink[];\n cta?: { text: string; href: string };\n}\n\nexport interface NavbarBlock {\n type: \"navbar\";\n id: string;\n style?: BlockStyle;\n props: NavbarProps;\n}\n\n// ── Footer ─────────────────────────────────────────────────────────────────────\n\nexport interface FooterColumn {\n heading?: string;\n links: NavLink[];\n}\n\nexport interface FooterProps {\n columns: FooterColumn[];\n copyright?: string;\n}\n\nexport interface FooterBlock {\n type: \"footer\";\n id: string;\n style?: BlockStyle;\n props: FooterProps;\n}\n\n// ── Slider / Carousel (recursive container, client-hydrated) ────────────────────\n\nexport interface SlideItem {\n id: string;\n children: ContentBlock[];\n}\n\nexport interface SliderProps {\n slides: SlideItem[];\n autoplay?: boolean;\n interval?: number; // in ms\n loop?: boolean;\n}\n\nexport interface SliderBlock {\n type: \"slider\";\n id: string;\n style?: BlockStyle;\n props: SliderProps;\n}\n\n// ── Tabs (recursive container, client-hydrated) ─────────────────────────────────\n\nexport interface TabItem {\n id: string;\n label: string;\n children: ContentBlock[];\n}\n\nexport interface TabsProps {\n tabs: TabItem[];\n}\n\nexport interface TabsBlock {\n type: \"tabs\";\n id: string;\n style?: BlockStyle;\n props: TabsProps;\n}\n\n// ── Component instance (Webflow-style reusable symbol) ──────────────────────────\n// References a reusable component by id. `overrides` maps a component prop key\n// (declared in the component's `props[]` allowlist) to a value, applied to the\n// component's block tree at render time. Resolved against delivered components.\n\nexport interface ComponentProps {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\nexport interface ComponentBlock {\n type: \"component\";\n id: string;\n style?: BlockStyle;\n props: ComponentProps;\n}\n\n// ── Union ─────────────────────────────────────────────────────────────────────\n\nexport type ContentBlock =\n | HeadingBlock\n | TextBlock\n | ImageBlock\n | ButtonBlock\n | SpacerBlock\n | ColumnsBlock\n | VideoBlock\n | FormBlock\n | SectionBlock\n | NavbarBlock\n | FooterBlock\n | SliderBlock\n | TabsBlock\n | ComponentBlock;\n\n/** Literal union of all block type discriminators. */\nexport type BlockType = ContentBlock[\"type\"];\n\n/**\n * Type guard — narrows an unknown block to `ContentBlock`.\n *\n * @example\n * const block = maybeBlock as unknown;\n * if (isBlock(block)) {\n * // block is ContentBlock here\n * }\n */\nexport function isBlock(value: unknown): value is ContentBlock {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n );\n}\n\n/**\n * Extract the `type` discriminator from a block, or `null` if not a block.\n *\n * @example\n * const block = { type: \"heading\", id: \"1\", props: { text: \"Hi\" } };\n * getBlockType(block); // \"heading\"\n * getBlockType({ not: \"a block\" }); // null\n */\nexport function getBlockType(value: unknown): BlockType | null {\n if (isBlock(value)) return value.type;\n return null;\n}\n","/**\n * FLO-264 — bounded block-style tokens → CSS. Framework-agnostic (returns a plain\n * declaration object, no React types) so every renderer shares ONE mapping: the\n * headless @betttercms/next adapter, @betttercms/ui, and (string form) the hosted\n * render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.\n */\nimport type { BlockStyle } from \"./block.js\";\n\nconst SPACE_PX: Record<string, string> = { none: \"0\", xs: \"4px\", sm: \"8px\", md: \"16px\", lg: \"32px\", xl: \"64px\" };\nconst FONT_SIZE_REM: Record<string, string> = { sm: \"0.875rem\", base: \"1rem\", lg: \"1.25rem\", xl: \"1.5rem\", \"2xl\": \"2rem\" };\nconst WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };\nconst RADIUS_PX: Record<string, string> = { none: \"0\", sm: \"4px\", md: \"8px\", lg: \"16px\", full: \"9999px\" };\nconst COLOR_HEX: Record<string, string> = { white: \"#ffffff\", black: \"#111111\", muted: \"#6b7280\", mutedBg: \"#f3f4f6\", primary: \"#111111\", accent: \"#4f46e5\" };\n\n/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */\nexport function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: Record<string, string | number> = {};\n if (s.paddingY && SPACE_PX[s.paddingY] != null) { css.paddingTop = SPACE_PX[s.paddingY]!; css.paddingBottom = SPACE_PX[s.paddingY]!; }\n if (s.paddingX && SPACE_PX[s.paddingX] != null) { css.paddingLeft = SPACE_PX[s.paddingX]!; css.paddingRight = SPACE_PX[s.paddingX]!; }\n if (s.marginTop && SPACE_PX[s.marginTop] != null) css.marginTop = SPACE_PX[s.marginTop]!;\n if (s.marginBottom && SPACE_PX[s.marginBottom] != null) css.marginBottom = SPACE_PX[s.marginBottom]!;\n if (s.background && COLOR_HEX[s.background]) css.background = COLOR_HEX[s.background]!;\n if (s.textColor && COLOR_HEX[s.textColor]) css.color = COLOR_HEX[s.textColor]!;\n if (s.align === \"left\" || s.align === \"center\" || s.align === \"right\") css.textAlign = s.align;\n if (s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n if (s.radius && RADIUS_PX[s.radius] != null) css.borderRadius = RADIUS_PX[s.radius]!;\n return Object.keys(css).length ? css : undefined;\n}\n"],"mappings":";AAgSO,SAAS,QAAQ,OAAuC;AAC7D,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAAkC,MAAM,MAAM;AAE1D;AAUO,SAAS,aAAa,OAAkC;AAC7D,MAAI,QAAQ,KAAK,EAAG,QAAO,MAAM;AACjC,SAAO;AACT;;;AC5SA,IAAM,WAAmC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI,OAAO;AAC/G,IAAM,gBAAwC,EAAE,IAAI,YAAY,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,OAAO,OAAO;AACzH,IAAM,SAAiC,EAAE,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,IAAI;AAC5F,IAAM,YAAoC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,SAAS;AACxG,IAAM,YAAoC,EAAE,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW,SAAS,WAAW,SAAS,WAAW,QAAQ,UAAU;AAGrJ,SAAS,gBAAgB,OAA4E;AAC1G,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,QAAM,MAAuC,CAAC;AAC9C,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,aAAa,SAAS,EAAE,QAAQ;AAAI,QAAI,gBAAgB,SAAS,EAAE,QAAQ;AAAA,EAAI;AACrI,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,cAAc,SAAS,EAAE,QAAQ;AAAI,QAAI,eAAe,SAAS,EAAE,QAAQ;AAAA,EAAI;AACrI,MAAI,EAAE,aAAa,SAAS,EAAE,SAAS,KAAK,KAAM,KAAI,YAAY,SAAS,EAAE,SAAS;AACtF,MAAI,EAAE,gBAAgB,SAAS,EAAE,YAAY,KAAK,KAAM,KAAI,eAAe,SAAS,EAAE,YAAY;AAClG,MAAI,EAAE,cAAc,UAAU,EAAE,UAAU,EAAG,KAAI,aAAa,UAAU,EAAE,UAAU;AACpF,MAAI,EAAE,aAAa,UAAU,EAAE,SAAS,EAAG,KAAI,QAAQ,UAAU,EAAE,SAAS;AAC5E,MAAI,EAAE,UAAU,UAAU,EAAE,UAAU,YAAY,EAAE,UAAU,QAAS,KAAI,YAAY,EAAE;AACzF,MAAI,EAAE,YAAY,cAAc,EAAE,QAAQ,EAAG,KAAI,WAAW,cAAc,EAAE,QAAQ;AACpF,MAAI,EAAE,UAAU,OAAO,EAAE,MAAM,KAAK,KAAM,KAAI,aAAa,OAAO,EAAE,MAAM;AAC1E,MAAI,EAAE,UAAU,UAAU,EAAE,MAAM,KAAK,KAAM,KAAI,eAAe,UAAU,EAAE,MAAM;AAClF,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,MAAM;AACzC;","names":[]}
1
+ {"version":3,"sources":["../src/block.ts","../src/blockStyle.ts"],"sourcesContent":["/**\n * ContentBlock — a discriminated union of all CMS block types.\n * Each block has a `type` discriminator and a `props` object\n * whose shape matches the block type.\n */\n\n// ── Block style (FLO-264) ──────────────────────────────────────────────────────\n// A uniform, BOUNDED set of design tokens any block may carry (sibling to `props`).\n// Tokens map to fixed CSS values in the renderer (`styleTokensToCss`) so styling\n// reaches the live site WITHOUT arbitrary CSS. Additive + fully optional.\n\nexport type SpaceToken = \"none\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type ColorToken = \"none\" | \"white\" | \"black\" | \"muted\" | \"mutedBg\" | \"primary\" | \"accent\";\nexport type AlignToken = \"left\" | \"center\" | \"right\";\nexport type FontSizeToken = \"sm\" | \"base\" | \"lg\" | \"xl\" | \"2xl\";\nexport type WeightToken = \"normal\" | \"medium\" | \"semibold\" | \"bold\";\nexport type RadiusToken = \"none\" | \"sm\" | \"md\" | \"lg\" | \"full\";\n\n// Section design (task 4) — the per-instance design a section carries on the page.\nexport type ThemeToken = \"inherit\" | \"light\" | \"dark\";\nexport type BgToken = \"none\" | \"surface\" | \"muted\" | \"accent\" | \"dark\" | \"custom\";\nexport type ContentWidthToken = \"narrow\" | \"default\" | \"wide\" | \"full\";\nexport type CornerToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\" | \"2xl\";\nexport type ShadowToken = \"0\" | \"s\" | \"m\" | \"l\" | \"xl\";\n\nexport interface BlockStyle {\n // Legacy token set (FLO-264). Where these overlap the section fields below\n // (background, radius, padding), the section field WINS in the renderer.\n paddingY?: SpaceToken;\n paddingX?: SpaceToken;\n marginTop?: SpaceToken;\n marginBottom?: SpaceToken;\n background?: ColorToken;\n textColor?: ColorToken;\n align?: AlignToken;\n fontSize?: FontSizeToken;\n weight?: WeightToken;\n radius?: RadiusToken;\n\n // Section design (task 4).\n theme?: ThemeToken;\n bg?: BgToken;\n /** Only read when `bg === \"custom\"`. Hex only. */\n bgCustom?: string;\n /** Padding sliders, in px (0–240). */\n paddingTop?: number;\n paddingBottom?: number;\n paddingSides?: number;\n contentWidth?: ContentWidthToken;\n fullHeight?: boolean;\n /** 0–100. */\n opacity?: number;\n corner?: CornerToken;\n shadow?: ShadowToken;\n borderTop?: boolean;\n borderBottom?: boolean;\n /** 🔴 The one free-form string. MUST go through `safeCssUrl()` before reaching CSS. */\n bgImage?: string;\n}\n\n// ── Heading ──────────────────────────────────────────────────────────────────\n\nexport interface HeadingProps {\n text: string;\n level?: 1 | 2 | 3;\n}\n\nexport interface HeadingBlock {\n type: \"heading\";\n id: string;\n style?: BlockStyle;\n props: HeadingProps;\n}\n\n// ── Text ─────────────────────────────────────────────────────────────────────\n\nexport interface TextProps {\n html: string;\n}\n\nexport interface TextBlock {\n type: \"text\";\n id: string;\n style?: BlockStyle;\n props: TextProps;\n}\n\n/**\n * A rich-text block: the same HTML payload as `text`, authored through a real editor.\n *\n * WHY A SEPARATE TYPE RATHER THAN CHANGING `text`. Every `text` block already on a live page\n * holds an HTML string that the delivery renderer injects as-is. Repurposing that type would\n * mean migrating published content, and getting it wrong renders visible markup to visitors.\n * A new type costs nothing at rest and leaves existing pages untouched.\n *\n * The payload is deliberately IDENTICAL to TextProps (an HTML string) so the two are\n * interchangeable at the renderer: delivery treats them the same, and the difference is\n * entirely in how an author edits them — `text` is a plain field, `richtext` gets the\n * formatting surface.\n */\n/**\n * A Portable Text node — the structured form of rich text.\n *\n * Kept alongside `html` rather than replacing it, so nothing already published moves. The\n * structure exists because an HTML string cannot carry INTENT: a colour is a hex with no\n * notion of which brand token produced it, an embedded component is a div with no reference\n * to resolve, and neither can be read back by tooling. Nodes can carry all of that.\n */\nexport interface PortableTextNode {\n _type: string;\n _key?: string;\n /** Block style — \"normal\", \"h2\", \"blockquote\". */\n style?: string;\n text?: string;\n children?: PortableTextNode[];\n /** Marks on a span: \"strong\", \"em\", or a token reference like \"color:brand-accent\". */\n marks?: string[];\n /** An embedded component or reference resolves through these. */\n schemaKey?: string;\n _ref?: string;\n fields?: Record<string, unknown>;\n}\n\nexport interface PortableTextDocument {\n version: 1;\n content: PortableTextNode[];\n}\n\nexport interface RichTextProps {\n /**\n * The RENDERED CACHE. Delivery reads this, so the fast path stays a string interpolation\n * and every page published before `content` existed keeps rendering byte-identically.\n */\n html: string;\n /**\n * The SOURCE OF TRUTH, when present — `content` always wins over `html`.\n *\n * Optional on purpose: this is the same envelope the field values already use\n * (`{ format, value, html }`), where `html` is likewise derived. Any writer that sets\n * `html` alone on a block that HAS `content` must delete `content` in the same write, or\n * the stale string silently shadows the newer structure.\n */\n content?: PortableTextDocument;\n}\n\nexport interface RichTextBlock {\n type: \"richtext\";\n id: string;\n style?: BlockStyle;\n props: RichTextProps;\n}\n\n// ── Image ────────────────────────────────────────────────────────────────────\n\nexport interface ImageProps {\n src: string;\n alt: string;\n width?: number;\n height?: number;\n caption?: string;\n}\n\nexport interface ImageBlock {\n type: \"image\";\n id: string;\n style?: BlockStyle;\n props: ImageProps;\n}\n\n// ── Button ───────────────────────────────────────────────────────────────────\n\nexport interface ButtonProps {\n text: string;\n href: string;\n variant?: \"primary\" | \"secondary\";\n}\n\nexport interface ButtonBlock {\n type: \"button\";\n id: string;\n style?: BlockStyle;\n props: ButtonProps;\n}\n\n// ── Spacer ───────────────────────────────────────────────────────────────────\n\nexport interface SpacerProps {\n height: number; // in px\n}\n\nexport interface SpacerBlock {\n type: \"spacer\";\n id: string;\n style?: BlockStyle;\n props: SpacerProps;\n}\n\n// ── Columns ───────────────────────────────────────────────────────────────────\n\nexport interface ColumnsProps {\n columns: ContentBlock[][]; // array of column slots, each slot is an array of blocks\n gap?: number; // in px\n}\n\nexport interface ColumnsBlock {\n type: \"columns\";\n id: string;\n style?: BlockStyle;\n props: ColumnsProps;\n}\n\n// ── Video ────────────────────────────────────────────────────────────────────\n\nexport interface VideoProps {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n}\n\nexport interface VideoBlock {\n type: \"video\";\n id: string;\n style?: BlockStyle;\n props: VideoProps;\n}\n\n// ── Form ─────────────────────────────────────────────────────────────────────\n\nexport interface FormProps {\n formId: string; // references forms.id (a nanoid). Resolved against delivered forms at render time.\n}\n\nexport interface FormBlock {\n type: \"form\";\n id: string;\n style?: BlockStyle;\n props: FormProps;\n}\n\n// ── Section (recursive container) ──────────────────────────────────────────────\n\nexport interface SectionProps {\n children: ContentBlock[];\n background?: string;\n paddingY?: number; // in px\n maxWidth?: number; // in px\n}\n\nexport interface SectionBlock {\n type: \"section\";\n id: string;\n style?: BlockStyle;\n props: SectionProps;\n}\n\n// ── Navbar ─────────────────────────────────────────────────────────────────────\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavbarProps {\n logo?: { src: string; alt: string; href?: string };\n links: NavLink[];\n cta?: { text: string; href: string };\n}\n\nexport interface NavbarBlock {\n type: \"navbar\";\n id: string;\n style?: BlockStyle;\n props: NavbarProps;\n}\n\n// ── Footer ─────────────────────────────────────────────────────────────────────\n\nexport interface FooterColumn {\n heading?: string;\n links: NavLink[];\n}\n\nexport interface FooterProps {\n columns: FooterColumn[];\n copyright?: string;\n}\n\nexport interface FooterBlock {\n type: \"footer\";\n id: string;\n style?: BlockStyle;\n props: FooterProps;\n}\n\n// ── Slider / Carousel (recursive container, client-hydrated) ────────────────────\n\nexport interface SlideItem {\n id: string;\n children: ContentBlock[];\n}\n\nexport interface SliderProps {\n slides: SlideItem[];\n autoplay?: boolean;\n interval?: number; // in ms\n loop?: boolean;\n}\n\nexport interface SliderBlock {\n type: \"slider\";\n id: string;\n style?: BlockStyle;\n props: SliderProps;\n}\n\n// ── Tabs (recursive container, client-hydrated) ─────────────────────────────────\n\nexport interface TabItem {\n id: string;\n label: string;\n children: ContentBlock[];\n}\n\nexport interface TabsProps {\n tabs: TabItem[];\n}\n\nexport interface TabsBlock {\n type: \"tabs\";\n id: string;\n style?: BlockStyle;\n props: TabsProps;\n}\n\n// ── Component instance (Webflow-style reusable symbol) ──────────────────────────\n// References a reusable component by id. `overrides` maps a component prop key\n// (declared in the component's `props[]` allowlist) to a value, applied to the\n// component's block tree at render time. Resolved against delivered components.\n\nexport interface ComponentProps {\n componentId: string;\n overrides?: Record<string, unknown>;\n}\n\nexport interface ComponentBlock {\n type: \"component\";\n id: string;\n style?: BlockStyle;\n props: ComponentProps;\n}\n\n// ── Union ─────────────────────────────────────────────────────────────────────\n\nexport type ContentBlock =\n | HeadingBlock\n | TextBlock\n | RichTextBlock\n | ImageBlock\n | ButtonBlock\n | SpacerBlock\n | ColumnsBlock\n | VideoBlock\n | FormBlock\n | SectionBlock\n | NavbarBlock\n | FooterBlock\n | SliderBlock\n | TabsBlock\n | ComponentBlock;\n\n/** Literal union of all block type discriminators. */\nexport type BlockType = ContentBlock[\"type\"];\n\n/**\n * Type guard — narrows an unknown block to `ContentBlock`.\n *\n * @example\n * const block = maybeBlock as unknown;\n * if (isBlock(block)) {\n * // block is ContentBlock here\n * }\n */\nexport function isBlock(value: unknown): value is ContentBlock {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n typeof (value as Record<string, unknown>)[\"type\"] === \"string\"\n );\n}\n\n/**\n * Extract the `type` discriminator from a block, or `null` if not a block.\n *\n * @example\n * const block = { type: \"heading\", id: \"1\", props: { text: \"Hi\" } };\n * getBlockType(block); // \"heading\"\n * getBlockType({ not: \"a block\" }); // null\n */\nexport function getBlockType(value: unknown): BlockType | null {\n if (isBlock(value)) return value.type;\n return null;\n}\n","/**\n * FLO-264 — bounded block-style tokens → CSS. Framework-agnostic (returns a plain\n * declaration object, no React types) so every renderer shares ONE mapping: the\n * headless @bettercms-ai/next adapter, @bettercms-ai/ui, and (string form) the hosted\n * render-page.ts. Unknown tokens are dropped — closed set, no arbitrary CSS.\n */\nimport type { BlockStyle } from \"./block.js\";\n\nconst SPACE_PX: Record<string, string> = { none: \"0\", xs: \"4px\", sm: \"8px\", md: \"16px\", lg: \"32px\", xl: \"64px\" };\nconst FONT_SIZE_REM: Record<string, string> = { sm: \"0.875rem\", base: \"1rem\", lg: \"1.25rem\", xl: \"1.5rem\", \"2xl\": \"2rem\" };\nconst WEIGHT: Record<string, number> = { normal: 400, medium: 500, semibold: 600, bold: 700 };\nconst RADIUS_PX: Record<string, string> = { none: \"0\", sm: \"4px\", md: \"8px\", lg: \"16px\", full: \"9999px\" };\nconst COLOR_HEX: Record<string, string> = { white: \"#ffffff\", black: \"#111111\", muted: \"#6b7280\", mutedBg: \"#f3f4f6\", primary: \"#111111\", accent: \"#4f46e5\" };\n\n/** A CSS declaration object (key → value) usable as a React `style` prop, or undefined when empty. */\nexport function blockStyleToCss(style: BlockStyle | undefined): Record<string, string | number> | undefined {\n if (!style || typeof style !== \"object\") return undefined;\n const s = style as Record<string, string>;\n const css: Record<string, string | number> = {};\n if (s.paddingY && SPACE_PX[s.paddingY] != null) { css.paddingTop = SPACE_PX[s.paddingY]!; css.paddingBottom = SPACE_PX[s.paddingY]!; }\n if (s.paddingX && SPACE_PX[s.paddingX] != null) { css.paddingLeft = SPACE_PX[s.paddingX]!; css.paddingRight = SPACE_PX[s.paddingX]!; }\n if (s.marginTop && SPACE_PX[s.marginTop] != null) css.marginTop = SPACE_PX[s.marginTop]!;\n if (s.marginBottom && SPACE_PX[s.marginBottom] != null) css.marginBottom = SPACE_PX[s.marginBottom]!;\n if (s.background && COLOR_HEX[s.background]) css.background = COLOR_HEX[s.background]!;\n if (s.textColor && COLOR_HEX[s.textColor]) css.color = COLOR_HEX[s.textColor]!;\n if (s.align === \"left\" || s.align === \"center\" || s.align === \"right\") css.textAlign = s.align;\n if (s.fontSize && FONT_SIZE_REM[s.fontSize]) css.fontSize = FONT_SIZE_REM[s.fontSize]!;\n if (s.weight && WEIGHT[s.weight] != null) css.fontWeight = WEIGHT[s.weight]!;\n if (s.radius && RADIUS_PX[s.radius] != null) css.borderRadius = RADIUS_PX[s.radius]!;\n return Object.keys(css).length ? css : undefined;\n}\n"],"mappings":";AA+XO,SAAS,QAAQ,OAAuC;AAC7D,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAQ,MAAkC,MAAM,MAAM;AAE1D;AAUO,SAAS,aAAa,OAAkC;AAC7D,MAAI,QAAQ,KAAK,EAAG,QAAO,MAAM;AACjC,SAAO;AACT;;;AC3YA,IAAM,WAAmC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI,OAAO;AAC/G,IAAM,gBAAwC,EAAE,IAAI,YAAY,MAAM,QAAQ,IAAI,WAAW,IAAI,UAAU,OAAO,OAAO;AACzH,IAAM,SAAiC,EAAE,QAAQ,KAAK,QAAQ,KAAK,UAAU,KAAK,MAAM,IAAI;AAC5F,IAAM,YAAoC,EAAE,MAAM,KAAK,IAAI,OAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,SAAS;AACxG,IAAM,YAAoC,EAAE,OAAO,WAAW,OAAO,WAAW,OAAO,WAAW,SAAS,WAAW,SAAS,WAAW,QAAQ,UAAU;AAGrJ,SAAS,gBAAgB,OAA4E;AAC1G,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,IAAI;AACV,QAAM,MAAuC,CAAC;AAC9C,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,aAAa,SAAS,EAAE,QAAQ;AAAI,QAAI,gBAAgB,SAAS,EAAE,QAAQ;AAAA,EAAI;AACrI,MAAI,EAAE,YAAY,SAAS,EAAE,QAAQ,KAAK,MAAM;AAAE,QAAI,cAAc,SAAS,EAAE,QAAQ;AAAI,QAAI,eAAe,SAAS,EAAE,QAAQ;AAAA,EAAI;AACrI,MAAI,EAAE,aAAa,SAAS,EAAE,SAAS,KAAK,KAAM,KAAI,YAAY,SAAS,EAAE,SAAS;AACtF,MAAI,EAAE,gBAAgB,SAAS,EAAE,YAAY,KAAK,KAAM,KAAI,eAAe,SAAS,EAAE,YAAY;AAClG,MAAI,EAAE,cAAc,UAAU,EAAE,UAAU,EAAG,KAAI,aAAa,UAAU,EAAE,UAAU;AACpF,MAAI,EAAE,aAAa,UAAU,EAAE,SAAS,EAAG,KAAI,QAAQ,UAAU,EAAE,SAAS;AAC5E,MAAI,EAAE,UAAU,UAAU,EAAE,UAAU,YAAY,EAAE,UAAU,QAAS,KAAI,YAAY,EAAE;AACzF,MAAI,EAAE,YAAY,cAAc,EAAE,QAAQ,EAAG,KAAI,WAAW,cAAc,EAAE,QAAQ;AACpF,MAAI,EAAE,UAAU,OAAO,EAAE,MAAM,KAAK,KAAM,KAAI,aAAa,OAAO,EAAE,MAAM;AAC1E,MAAI,EAAE,UAAU,UAAU,EAAE,MAAM,KAAK,KAAM,KAAI,eAAe,UAAU,EAAE,MAAM;AAClF,SAAO,OAAO,KAAK,GAAG,EAAE,SAAS,MAAM;AACzC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/types",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",