@bettercms-ai/kit 2.0.0-next.0 → 2.0.0-next.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.
Files changed (90) hide show
  1. package/dist/adapters/lossy.d.ts +9 -1
  2. package/dist/adapters/lossy.js +16 -5
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/prod-types.d.ts +9 -22
  5. package/dist/adapters/prod-types.js +36 -35
  6. package/dist/adapters/prod-types.js.map +1 -1
  7. package/dist/adapters/schema.js +84 -39
  8. package/dist/adapters/schema.js.map +1 -1
  9. package/dist/context.d.ts +39 -0
  10. package/dist/context.js +40 -1
  11. package/dist/context.js.map +1 -1
  12. package/dist/controls/link.js +112 -196
  13. package/dist/controls/link.js.map +1 -1
  14. package/dist/controls/location.js +3 -8
  15. package/dist/controls/location.js.map +1 -1
  16. package/dist/controls/media.d.ts +0 -14
  17. package/dist/controls/media.js +52 -95
  18. package/dist/controls/media.js.map +1 -1
  19. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  20. package/dist/controls/rich-text/article-shell.js +510 -0
  21. package/dist/controls/rich-text/article-shell.js.map +1 -0
  22. package/dist/controls/rich-text/author.d.ts +25 -0
  23. package/dist/controls/rich-text/author.js +104 -0
  24. package/dist/controls/rich-text/author.js.map +1 -0
  25. package/dist/controls/rich-text/blocks.d.ts +19 -2
  26. package/dist/controls/rich-text/blocks.js +273 -638
  27. package/dist/controls/rich-text/blocks.js.map +1 -1
  28. package/dist/controls/rich-text/button.d.ts +23 -0
  29. package/dist/controls/rich-text/button.js +85 -0
  30. package/dist/controls/rich-text/button.js.map +1 -0
  31. package/dist/controls/rich-text/catalog.d.ts +2 -5
  32. package/dist/controls/rich-text/catalog.js +120 -6
  33. package/dist/controls/rich-text/catalog.js.map +1 -1
  34. package/dist/controls/rich-text/checklist.d.ts +24 -0
  35. package/dist/controls/rich-text/checklist.js +115 -0
  36. package/dist/controls/rich-text/checklist.js.map +1 -0
  37. package/dist/controls/rich-text/codec.d.ts +10 -1
  38. package/dist/controls/rich-text/codec.js +11 -1
  39. package/dist/controls/rich-text/codec.js.map +1 -1
  40. package/dist/controls/rich-text/columns.d.ts +41 -0
  41. package/dist/controls/rich-text/columns.js +181 -0
  42. package/dist/controls/rich-text/columns.js.map +1 -0
  43. package/dist/controls/rich-text/control.js +1 -0
  44. package/dist/controls/rich-text/control.js.map +1 -1
  45. package/dist/controls/rich-text/dom.d.ts +84 -4
  46. package/dist/controls/rich-text/dom.js +171 -10
  47. package/dist/controls/rich-text/dom.js.map +1 -1
  48. package/dist/controls/rich-text/editor.d.ts +4 -2
  49. package/dist/controls/rich-text/editor.js +184 -12
  50. package/dist/controls/rich-text/editor.js.map +1 -1
  51. package/dist/controls/rich-text/embed.d.ts +28 -0
  52. package/dist/controls/rich-text/embed.js +210 -0
  53. package/dist/controls/rich-text/embed.js.map +1 -0
  54. package/dist/controls/rich-text/footnote.d.ts +41 -0
  55. package/dist/controls/rich-text/footnote.js +185 -0
  56. package/dist/controls/rich-text/footnote.js.map +1 -0
  57. package/dist/controls/rich-text/gallery.d.ts +28 -0
  58. package/dist/controls/rich-text/gallery.js +167 -0
  59. package/dist/controls/rich-text/gallery.js.map +1 -0
  60. package/dist/controls/rich-text/link-form.d.ts +3 -1
  61. package/dist/controls/rich-text/link-form.js +2 -2
  62. package/dist/controls/rich-text/link-form.js.map +1 -1
  63. package/dist/controls/rich-text/ops.js +6 -0
  64. package/dist/controls/rich-text/ops.js.map +1 -1
  65. package/dist/controls/rich-text/related.d.ts +36 -0
  66. package/dist/controls/rich-text/related.js +213 -0
  67. package/dist/controls/rich-text/related.js.map +1 -0
  68. package/dist/controls/rich-text/toc.d.ts +47 -0
  69. package/dist/controls/rich-text/toc.js +160 -0
  70. package/dist/controls/rich-text/toc.js.map +1 -0
  71. package/dist/core/core.d.ts +11 -3
  72. package/dist/core/core.js +24 -6
  73. package/dist/core/core.js.map +1 -1
  74. package/dist/core/facets.d.ts +16 -0
  75. package/dist/core/facets.js +17 -1
  76. package/dist/core/facets.js.map +1 -1
  77. package/dist/core/index.js +2 -2
  78. package/dist/index.js +4 -4
  79. package/dist/library/kit-catalog.json +47 -44
  80. package/dist/schema/types.d.ts +15 -0
  81. package/dist/schema/types.js.map +1 -1
  82. package/dist/styles.css +1 -1
  83. package/dist/ui/autocomplete.d.ts +29 -1
  84. package/dist/ui/autocomplete.js +102 -47
  85. package/dist/ui/autocomplete.js.map +1 -1
  86. package/dist/ui/button.js +3 -5
  87. package/dist/ui/button.js.map +1 -1
  88. package/dist/ui/index.js +2 -2
  89. package/dist/ui/toast.js +1 -1
  90. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"prod-types.js","names":[],"sources":["../../src/adapters/prod-types.ts"],"sourcesContent":["/**\n * PROD SHAPES — the production schema language and stored values, typed locally so the kit stays a package that could\n * leave the repo (it may not import @bettercms-ai/types, and the dashboard's pin predates F1 / F1.x-props anyway).\n *\n * Mirrors the backend at F1 + F1.x-props + link objects + tags / rating / code (72ea2b68d), then reference props\n * (73a120c50), validation parity (dd021ceba), option meta (ab15fe893), V2 chrome keys and types (98e48b9e3, 324580b2e),\n * the V2 icon vocabulary (e126bf33d) and the localized flag (279a10490) — origin/dev 81f385ff3:\n * packages/types/src/content-model.ts, component.ts, link-value.ts, button-look.ts, dock-icon-names.ts, video-value.ts\n * src/lib/validation/schemas/content.ts (baseField, fieldUiSchema, chromeUiProblems, fieldsets, MAX_FIELD_DEPTH)\n * src/lib/validation/schemas/components.ts (componentPropDefSchema, subFieldSchema, propUiSchema, propValidationHardening)\n * src/lib/content/validation-parity.ts, src/lib/content/dock-vocabulary.ts (TAB_MAX, TAB_NAME_MAX)\n * When the backend widens, widen these and the adapters together; the round-trip test then shrinks the lossy ledger.\n */\n\n/* ── Limits the backend enforces ─────────────────────────────────────── */\n/** Field levels one schema may nest (a top-level field, or a prop, is level 1). */\nexport const MAX_FIELD_DEPTH = 10;\n/** Tabs (`kind: \"tab\"` fieldsets) one screen may hold, and a tab name's length. */\nexport const TAB_MAX = 3;\nexport const TAB_NAME_MAX = 40;\nexport const FIELDSETS_MAX = 30;\nexport const FIELDSET_NAME_MAX = 60;\nexport const FIELDSET_DESCRIPTION_MAX = 500;\nexport const FIELD_HELP_MAX = 500;\nexport const PROP_HELP_MAX = 200;\nexport const PROP_PLACEHOLDER_MAX = 120;\nexport const HELP_MORE_MAX = 2000;\nexport const LOCK_REASON_MAX = 200;\nexport const ITEM_LABEL_MAX = 24;\nexport const PREVIEW_FALLBACK_MAX = 60;\nexport const PROP_GROUP_LABEL_MAX = 32;\nexport const PATTERN_MAX = 200;\n/** A tags value's tag length (TAG_VALUE_MAX_LENGTH), a code value's length (CODE_MAX_LENGTH), a rating's max with none set. */\nexport const TAG_VALUE_MAX_LENGTH = 64;\nexport const CODE_MAX_LENGTH = 100_000;\nexport const RATING_DEFAULT_MAX = 5;\n/** ratingConfigSchema: config.max a whole 1–10; (max − min) / step whole and at most this many stops. */\nexport const RATING_MAX = 10;\nexport const RATING_MAX_STOPS = 100;\n/** tagsConfigSchema: config.min 0–500, config.max 1–500. */\nexport const TAGS_ITEMS_MAX = 500;\n/** A choice option's description (OPTION_DESCRIPTION_MAX): one line. */\nexport const OPTION_DESCRIPTION_MAX = 140;\n/** config.patternMessage (PATTERN_MESSAGE_MAX), config.unit on a number (NUMBER_UNIT_MAX). */\nexport const PATTERN_MESSAGE_MAX = 200;\nexport const NUMBER_UNIT_MAX = 24;\n/** fieldUiSchema: ui.rows 1–40, ui.placeholder 1–120, ui.itemTitle 1–60, ui.synced.from 1–64. */\nexport const UI_ROWS_MAX = 40;\nexport const UI_PLACEHOLDER_MAX = 120;\nexport const ITEM_TITLE_MAX = 60;\nexport const SYNCED_FROM_MAX = 64;\n/** ui.itemName is an identifier: a letter, then letters, digits or _ (≤ 64). */\nexport const ITEM_NAME_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\n/** propUiSchema group: description 1–200, order 0–99. */\nexport const PROP_GROUP_DESCRIPTION_MAX = 200;\nexport const PROP_GROUP_ORDER_MAX = 99;\n/** propUiSchema tab: at most 8 distinct tabs per component, an id 1–40, a label ≤ TAB_NAME_MAX trimmed, order 0–99. */\nexport const PROP_TAB_MAX = 8;\nexport const PROP_TAB_ID_MAX = 40;\n/** numberScaleSchema: token value 1–32, label 1–24, title 1–60, css 1–60; 1–50 steps; at most 20 presets. */\nexport const SCALE_TOKEN_VALUE_MAX = 32;\nexport const SCALE_LABEL_MAX = 24;\nexport const SCALE_TITLE_MAX = 60;\nexport const SCALE_CSS_MAX = 60;\nexport const SCALE_STEPS_MAX = 50;\nexport const SCALE_PRESETS_MAX = 20;\n/** The video block's transcript cap (VIDEO_TRANSCRIPT_MAX). */\nexport const VIDEO_TRANSCRIPT_MAX = 100_000;\n\n/* ── Icons: the closed dock vocabulary (packages/types/src/dock-icon-names.ts at e126bf33d: 472 names, Sanity's set\n * plus every distinct V2 corpus icon but `map`; copied verbatim from that generated file, regenerate from it) ── */\nexport const DOCK_ICON_NAMES = [\n \"abc\", \"access-denied\", \"activity\", \"add\", \"add-circle\", \"add-comment\", \"add-document\", \"add-user\", \"address-book\",\n \"adjustments\", \"adjustments-horizontal\", \"alarm\", \"alert-triangle\", \"align-left\", \"api\", \"app-window\", \"apple\",\n \"apps\", \"archive\", \"arrow-back-up\", \"arrow-down\", \"arrow-guide\", \"arrow-left\", \"arrow-right\", \"arrow-top-right\",\n \"arrow-up\", \"arrows-diagonal\", \"arrows-down\", \"arrows-exchange\", \"arrows-horizontal\", \"arrows-left-right\",\n \"arrows-shuffle\", \"arrows-sort\", \"article\", \"aspect-ratio\", \"asterisk\", \"award\", \"axis-x\", \"backpack\", \"badge\",\n \"badge-cc\", \"badges\", \"bar-chart\", \"basket\", \"bell\", \"bill\", \"binary-document\", \"block-content\", \"block-element\",\n \"blockquote\", \"bold\", \"bolt\", \"book\", \"book-2\", \"bookmark\", \"bookmark-filled\", \"books\", \"bottle\", \"box\",\n \"brand-dribbble\", \"brand-facebook\", \"brand-instagram\", \"brand-linkedin\", \"brand-pinterest\", \"brand-tiktok\",\n \"brand-x\", \"brand-youtube\", \"briefcase\", \"broadcast\", \"browser\", \"bug\", \"building\", \"building-skyscraper\",\n \"building-store\", \"bulb-filled\", \"bulb-outline\", \"calculator\", \"calendar\", \"calendar-dollar\", \"calendar-event\",\n \"calendar-exclamation\", \"calendar-off\", \"calendar-plus\", \"calendar-star\", \"calendar-time\", \"camera\", \"campfire\",\n \"carousel-horizontal\", \"case\", \"cash\", \"category\", \"category-2\", \"chart-area\", \"chart-arrows\", \"chart-bar\",\n \"chart-bar-popular\", \"chart-donut\", \"chart-dots\", \"chart-line\", \"chart-upward\", \"check\", \"checkbox\", \"checklist\",\n \"checkmark\", \"checkmark-circle\", \"chef-hat\", \"chevron-down\", \"chevron-left\", \"chevron-right\", \"chevron-up\",\n \"chevrons-right\", \"circle\", \"circle-check\", \"circle-dot\", \"circle-number-1\", \"circle-plus\", \"click\", \"clipboard\",\n \"clipboard-image\", \"clipboard-text\", \"clock\", \"clock-check\", \"clock-hour-4\", \"close\", \"close-circle\", \"code\",\n \"code-block\", \"cog\", \"collapse\", \"color-wheel\", \"columns\", \"columns-2\", \"columns-3\", \"comment\", \"component\",\n \"compose\", \"compose-sparkles\", \"confetti\", \"controls\", \"cookie\", \"copy\", \"credit-card\", \"crop\", \"cube\",\n \"currency-dollar\", \"dashboard\", \"database\", \"database-search\", \"desktop\", \"device-desktop\", \"device-mobile\",\n \"device-tablet\", \"devices\", \"diamond\", \"discount\", \"document\", \"document-pdf\", \"document-remove\", \"document-sheet\",\n \"document-text\", \"document-video\", \"document-word\", \"document-zip\", \"documents\", \"door-exit\", \"dot\",\n \"double-chevron-down\", \"double-chevron-left\", \"double-chevron-right\", \"double-chevron-up\", \"double-quote\",\n \"download\", \"drag-handle\", \"drop\", \"droplet\", \"droplet-half\", \"earth-americas\", \"earth-globe\", \"edit\", \"egg\",\n \"ellipsis-horizontal\", \"ellipsis-vertical\", \"empty\", \"enter\", \"enter-right\", \"envelope\", \"equal\", \"error-filled\",\n \"error-outline\", \"error-screen\", \"expand\", \"eye-closed\", \"eye-off\", \"eye-open\", \"face-happy\", \"face-indifferent\",\n \"face-sad\", \"feather\", \"feedback\", \"file\", \"file-certificate\", \"file-code\", \"file-download\", \"file-text\", \"filter\",\n \"flag\", \"flame\", \"flask\", \"focus-2\", \"folder\", \"folders\", \"forms\", \"frame\", \"generate\", \"gift\", \"git-branch\",\n \"github\", \"grid-dots\", \"groq\", \"hammer\", \"hand-finger\", \"hanger\", \"hash\", \"headphones\", \"headset\", \"heart\",\n \"heart-filled\", \"heart-handshake\", \"help-circle\", \"highlight\", \"history\", \"home\", \"hourglass\", \"ice-cream\",\n \"id-badge\", \"id-badge-2\", \"image\", \"image-remove\", \"images\", \"inbox\", \"infinity\", \"info-circle\", \"info-filled\",\n \"info-outline\", \"info-square-rounded\", \"inline\", \"inline-element\", \"input-search\", \"insert-above\", \"insert-below\",\n \"italic\", \"joystick\", \"json\", \"language\", \"launch\", \"layout\", \"layout-align-center\", \"layout-board\",\n \"layout-board-split\", \"layout-bottombar\", \"layout-bottombar-expand\", \"layout-cards\", \"layout-columns\",\n \"layout-dashboard\", \"layout-grid\", \"layout-list\", \"layout-navbar\", \"layout-rows\", \"layout-sidebar\",\n \"layout-sidebar-right\", \"leaf\", \"leave\", \"lemon\", \"library-photo\", \"lifebuoy\", \"link\", \"link-removed\", \"linkedin\",\n \"list\", \"list-check\", \"list-details\", \"list-numbers\", \"list-tree\", \"lock\", \"logo-js\", \"logo-ts\", \"mail\", \"map-2\",\n \"map-pin\", \"map-pins\", \"marker\", \"marker-removed\", \"master-detail\", \"math-function\", \"meat\", \"menu\", \"message\",\n \"message-2\", \"message-check\", \"message-circle\", \"message-circle-2\", \"message-plus\", \"message-star\", \"microphone\",\n \"microphone-slash\", \"mobile-device\", \"mood-empty\", \"moon\", \"movie\", \"news\", \"notes\", \"number\", \"ok-hand\", \"olist\",\n \"overage\", \"package\", \"packages\", \"palette\", \"panel-left\", \"panel-right\", \"paperclip\", \"pause\", \"pencil\", \"phone\",\n \"photo\", \"photo-scan\", \"photo-search\", \"pig-money\", \"pin\", \"pin-filled\", \"pin-removed\", \"play\", \"player-play\",\n \"player-track-next\", \"playlist-add\", \"plug\", \"plug-connected\", \"plus-minus\", \"point\", \"presentation\", \"printer\",\n \"progress-50\", \"progress-75\", \"projects\", \"publish\", \"qrcode\", \"quote\", \"read-only\", \"receipt\", \"recycle\", \"redo\",\n \"refresh\", \"remove\", \"remove-circle\", \"repeat\", \"reset\", \"restore\", \"retrieve\", \"retry\", \"revert\", \"robot\",\n \"rocket\", \"rosette\", \"route\", \"ruler\", \"ruler-measure\", \"salad\", \"scale\", \"schema\", \"school\", \"search\", \"section\",\n \"select\", \"send\", \"server\", \"settings\", \"share\", \"shield-check\", \"shield-lock\", \"shopping-bag\", \"shopping-cart\",\n \"shopping-cart-plus\", \"signature\", \"sitemap\", \"slideshow\", \"sort\", \"sort-descending\", \"spacing-vertical\", \"sparkle\",\n \"sparkles\", \"speakerphone\", \"spinner\", \"split-horizontal\", \"split-vertical\", \"square\", \"stack\", \"stack-2\",\n \"stack-compact\", \"stairs\", \"stairs-up\", \"star\", \"star-filled\", \"stars\", \"stop\", \"strikethrough\", \"string\",\n \"subtask\", \"sun\", \"superscript\", \"sync\", \"table\", \"table-options\", \"tablet-device\", \"tag\", \"tags\", \"target\", \"task\",\n \"template\", \"tent\", \"terminal\", \"terminal-2\", \"text\", \"th-large\", \"th-list\", \"thumb-up\", \"thumbs-down\", \"thumbs-up\",\n \"ticket\", \"tiers\", \"timeline\", \"toggle-arrow-right\", \"toggle-right\", \"token\", \"tool\", \"tools-kitchen-2\", \"transfer\",\n \"translate\", \"trash\", \"trend-upward\", \"triangle-outline\", \"trolley\", \"truck\", \"truck-delivery\", \"truncate\",\n \"twitter\", \"typography\", \"ulist\", \"unarchive\", \"underline\", \"undo\", \"unknown\", \"unlink\", \"unlock\", \"unpublish\",\n \"upload\", \"user\", \"user-circle\", \"user-plus\", \"user-search\", \"user-star\", \"users\", \"users-group\", \"versions\",\n \"video\", \"vocabulary\", \"vs\", \"warning-filled\", \"warning-outline\", \"weight\", \"world\", \"wrench\", \"zoom-question\",\n] as const;\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n\n/* ── Content model fields ────────────────────────────────────────────── */\nexport type ProdFieldType =\n | \"text\" | \"richtext\" | \"document\" | \"image\" | \"boolean\" | \"number\" | \"select\"\n | \"reference\" | \"multi-reference\" | \"multiReference\" | \"array\" | \"date\" | \"datetime\"\n | \"longtext\" | \"slug\" | \"email\" | \"phone\" | \"link\" | \"color\" | \"json\" | \"file\"\n | \"component-ref\" | \"modular\" | \"sections\" | \"location\" | \"button\" | \"multiselect\" | \"icon\" | \"object\"\n | \"tags\" | \"rating\" | \"code\"\n /** V2 video: a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (VideoValue). */\n | \"video\"\n /** Legacy input only: normalized to `array` + zones on write, still read. */\n | \"group\" | \"repeater\";\n\nexport type OpenMode = \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n/** backend SHOW_IF_OPS (validation/schemas/content.ts). */\nexport type ShowIfOp = \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\";\nexport interface ShowIfRule {\n field: string;\n op: ShowIfOp;\n value?: string | string[];\n}\nexport interface ShowIf {\n match: \"all\" | \"any\";\n rules: ShowIfRule[];\n}\n\nexport type UiLayout = \"list\" | \"grid\" | \"table\" | \"rows\" | \"chips\" | \"gallery\";\n/** ui.control (UI_CONTROLS): the leaf controls, the V2 control layouts among them. */\nexport const UI_CONTROLS = [\"segmented\", \"slider\", \"rating\", \"dropdown\", \"radio\", \"cards\", \"grid\", \"switch\", \"checkbox\"] as const;\nexport type UiControl = (typeof UI_CONTROLS)[number];\n/** The V2 control layouts and the types each fits (CONTROL_TYPES); segmented / slider / rating have their own rules. */\nexport const CONTROL_TYPES: Readonly<Partial<Record<UiControl, readonly string[]>>> = {\n dropdown: [\"select\"],\n radio: [\"select\"],\n cards: [\"select\", \"multiselect\"],\n grid: [\"select\"],\n switch: [\"boolean\"],\n checkbox: [\"boolean\", \"multiselect\"],\n};\n/** A row preview: child keys or dotted paths (V2), a literal fallback, and an icon shown while there is no media. */\nexport interface UiPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\nexport interface FieldUi {\n collapsed?: boolean;\n preview?: UiPreview;\n layout?: UiLayout;\n reorderable?: boolean;\n control?: UiControl;\n icon?: DockIconName;\n itemLabel?: string;\n /** text / longtext: the lines a text box opens with (1–40). */\n rows?: number;\n /** a field's placeholder when its config is strict (a prop keeps its own `placeholder`). */\n placeholder?: string;\n /** a list's item type: its identifier and its title (V2 `of[0].name` / `title`). */\n itemName?: string;\n itemTitle?: string;\n /** the value comes from a global: an edit applies everywhere. */\n synced?: { from: string };\n /** link / image / button: a plain string or the object. */\n valueShape?: \"string\" | \"object\";\n /** V2 field access (D58): the editor gates, the backend stores. */\n access?: { view?: \"schema.view\"; edit?: \"schema.manage\" };\n /** true = never shown in the form; false ≡ absent. */\n hidden?: boolean;\n /** modular: per block slug, how a row of that block type reads (V2 `of[i].icon` / `preview`). */\n blocks?: Record<string, { icon?: DockIconName; preview?: UiPreview }>;\n input?: { name: string; writes?: string[] };\n}\n\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\nexport interface ScaleTokenStep {\n value: string;\n label: string;\n title?: string;\n px?: number;\n css?: string;\n}\nexport type ScaleBound = number | Partial<Record<ScaleUnit, number>>;\n/**\n * A number's `config.scale` (CPO D41): a stepped range, numeric steps or token steps, units, presets, and the custom\n * escape hatch (a boolean, or its bounds). A token scale stores the token string; a custom value `{ value, unit }`.\n */\nexport interface NumberScale {\n steps: { min: number; max: number; step?: number } | Array<{ value: number; label?: string }> | ScaleTokenStep[];\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n allowCustom?: boolean | { min?: ScaleBound; max?: ScaleBound; units?: ScaleUnit[]; step?: number };\n presets?: Array<{ label?: string; value: number | string | ScaleCustomValue }>;\n}\n\nexport interface ArrayZoneConfig {\n nonRepeatable?: ContentModelField[];\n repeatable?: { fields: ContentModelField[]; minItems?: number; maxItems?: number };\n}\n\n/** One choice: a bare value, or `{ label, value }` with optional chrome (a dock icon, one line ≤ 140 under the label). */\nexport interface ChoiceOption {\n label: string;\n value: string;\n icon?: DockIconName;\n description?: string;\n}\nexport type SelectOption = string | ChoiceOption;\n\n/**\n * A list of scalars' item settings (backend arrayItemSettingsSchema, an `array` prop's `config.item`): the V2 item field's\n * description, locale chip, required, and a text / rich text item's length (a text item's pattern).\n */\nexport interface ArrayItemSettings {\n helpText?: string;\n localized?: boolean;\n required?: boolean;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n patternMessage?: string;\n}\n\n/** The typed keys of a field's `config` bag; the bag itself stays loose on scalar types. */\nexport interface FieldConfig {\n /** primitive array: scalars, or images, links or rich text (each item judged by its own type). */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n zones?: ArrayZoneConfig;\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n /** reference / multi-reference (props): the non-entry targets, and a filter over the target's fields. */\n targets?: (\"page\" | \"form\" | \"collection\")[];\n filter?: string;\n min?: number;\n max?: number;\n step?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n /** text / longtext: the message shown when the pattern does not match (≤ 200, needs `pattern`). */\n patternMessage?: string;\n /** number: the error bounds (V2 validation.min / max); they win over min / max. */\n validation?: { min?: number; max?: number };\n /** number: what it counts (\"%\", \"USD\"), 1–24 characters. */\n unit?: string;\n placeholder?: string;\n includeTime?: boolean;\n /** \"site\", an IANA zone name, true (the editor picks a zone) or false (none). */\n timezone?: string | boolean;\n blockSlugs?: string[];\n minItems?: number;\n maxItems?: number;\n allowedSections?: string[];\n componentIds?: string[];\n /** slot (props): the V2 `of.allow` block names it takes, kept as written (backend slotAllowIssues). */\n allow?: string[];\n /** array (props): the item's own settings (backend arrayItemSettingsSchema). */\n item?: ArrayItemSettings;\n scale?: NumberScale;\n /** multiselect: its choices; with `allowCustom` it is free tags. tags: its suggestions. */\n options?: SelectOption[];\n allowCustom?: boolean;\n /** code: the language, and the languages an editor may pick (strict config, with tags' and rating's). */\n language?: string;\n languages?: string[];\n /**\n * text: \"url\" marks a text field the kit edits as a URL (V2 `url`). The backend keeps a text field's config as sent and\n * enforces its minLength / maxLength / pattern, which a link field would not; it reads no other meaning into the key.\n */\n inputType?: \"url\";\n [key: string]: unknown;\n}\n\nexport interface ContentModelField {\n key: string;\n label: string;\n type: ProdFieldType;\n helpText?: string;\n required?: boolean;\n unique?: boolean;\n defaultValue?: unknown;\n /** select: strings or { label, value }. */\n options?: SelectOption[];\n config?: FieldConfig | null;\n /** object (and legacy group / repeater): child fields. */\n fields?: ContentModelField[];\n openMode?: OpenMode;\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n fieldsetId?: string;\n placement?: \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n showIf?: ShowIf;\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: once any field is marked, a translation owns only its localized values. */\n localized?: boolean;\n ui?: FieldUi;\n searchable?: boolean;\n [key: string]: unknown;\n}\n\nexport type FieldsetKind = \"group\" | \"row\" | \"tab\";\nexport interface Fieldset {\n id: string;\n name: string;\n description?: string;\n kind?: FieldsetKind;\n icon?: DockIconName;\n collapsed?: boolean;\n tab?: string;\n collapsible?: boolean;\n columns?: 1 | 2;\n layout?: \"stack\" | \"breakpoints\";\n}\n\n/** A content model as the adapters read and write it (server-owned ids and timestamps left out). */\nexport interface ProdContentModel {\n name: string;\n slug: string;\n description?: string;\n kind?: \"model\" | \"block\";\n fields: ContentModelField[];\n fieldsets?: Fieldset[];\n}\n\n/* ── Component props ─────────────────────────────────────────────────── */\nexport const COMPONENT_PROP_TYPES = [\n \"text\", \"richtext\", \"image\", \"url\", \"boolean\", \"number\", \"select\", \"group\", \"table\", \"slot\", \"form\",\n \"link\", \"button\", \"date\", \"color\", \"file\", \"icon\", \"multiselect\",\n \"object\", \"datetime\", \"slug\", \"email\", \"phone\", \"json\", \"location\", \"tags\", \"rating\", \"code\",\n /** an entry id (or `{ entryId, modelSlug }`) and a list of them, hydrated on delivery; no definition default. */\n \"reference\", \"multi-reference\",\n /** a video value, a list of `config.itemType` values, multi-line text. */\n \"video\", \"array\", \"longtext\",\n] as const;\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\nexport type ComponentSubFieldType = Exclude<ComponentPropType, \"slot\" | \"form\">;\n\nexport const COMPONENT_CATEGORIES = [\n \"navbar\", \"footer\", \"button\", \"section\", \"slider\", \"tabs\", \"form\", \"custom\", \"hero\", \"content\", \"social-proof\", \"conversion\",\n] as const;\nexport type ComponentCategory = (typeof COMPONENT_CATEGORIES)[number];\n\nexport interface PropGroup {\n id: string;\n label?: string;\n kind?: \"group\" | \"row\";\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys, on the defining prop: a line under the header (≤ 200), side by side, a static header, a\n * breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n/**\n * A top-level prop's tab. Defined once: the first top-level prop with an id carries its label / icon / order, later\n * props carry `{ id }` only. A nested prop names one as `{ id }` only (tab_nested refuses a definition there; V2 and\n * the dock ignore it); one ui.group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n label?: string;\n icon?: DockIconName;\n /** its place among the tabs (0–99; absent = where its first prop sits). */\n order?: number;\n}\nexport type PropUi = FieldUi & { group?: PropGroup; tab?: PropTab };\n\nexport interface ComponentSubField {\n key: string;\n label: string;\n type: ComponentSubFieldType;\n defaultValue?: unknown;\n required?: boolean;\n /** null = no help on purpose (V2 has no description); absent = the platform's auto-help. */\n helpText?: string | null;\n placeholder?: string;\n /** strings or { label, value } (subFieldOptionSchema). */\n options?: SelectOption[];\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** on a table's sub-field: no two rows share it; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** the prop's ui, inline group included (V2 fieldsets nest). */\n ui?: PropUi;\n readOnly?: true | \"developer\";\n lockReason?: string;\n localized?: boolean;\n fields?: ComponentSubField[];\n config?: { fields?: ComponentSubField[]; options?: SelectOption[] } & Record<string, unknown>;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n /**\n * Where the override writes inside the component's blockJson. Binding, not schema: the V2 language has no twin, so\n * fromTypeSchema leaves it unset and the host binds it (componentize lane) before the save.\n */\n target?: { blockId: string; path: string };\n type: ComponentPropType;\n defaultValue?: unknown;\n required?: boolean;\n /** null = no help on purpose (V2 has no description); absent = the platform's auto-help. */\n helpText?: string | null;\n placeholder?: string;\n showIf?: ShowIf;\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** a list prop's items (a table's rows) distinct; refused on a top-level scalar (unique_prop_scope). */\n unique?: boolean;\n openMode?: OpenMode;\n readOnly?: true | \"developer\";\n lockReason?: string;\n localized?: boolean;\n config?: {\n componentIds?: string[];\n /** slot: the V2 block names it takes (`textBlock`), resolved to the project's components by the dock. */\n allow?: string[];\n /** array: the item's own settings. */\n item?: ArrayItemSettings;\n multiple?: boolean;\n minItems?: number;\n maxItems?: number;\n options?: SelectOption[];\n fields?: ComponentSubField[];\n min?: number;\n max?: number;\n step?: number;\n /** number: the error bounds (they win over min / max). */\n validation?: { min?: number; max?: number };\n /** text / url / longtext / richtext: length (richtext: its plain text). text / url / longtext: a pattern and its message. */\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n patternMessage?: string;\n /** reference / multi-reference: the target model, or polymorphic with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n /** reference / multi-reference: page / form / collection targets (backend REF_TARGET_KINDS) and a filter over the target's fields. */\n targets?: (\"page\" | \"form\" | \"collection\")[];\n filter?: string;\n /** array: what the list holds. */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n /** table with mode \"types\" (a polymorphic list): its item types, each row's `_type` naming one. */\n itemTypes?: { name: string; label?: string; fields: ComponentSubField[]; icon?: DockIconName; preview?: UiPreview }[];\n } & Record<string, unknown>;\n ui?: PropUi;\n}\n\n/** A component as the adapters read and write it. */\n/**\n * How ONE instance of a component reads as a row in a parent's slot list (backend `components.preview`, migration 0459;\n * types ComponentPreview): V2's document-level `preview`. `title` / `subtitle` / `media` each name a TOP-LEVEL prop key\n * (the API refuses any other: preview_key_unknown), `fallback` is the literal row label (trimmed, 1..120), `icon` a dock\n * icon shown while the row has no media.\n */\nexport type ComponentPreview = UiPreview;\n/** backend componentPreviewSchema: a preview slot names a key of at most this many characters */\nexport const COMPONENT_PREVIEW_KEY_MAX = 64;\n/** backend componentPreviewSchema: the row's literal fallback label, trimmed, at most this many characters */\nexport const COMPONENT_PREVIEW_FALLBACK_MAX = 120;\n\nexport interface ProdComponent {\n name: string;\n slug: string;\n description?: string;\n category?: ComponentCategory;\n props: ComponentPropDef[];\n preview?: ComponentPreview | null;\n /** The component's dock icon (backend `components.icon`, dockIconSchema): V2's block icon. */\n icon?: DockIconName | null;\n /** The V2 tabs no top-level prop sits in (backend `components.tabs`, componentTabsSchema): declared, shown by none. */\n tabs?: PropTab[] | null;\n}\n\n/* ── Stored values ───────────────────────────────────────────────────── */\nexport const LINK_RELS = [\"nofollow\", \"sponsored\", \"ugc\"] as const;\nexport type LinkRel = (typeof LINK_RELS)[number];\nexport const LINK_VALUE_TYPES = [\"url\", \"page\", \"entry\", \"email\", \"phone\", \"anchor\", \"section\", \"file\"] as const;\nexport type LinkValueType = (typeof LINK_VALUE_TYPES)[number];\n/** The F1 link object (link-value.ts). A bare href string stays valid too. */\nexport interface ProdLinkValue {\n type?: LinkValueType;\n href: string;\n title?: string;\n newTab?: boolean;\n target?: \"_self\" | \"_blank\";\n rel?: LinkRel;\n section?: string;\n /** page / entry links: the target's id. */\n ref?: string;\n}\n\nexport const BUTTON_VARIANTS = [\"primary\", \"secondary\", \"tertiary\", \"brand\", \"dark\", \"light\", \"outline\", \"link\"] as const;\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\nexport const BUTTON_SIZES = [\"sm\", \"md\", \"lg\"] as const;\n/** One button as one value (button-look.ts ButtonValue). */\nexport interface ProdButtonValue {\n label: string;\n href: string | ProdLinkValue;\n variant?: ButtonVariant;\n size?: (typeof BUTTON_SIZES)[number];\n arrow?: boolean;\n icon?: DockIconName | null;\n newTab?: boolean;\n rel?: LinkRel;\n /** Stretch across the column (backend button_full_width_invalid refuses a non-boolean a write brings). */\n fullWidth?: boolean;\n}\n\n/** 0–1 fractions of the image cut from each edge. */\nexport interface ProdImageCrop {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n/** The normalized image value (field-value-normalize.ts): other keys are dropped on write. */\nexport interface ProdImageValue {\n id?: string;\n url: string;\n name?: string;\n altText?: string;\n /** 0–1 fractions. */\n focal?: { x: number; y: number };\n crop?: ProdImageCrop;\n}\n\n/** The V2 video value's object form (video-value.ts): exactly the video block's props. A bare URL string is valid too. */\nexport const VIDEO_VALUE_KEYS = [\"url\", \"poster\", \"autoplay\", \"loop\", \"transcript\"] as const;\nexport interface ProdVideoValue {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n transcript?: string;\n}\n\n/** A polymorphic reference value. */\nexport interface ProdPolymorphicRef {\n entryId: string;\n modelSlug: string;\n}\n/**\n * A page, form or collection pick on a prop reference that also takes entries (backend reference-target-config.ts\n * targetRefOf): a bare string there is read as an entry id (acceptsEntries), so a non-entry pick names its kind.\n */\nexport interface ProdTargetRef {\n kind: \"page\" | \"form\" | \"collection\";\n id: string;\n}\n/** What a `form` prop stores. */\nexport interface ProdFormRef {\n formId: string;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"prod-types.js","names":[],"sources":["../../src/adapters/prod-types.ts"],"sourcesContent":["/**\n * PROD SHAPES — the production schema language and stored values, typed locally. The caps and key rules the backend\n * and the kit must agree on come from @bettercms-ai/types (W1a, a peer of the kit since W1c): one home per constant.\n *\n * Mirrors the backend at F1 + F1.x-props + link objects + tags / rating / code (72ea2b68d), then reference props\n * (73a120c50), validation parity (dd021ceba), option meta (ab15fe893), V2 chrome keys and types (98e48b9e3, 324580b2e),\n * the V2 icon vocabulary (e126bf33d) and the localized flag (279a10490) — origin/dev 81f385ff3:\n * packages/types/src/content-model.ts, component.ts, link-value.ts, button-look.ts, dock-icon-names.ts, video-value.ts\n * src/lib/validation/schemas/content.ts (baseField, fieldUiSchema, chromeUiProblems, fieldsets, MAX_FIELD_DEPTH)\n * src/lib/validation/schemas/components.ts (componentPropDefSchema, subFieldSchema, propUiSchema, propValidationHardening)\n * src/lib/content/validation-parity.ts, src/lib/content/dock-vocabulary.ts (TAB_MAX, TAB_NAME_MAX)\n * When the backend widens, widen these and the adapters together; the round-trip test then shrinks the lossy ledger.\n */\nimport { DEPTH_MAX, HELP_CAPS, TAB_MAX as SHARED_TAB_MAX, TAB_MAX_RENDERABLE_NOW } from \"@bettercms-ai/types\";\n\n/* ── Limits the backend enforces ─────────────────────────────────────── */\n/** Field levels one schema may nest (a top-level field, or a prop, is level 1). */\nexport const MAX_FIELD_DEPTH = DEPTH_MAX;\n/** Tabs (`kind: \"tab\"` fieldsets) a model screen holds TODAY (it rises to types' TAB_MAX at F12), and a tab name's length. */\nexport const TAB_MAX = TAB_MAX_RENDERABLE_NOW;\nexport const TAB_NAME_MAX = 40;\nexport const FIELDSETS_MAX = 30;\nexport const FIELDSET_NAME_MAX = 60;\nexport const FIELDSET_DESCRIPTION_MAX = HELP_CAPS.fieldset;\nexport const FIELD_HELP_MAX = HELP_CAPS.field;\nexport const PROP_HELP_MAX = HELP_CAPS.prop;\nexport const PROP_PLACEHOLDER_MAX = HELP_CAPS.placeholder;\nexport const HELP_MORE_MAX = HELP_CAPS.helpMore;\nexport const LOCK_REASON_MAX = 200;\nexport const ITEM_LABEL_MAX = 24;\nexport const PREVIEW_FALLBACK_MAX = 60;\nexport const PROP_GROUP_LABEL_MAX = 32;\nexport const PATTERN_MAX = 200;\n/** A tags value's tag length (TAG_VALUE_MAX_LENGTH), a code value's length (CODE_MAX_LENGTH), a rating's max with none set. */\nexport const TAG_VALUE_MAX_LENGTH = 64;\nexport const CODE_MAX_LENGTH = 100_000;\nexport const RATING_DEFAULT_MAX = 5;\n/** ratingConfigSchema: config.max a whole 1–10; (max − min) / step whole and at most this many stops. */\nexport const RATING_MAX = 10;\nexport const RATING_MAX_STOPS = 100;\n/** tagsConfigSchema: config.min 0–500, config.max 1–500. */\nexport const TAGS_ITEMS_MAX = 500;\n/** A choice option's description (OPTION_DESCRIPTION_MAX): one line. */\nexport const OPTION_DESCRIPTION_MAX = HELP_CAPS.option;\n/** config.patternMessage (PATTERN_MESSAGE_MAX), config.unit on a number (NUMBER_UNIT_MAX). */\nexport const PATTERN_MESSAGE_MAX = 200;\nexport const NUMBER_UNIT_MAX = 24;\n/** fieldUiSchema: ui.rows 1–40, ui.placeholder 1–120, ui.itemTitle 1–60, ui.synced.from 1–64. */\nexport const UI_ROWS_MAX = 40;\nexport const UI_PLACEHOLDER_MAX = HELP_CAPS.placeholder;\nexport const ITEM_TITLE_MAX = 60;\nexport const SYNCED_FROM_MAX = 64;\n/** ui.itemName is an identifier: a letter, then letters, digits or _ (≤ 64). */\nexport const ITEM_NAME_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\n/** propUiSchema group: description 1–200, order 0–99. */\nexport const PROP_GROUP_DESCRIPTION_MAX = HELP_CAPS.propGroup;\nexport const PROP_GROUP_ORDER_MAX = 99;\n/** propUiSchema tab: at most 8 distinct tabs per component, an id 1–40, a label ≤ TAB_NAME_MAX trimmed, order 0–99. */\nexport const PROP_TAB_MAX = SHARED_TAB_MAX;\nexport const PROP_TAB_ID_MAX = 40;\n/** numberScaleSchema: token value 1–32, label 1–24, title 1–60, css 1–60; 1–50 steps; at most 20 presets. */\nexport const SCALE_TOKEN_VALUE_MAX = 32;\nexport const SCALE_LABEL_MAX = 24;\nexport const SCALE_TITLE_MAX = 60;\nexport const SCALE_CSS_MAX = 60;\nexport const SCALE_STEPS_MAX = 50;\nexport const SCALE_PRESETS_MAX = 20;\n/** The video block's transcript cap (VIDEO_TRANSCRIPT_MAX). */\nexport const VIDEO_TRANSCRIPT_MAX = 100_000;\n\n/* ── Icons: the closed dock vocabulary (packages/types/src/dock-icon-names.ts at e126bf33d: 472 names, Sanity's set\n * plus every distinct V2 corpus icon but `map`; copied verbatim from that generated file, regenerate from it) ── */\nexport const DOCK_ICON_NAMES = [\n \"abc\", \"access-denied\", \"activity\", \"add\", \"add-circle\", \"add-comment\", \"add-document\", \"add-user\", \"address-book\",\n \"adjustments\", \"adjustments-horizontal\", \"alarm\", \"alert-triangle\", \"align-left\", \"api\", \"app-window\", \"apple\",\n \"apps\", \"archive\", \"arrow-back-up\", \"arrow-down\", \"arrow-guide\", \"arrow-left\", \"arrow-right\", \"arrow-top-right\",\n \"arrow-up\", \"arrows-diagonal\", \"arrows-down\", \"arrows-exchange\", \"arrows-horizontal\", \"arrows-left-right\",\n \"arrows-shuffle\", \"arrows-sort\", \"article\", \"aspect-ratio\", \"asterisk\", \"award\", \"axis-x\", \"backpack\", \"badge\",\n \"badge-cc\", \"badges\", \"bar-chart\", \"basket\", \"bell\", \"bill\", \"binary-document\", \"block-content\", \"block-element\",\n \"blockquote\", \"bold\", \"bolt\", \"book\", \"book-2\", \"bookmark\", \"bookmark-filled\", \"books\", \"bottle\", \"box\",\n \"brand-dribbble\", \"brand-facebook\", \"brand-instagram\", \"brand-linkedin\", \"brand-pinterest\", \"brand-tiktok\",\n \"brand-x\", \"brand-youtube\", \"briefcase\", \"broadcast\", \"browser\", \"bug\", \"building\", \"building-skyscraper\",\n \"building-store\", \"bulb-filled\", \"bulb-outline\", \"calculator\", \"calendar\", \"calendar-dollar\", \"calendar-event\",\n \"calendar-exclamation\", \"calendar-off\", \"calendar-plus\", \"calendar-star\", \"calendar-time\", \"camera\", \"campfire\",\n \"carousel-horizontal\", \"case\", \"cash\", \"category\", \"category-2\", \"chart-area\", \"chart-arrows\", \"chart-bar\",\n \"chart-bar-popular\", \"chart-donut\", \"chart-dots\", \"chart-line\", \"chart-upward\", \"check\", \"checkbox\", \"checklist\",\n \"checkmark\", \"checkmark-circle\", \"chef-hat\", \"chevron-down\", \"chevron-left\", \"chevron-right\", \"chevron-up\",\n \"chevrons-right\", \"circle\", \"circle-check\", \"circle-dot\", \"circle-number-1\", \"circle-plus\", \"click\", \"clipboard\",\n \"clipboard-image\", \"clipboard-text\", \"clock\", \"clock-check\", \"clock-hour-4\", \"close\", \"close-circle\", \"code\",\n \"code-block\", \"cog\", \"collapse\", \"color-wheel\", \"columns\", \"columns-2\", \"columns-3\", \"comment\", \"component\",\n \"compose\", \"compose-sparkles\", \"confetti\", \"controls\", \"cookie\", \"copy\", \"credit-card\", \"crop\", \"cube\",\n \"currency-dollar\", \"dashboard\", \"database\", \"database-search\", \"desktop\", \"device-desktop\", \"device-mobile\",\n \"device-tablet\", \"devices\", \"diamond\", \"discount\", \"document\", \"document-pdf\", \"document-remove\", \"document-sheet\",\n \"document-text\", \"document-video\", \"document-word\", \"document-zip\", \"documents\", \"door-exit\", \"dot\",\n \"double-chevron-down\", \"double-chevron-left\", \"double-chevron-right\", \"double-chevron-up\", \"double-quote\",\n \"download\", \"drag-handle\", \"drop\", \"droplet\", \"droplet-half\", \"earth-americas\", \"earth-globe\", \"edit\", \"egg\",\n \"ellipsis-horizontal\", \"ellipsis-vertical\", \"empty\", \"enter\", \"enter-right\", \"envelope\", \"equal\", \"error-filled\",\n \"error-outline\", \"error-screen\", \"expand\", \"eye-closed\", \"eye-off\", \"eye-open\", \"face-happy\", \"face-indifferent\",\n \"face-sad\", \"feather\", \"feedback\", \"file\", \"file-certificate\", \"file-code\", \"file-download\", \"file-text\", \"filter\",\n \"flag\", \"flame\", \"flask\", \"focus-2\", \"folder\", \"folders\", \"forms\", \"frame\", \"generate\", \"gift\", \"git-branch\",\n \"github\", \"grid-dots\", \"groq\", \"hammer\", \"hand-finger\", \"hanger\", \"hash\", \"headphones\", \"headset\", \"heart\",\n \"heart-filled\", \"heart-handshake\", \"help-circle\", \"highlight\", \"history\", \"home\", \"hourglass\", \"ice-cream\",\n \"id-badge\", \"id-badge-2\", \"image\", \"image-remove\", \"images\", \"inbox\", \"infinity\", \"info-circle\", \"info-filled\",\n \"info-outline\", \"info-square-rounded\", \"inline\", \"inline-element\", \"input-search\", \"insert-above\", \"insert-below\",\n \"italic\", \"joystick\", \"json\", \"language\", \"launch\", \"layout\", \"layout-align-center\", \"layout-board\",\n \"layout-board-split\", \"layout-bottombar\", \"layout-bottombar-expand\", \"layout-cards\", \"layout-columns\",\n \"layout-dashboard\", \"layout-grid\", \"layout-list\", \"layout-navbar\", \"layout-rows\", \"layout-sidebar\",\n \"layout-sidebar-right\", \"leaf\", \"leave\", \"lemon\", \"library-photo\", \"lifebuoy\", \"link\", \"link-removed\", \"linkedin\",\n \"list\", \"list-check\", \"list-details\", \"list-numbers\", \"list-tree\", \"lock\", \"logo-js\", \"logo-ts\", \"mail\", \"map-2\",\n \"map-pin\", \"map-pins\", \"marker\", \"marker-removed\", \"master-detail\", \"math-function\", \"meat\", \"menu\", \"message\",\n \"message-2\", \"message-check\", \"message-circle\", \"message-circle-2\", \"message-plus\", \"message-star\", \"microphone\",\n \"microphone-slash\", \"mobile-device\", \"mood-empty\", \"moon\", \"movie\", \"news\", \"notes\", \"number\", \"ok-hand\", \"olist\",\n \"overage\", \"package\", \"packages\", \"palette\", \"panel-left\", \"panel-right\", \"paperclip\", \"pause\", \"pencil\", \"phone\",\n \"photo\", \"photo-scan\", \"photo-search\", \"pig-money\", \"pin\", \"pin-filled\", \"pin-removed\", \"play\", \"player-play\",\n \"player-track-next\", \"playlist-add\", \"plug\", \"plug-connected\", \"plus-minus\", \"point\", \"presentation\", \"printer\",\n \"progress-50\", \"progress-75\", \"projects\", \"publish\", \"qrcode\", \"quote\", \"read-only\", \"receipt\", \"recycle\", \"redo\",\n \"refresh\", \"remove\", \"remove-circle\", \"repeat\", \"reset\", \"restore\", \"retrieve\", \"retry\", \"revert\", \"robot\",\n \"rocket\", \"rosette\", \"route\", \"ruler\", \"ruler-measure\", \"salad\", \"scale\", \"schema\", \"school\", \"search\", \"section\",\n \"select\", \"send\", \"server\", \"settings\", \"share\", \"shield-check\", \"shield-lock\", \"shopping-bag\", \"shopping-cart\",\n \"shopping-cart-plus\", \"signature\", \"sitemap\", \"slideshow\", \"sort\", \"sort-descending\", \"spacing-vertical\", \"sparkle\",\n \"sparkles\", \"speakerphone\", \"spinner\", \"split-horizontal\", \"split-vertical\", \"square\", \"stack\", \"stack-2\",\n \"stack-compact\", \"stairs\", \"stairs-up\", \"star\", \"star-filled\", \"stars\", \"stop\", \"strikethrough\", \"string\",\n \"subtask\", \"sun\", \"superscript\", \"sync\", \"table\", \"table-options\", \"tablet-device\", \"tag\", \"tags\", \"target\", \"task\",\n \"template\", \"tent\", \"terminal\", \"terminal-2\", \"text\", \"th-large\", \"th-list\", \"thumb-up\", \"thumbs-down\", \"thumbs-up\",\n \"ticket\", \"tiers\", \"timeline\", \"toggle-arrow-right\", \"toggle-right\", \"token\", \"tool\", \"tools-kitchen-2\", \"transfer\",\n \"translate\", \"trash\", \"trend-upward\", \"triangle-outline\", \"trolley\", \"truck\", \"truck-delivery\", \"truncate\",\n \"twitter\", \"typography\", \"ulist\", \"unarchive\", \"underline\", \"undo\", \"unknown\", \"unlink\", \"unlock\", \"unpublish\",\n \"upload\", \"user\", \"user-circle\", \"user-plus\", \"user-search\", \"user-star\", \"users\", \"users-group\", \"versions\",\n \"video\", \"vocabulary\", \"vs\", \"warning-filled\", \"warning-outline\", \"weight\", \"world\", \"wrench\", \"zoom-question\",\n] as const;\nexport type DockIconName = (typeof DOCK_ICON_NAMES)[number];\nexport const DOCK_ICON_NAME_SET: ReadonlySet<string> = new Set<string>(DOCK_ICON_NAMES);\n\n/* ── Content model fields ────────────────────────────────────────────── */\nexport type ProdFieldType =\n | \"text\" | \"richtext\" | \"document\" | \"image\" | \"boolean\" | \"number\" | \"select\"\n | \"reference\" | \"multi-reference\" | \"multiReference\" | \"array\" | \"date\" | \"datetime\"\n | \"longtext\" | \"slug\" | \"email\" | \"phone\" | \"link\" | \"color\" | \"json\" | \"file\"\n | \"component-ref\" | \"modular\" | \"sections\" | \"location\" | \"button\" | \"multiselect\" | \"icon\" | \"object\"\n | \"tags\" | \"rating\" | \"code\"\n /** V2 video: a URL string or `{ url, poster?, autoplay?, loop?, transcript? }` (VideoValue). */\n | \"video\"\n /** Legacy input only: normalized to `array` + zones on write, still read. */\n | \"group\" | \"repeater\";\n\nexport type OpenMode = \"inline\" | \"drill\" | \"popover\" | \"dialog\";\n/** backend SHOW_IF_OPS (validation/schemas/content.ts). */\nexport type ShowIfOp = \"eq\" | \"neq\" | \"in\" | \"notIn\" | \"gt\" | \"lt\" | \"isSet\" | \"notEmpty\" | \"empty\";\nexport interface ShowIfRule {\n field: string;\n op: ShowIfOp;\n value?: string | string[];\n}\nexport interface ShowIf {\n match: \"all\" | \"any\";\n rules: ShowIfRule[];\n}\n\nexport type UiLayout = \"list\" | \"grid\" | \"table\" | \"rows\" | \"chips\" | \"gallery\";\n/** ui.control (UI_CONTROLS): the leaf controls, the V2 control layouts among them. */\nexport const UI_CONTROLS = [\"segmented\", \"slider\", \"rating\", \"dropdown\", \"radio\", \"cards\", \"grid\", \"switch\", \"checkbox\"] as const;\nexport type UiControl = (typeof UI_CONTROLS)[number];\n/** The V2 control layouts and the types each fits (CONTROL_TYPES); segmented / slider / rating have their own rules. */\nexport const CONTROL_TYPES: Readonly<Partial<Record<UiControl, readonly string[]>>> = {\n dropdown: [\"select\"],\n radio: [\"select\"],\n cards: [\"select\", \"multiselect\"],\n grid: [\"select\"],\n switch: [\"boolean\"],\n checkbox: [\"boolean\", \"multiselect\"],\n};\n/** A row preview: child keys or dotted paths (V2), a literal fallback, and an icon shown while there is no media. */\nexport interface UiPreview {\n title?: string;\n subtitle?: string;\n media?: string;\n fallback?: string;\n icon?: DockIconName;\n}\nexport interface FieldUi {\n collapsed?: boolean;\n preview?: UiPreview;\n layout?: UiLayout;\n reorderable?: boolean;\n control?: UiControl;\n icon?: DockIconName;\n itemLabel?: string;\n /** text / longtext: the lines a text box opens with (1–40). */\n rows?: number;\n /** a field's placeholder when its config is strict (a prop keeps its own `placeholder`). */\n placeholder?: string;\n /** a list's item type: its identifier and its title (V2 `of[0].name` / `title`). */\n itemName?: string;\n itemTitle?: string;\n /** the value comes from a global: an edit applies everywhere. */\n synced?: { from: string };\n /** link / image / button: a plain string or the object. */\n valueShape?: \"string\" | \"object\";\n /** V2 field access (D58): the editor gates, the backend stores. */\n access?: { view?: \"schema.view\"; edit?: \"schema.manage\" };\n /** true = never shown in the form; false ≡ absent. */\n hidden?: boolean;\n /** modular: per block slug, how a row of that block type reads (V2 `of[i].icon` / `preview`). */\n blocks?: Record<string, { icon?: DockIconName; preview?: UiPreview }>;\n input?: { name: string; writes?: string[] };\n}\n\nexport type ScaleUnit = \"px\" | \"%\" | \"rem\" | \"em\" | \"vw\" | \"vh\";\nexport interface ScaleCustomValue {\n value: number;\n unit: ScaleUnit;\n}\nexport interface ScaleTokenStep {\n value: string;\n label: string;\n title?: string;\n px?: number;\n css?: string;\n}\nexport type ScaleBound = number | Partial<Record<ScaleUnit, number>>;\n/**\n * A number's `config.scale` (CPO D41): a stepped range, numeric steps or token steps, units, presets, and the custom\n * escape hatch (a boolean, or its bounds). A token scale stores the token string; a custom value `{ value, unit }`.\n */\nexport interface NumberScale {\n steps: { min: number; max: number; step?: number } | Array<{ value: number; label?: string }> | ScaleTokenStep[];\n units?: ScaleUnit[];\n defaultUnit?: ScaleUnit;\n allowCustom?: boolean | { min?: ScaleBound; max?: ScaleBound; units?: ScaleUnit[]; step?: number };\n presets?: Array<{ label?: string; value: number | string | ScaleCustomValue }>;\n}\n\nexport interface ArrayZoneConfig {\n nonRepeatable?: ContentModelField[];\n repeatable?: { fields: ContentModelField[]; minItems?: number; maxItems?: number };\n}\n\n/** One choice: a bare value, or `{ label, value }` with optional chrome (a dock icon, one line ≤ 140 under the label). */\nexport interface ChoiceOption {\n label: string;\n value: string;\n icon?: DockIconName;\n description?: string;\n}\nexport type SelectOption = string | ChoiceOption;\n\n/**\n * A list of scalars' item settings (backend arrayItemSettingsSchema, an `array` prop's `config.item`): the V2 item field's\n * description, locale chip, required, and a text / rich text item's length (a text item's pattern).\n */\nexport interface ArrayItemSettings {\n helpText?: string;\n localized?: boolean;\n required?: boolean;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n patternMessage?: string;\n}\n\n/** The typed keys of a field's `config` bag; the bag itself stays loose on scalar types. */\nexport interface FieldConfig {\n /** primitive array: scalars, or images, links or rich text (each item judged by its own type). */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n zones?: ArrayZoneConfig;\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n /** reference / multi-reference (props): the non-entry targets, and a filter over the target's fields. */\n targets?: (\"page\" | \"form\" | \"collection\")[];\n filter?: string;\n min?: number;\n max?: number;\n step?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n /** text / longtext: the message shown when the pattern does not match (≤ 200, needs `pattern`). */\n patternMessage?: string;\n /** number: the error bounds (V2 validation.min / max); they win over min / max. */\n validation?: { min?: number; max?: number };\n /** number: what it counts (\"%\", \"USD\"), 1–24 characters. */\n unit?: string;\n placeholder?: string;\n includeTime?: boolean;\n /** \"site\", an IANA zone name, true (the editor picks a zone) or false (none). */\n timezone?: string | boolean;\n blockSlugs?: string[];\n minItems?: number;\n maxItems?: number;\n allowedSections?: string[];\n componentIds?: string[];\n /** slot (props): the V2 `of.allow` block names it takes, kept as written (backend slotAllowIssues). */\n allow?: string[];\n /** array (props): the item's own settings (backend arrayItemSettingsSchema). */\n item?: ArrayItemSettings;\n scale?: NumberScale;\n /** multiselect: its choices; with `allowCustom` it is free tags. tags: its suggestions. */\n options?: SelectOption[];\n allowCustom?: boolean;\n /** code: the language, and the languages an editor may pick (strict config, with tags' and rating's). */\n language?: string;\n languages?: string[];\n /**\n * text: \"url\" marks a text field the kit edits as a URL (V2 `url`). The backend keeps a text field's config as sent and\n * enforces its minLength / maxLength / pattern, which a link field would not; it reads no other meaning into the key.\n */\n inputType?: \"url\";\n [key: string]: unknown;\n}\n\nexport interface ContentModelField {\n key: string;\n label: string;\n type: ProdFieldType;\n helpText?: string;\n required?: boolean;\n unique?: boolean;\n defaultValue?: unknown;\n /** select: strings or { label, value }. */\n options?: SelectOption[];\n config?: FieldConfig | null;\n /** object (and legacy group / repeater): child fields. */\n fields?: ContentModelField[];\n openMode?: OpenMode;\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n fieldsetId?: string;\n placement?: \"cover\" | \"title\" | \"excerpt\" | \"body\" | \"inline\" | \"panel\";\n showIf?: ShowIf;\n readOnly?: true | \"developer\";\n lockReason?: string;\n /** V2 per-field localization: once any field is marked, a translation owns only its localized values. */\n localized?: boolean;\n ui?: FieldUi;\n searchable?: boolean;\n [key: string]: unknown;\n}\n\nexport type FieldsetKind = \"group\" | \"row\" | \"tab\";\nexport interface Fieldset {\n id: string;\n name: string;\n description?: string;\n kind?: FieldsetKind;\n icon?: DockIconName;\n collapsed?: boolean;\n tab?: string;\n collapsible?: boolean;\n columns?: 1 | 2;\n layout?: \"stack\" | \"breakpoints\";\n}\n\n/** A content model as the adapters read and write it (server-owned ids and timestamps left out). */\nexport interface ProdContentModel {\n name: string;\n slug: string;\n description?: string;\n kind?: \"model\" | \"block\";\n fields: ContentModelField[];\n fieldsets?: Fieldset[];\n}\n\n/* ── Component props ─────────────────────────────────────────────────── */\nexport const COMPONENT_PROP_TYPES = [\n \"text\", \"richtext\", \"image\", \"url\", \"boolean\", \"number\", \"select\", \"group\", \"table\", \"slot\", \"form\",\n \"link\", \"button\", \"date\", \"color\", \"file\", \"icon\", \"multiselect\",\n \"object\", \"datetime\", \"slug\", \"email\", \"phone\", \"json\", \"location\", \"tags\", \"rating\", \"code\",\n /** an entry id (or `{ entryId, modelSlug }`) and a list of them, hydrated on delivery; no definition default. */\n \"reference\", \"multi-reference\",\n /** a video value, a list of `config.itemType` values, multi-line text. */\n \"video\", \"array\", \"longtext\",\n] as const;\nexport type ComponentPropType = (typeof COMPONENT_PROP_TYPES)[number];\nexport type ComponentSubFieldType = Exclude<ComponentPropType, \"slot\" | \"form\">;\n\nexport const COMPONENT_CATEGORIES = [\n \"navbar\", \"footer\", \"button\", \"section\", \"slider\", \"tabs\", \"form\", \"custom\", \"hero\", \"content\", \"social-proof\", \"conversion\",\n] as const;\nexport type ComponentCategory = (typeof COMPONENT_CATEGORIES)[number];\n\nexport interface PropGroup {\n id: string;\n label?: string;\n kind?: \"group\" | \"row\";\n icon?: DockIconName;\n collapsed?: boolean;\n /** V2 fieldset keys, on the defining prop: a line under the header (≤ 200), side by side, a static header, a\n * breakpoint switcher, and its place among the groups (0–99; absent = where its first prop sits). */\n description?: string;\n columns?: 1 | 2;\n collapsible?: boolean;\n layout?: \"stack\" | \"breakpoints\";\n order?: number;\n}\n/**\n * A top-level prop's tab. Defined once: the first top-level prop with an id carries its label / icon / order, later\n * props carry `{ id }` only. A nested prop names one as `{ id }` only (tab_nested refuses a definition there; V2 and\n * the dock ignore it); one ui.group's members share one tab.\n */\nexport interface PropTab {\n id: string;\n label?: string;\n icon?: DockIconName;\n /** its place among the tabs (0–99; absent = where its first prop sits). */\n order?: number;\n}\nexport type PropUi = FieldUi & { group?: PropGroup; tab?: PropTab };\n\nexport interface ComponentSubField {\n key: string;\n label: string;\n type: ComponentSubFieldType;\n defaultValue?: unknown;\n required?: boolean;\n /** null = no help on purpose (V2 has no description); absent = the platform's auto-help. */\n helpText?: string | null;\n placeholder?: string;\n /** strings or { label, value } (subFieldOptionSchema). */\n options?: SelectOption[];\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** on a table's sub-field: no two rows share it; on a list: no item repeats. */\n unique?: boolean;\n openMode?: OpenMode;\n showIf?: ShowIf;\n /** the prop's ui, inline group included (V2 fieldsets nest). */\n ui?: PropUi;\n readOnly?: true | \"developer\";\n lockReason?: string;\n localized?: boolean;\n fields?: ComponentSubField[];\n config?: { fields?: ComponentSubField[]; options?: SelectOption[] } & Record<string, unknown>;\n}\n\nexport interface ComponentPropDef {\n key: string;\n label: string;\n /**\n * Where the override writes inside the component's blockJson. Binding, not schema: the V2 language has no twin, so\n * fromTypeSchema leaves it unset and the host binds it (componentize lane) before the save.\n */\n target?: { blockId: string; path: string };\n type: ComponentPropType;\n defaultValue?: unknown;\n required?: boolean;\n /** null = no help on purpose (V2 has no description); absent = the platform's auto-help. */\n helpText?: string | null;\n placeholder?: string;\n showIf?: ShowIf;\n helpMore?: string;\n advanced?: boolean;\n recommendedMax?: number;\n /** a list prop's items (a table's rows) distinct; refused on a top-level scalar (unique_prop_scope). */\n unique?: boolean;\n openMode?: OpenMode;\n readOnly?: true | \"developer\";\n lockReason?: string;\n localized?: boolean;\n config?: {\n componentIds?: string[];\n /** slot: the V2 block names it takes (`textBlock`), resolved to the project's components by the dock. */\n allow?: string[];\n /** array: the item's own settings. */\n item?: ArrayItemSettings;\n multiple?: boolean;\n minItems?: number;\n maxItems?: number;\n options?: SelectOption[];\n fields?: ComponentSubField[];\n min?: number;\n max?: number;\n step?: number;\n /** number: the error bounds (they win over min / max). */\n validation?: { min?: number; max?: number };\n /** text / url / longtext / richtext: length (richtext: its plain text). text / url / longtext: a pattern and its message. */\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n patternMessage?: string;\n /** reference / multi-reference: the target model, or polymorphic with an allowlist of model slugs. */\n contentModelId?: string;\n polymorphic?: boolean;\n allowedModelSlugs?: string[];\n /** reference / multi-reference: page / form / collection targets (backend REF_TARGET_KINDS) and a filter over the target's fields. */\n targets?: (\"page\" | \"form\" | \"collection\")[];\n filter?: string;\n /** array: what the list holds. */\n itemType?: \"text\" | \"number\" | \"date\" | \"image\" | \"link\" | \"richtext\";\n /** table with mode \"types\" (a polymorphic list): its item types, each row's `_type` naming one. */\n itemTypes?: { name: string; label?: string; fields: ComponentSubField[]; icon?: DockIconName; preview?: UiPreview }[];\n } & Record<string, unknown>;\n ui?: PropUi;\n}\n\n/** A component as the adapters read and write it. */\n/**\n * How ONE instance of a component reads as a row in a parent's slot list (backend `components.preview`, migration 0459;\n * types ComponentPreview): V2's document-level `preview`. `title` / `subtitle` / `media` each name a TOP-LEVEL prop key\n * (the API refuses any other: preview_key_unknown), `fallback` is the literal row label (trimmed, 1..120), `icon` a dock\n * icon shown while the row has no media.\n */\nexport type ComponentPreview = UiPreview;\n/** backend componentPreviewSchema: a preview slot names a key of at most this many characters */\nexport const COMPONENT_PREVIEW_KEY_MAX = 64;\n/** backend componentPreviewSchema: the row's literal fallback label, trimmed, at most this many characters */\nexport const COMPONENT_PREVIEW_FALLBACK_MAX = 120;\n\nexport interface ProdComponent {\n name: string;\n slug: string;\n description?: string;\n category?: ComponentCategory;\n props: ComponentPropDef[];\n preview?: ComponentPreview | null;\n /** The component's dock icon (backend `components.icon`, dockIconSchema): V2's block icon. */\n icon?: DockIconName | null;\n /** The V2 tabs no top-level prop sits in (backend `components.tabs`, componentTabsSchema): declared, shown by none. */\n tabs?: PropTab[] | null;\n}\n\n/* ── Stored values ───────────────────────────────────────────────────── */\nexport const LINK_RELS = [\"nofollow\", \"sponsored\", \"ugc\"] as const;\nexport type LinkRel = (typeof LINK_RELS)[number];\nexport const LINK_VALUE_TYPES = [\"url\", \"page\", \"entry\", \"email\", \"phone\", \"anchor\", \"section\", \"file\"] as const;\nexport type LinkValueType = (typeof LINK_VALUE_TYPES)[number];\n/** The F1 link object (link-value.ts). A bare href string stays valid too. */\nexport interface ProdLinkValue {\n type?: LinkValueType;\n href: string;\n title?: string;\n newTab?: boolean;\n target?: \"_self\" | \"_blank\";\n rel?: LinkRel;\n section?: string;\n /** page / entry links: the target's id. */\n ref?: string;\n}\n\nexport const BUTTON_VARIANTS = [\"primary\", \"secondary\", \"tertiary\", \"brand\", \"dark\", \"light\", \"outline\", \"link\"] as const;\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\nexport const BUTTON_SIZES = [\"sm\", \"md\", \"lg\"] as const;\n/** One button as one value (button-look.ts ButtonValue). */\nexport interface ProdButtonValue {\n label: string;\n href: string | ProdLinkValue;\n variant?: ButtonVariant;\n size?: (typeof BUTTON_SIZES)[number];\n arrow?: boolean;\n icon?: DockIconName | null;\n newTab?: boolean;\n rel?: LinkRel;\n /** Stretch across the column (backend button_full_width_invalid refuses a non-boolean a write brings). */\n fullWidth?: boolean;\n}\n\n/** 0–1 fractions of the image cut from each edge. */\nexport interface ProdImageCrop {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n/** The normalized image value (field-value-normalize.ts): other keys are dropped on write. */\nexport interface ProdImageValue {\n id?: string;\n url: string;\n name?: string;\n altText?: string;\n /** 0–1 fractions. */\n focal?: { x: number; y: number };\n crop?: ProdImageCrop;\n}\n\n/** The V2 video value's object form (video-value.ts): exactly the video block's props. A bare URL string is valid too. */\nexport const VIDEO_VALUE_KEYS = [\"url\", \"poster\", \"autoplay\", \"loop\", \"transcript\"] as const;\nexport interface ProdVideoValue {\n url: string;\n poster?: string;\n autoplay?: boolean;\n loop?: boolean;\n transcript?: string;\n}\n\n/** A polymorphic reference value. */\nexport interface ProdPolymorphicRef {\n entryId: string;\n modelSlug: string;\n}\n/**\n * A page, form or collection pick on a prop reference that also takes entries (backend reference-target-config.ts\n * targetRefOf): a bare string there is read as an entry id (acceptsEntries), so a non-entry pick names its kind.\n */\nexport interface ProdTargetRef {\n kind: \"page\" | \"form\" | \"collection\";\n id: string;\n}\n/** What a `form` prop stores. */\nexport interface ProdFormRef {\n formId: string;\n}\n"],"mappings":"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"}
@@ -1,9 +1,10 @@
1
1
  import { CATALOG, FEATURES, isHostConfigKey } from "./lossy.js";
2
- import { CONTROL_TYPES, HELP_MORE_MAX, ITEM_NAME_RE, UI_CONTROLS } from "./prod-types.js";
2
+ import { CONTROL_TYPES, FIELDSET_DESCRIPTION_MAX, FIELD_HELP_MAX, HELP_MORE_MAX, ITEM_NAME_RE, MAX_FIELD_DEPTH, OPTION_DESCRIPTION_MAX, PROP_GROUP_DESCRIPTION_MAX, PROP_HELP_MAX, PROP_PLACEHOLDER_MAX, PROP_TAB_MAX, TAB_MAX as TAB_MAX$1, UI_CONTROLS, UI_PLACEHOLDER_MAX } from "./prod-types.js";
3
3
  import { dockIconOf, tablerIconOf } from "./icons.js";
4
4
  import { slotChildrenFromStored, slotChildrenToStored } from "../controls/slot-services.js";
5
5
  import { isDataTableProp, tableConfigFromOptions, tableOptionsFromConfig } from "../controls/table/prod.js";
6
6
  import { buttonFromProd, buttonToProd, datetimeFromProd, datetimeToProd, imageFromProd, imageToProd, isCropRect, linkFromProd, linkToProd, listFromProd, listToProd, ratingFromProd, ratingToProd, referenceFromProd, referenceToProd, scaleFromProd, scaleToProd, typedRowsFromProd, typedRowsToProd, videoFromProd, videoToProd, zoneListFromProd, zoneListToProd } from "./values.js";
7
+ import { BLOCK_FIELD_TYPES_RENDERABLE_NOW, KEY_FORMAT, PRIMITIVE_ARRAY_RULE, RICHTEXT_FEATURES, isReservedKey, normaliseRichTextFeatures } from "@bettercms-ai/types";
7
8
  //#region src/adapters/schema.ts
8
9
  var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
9
10
  function deepEqual(a, b) {
@@ -182,24 +183,8 @@ var CATEGORY_TO_PROD = {
182
183
  Content: "content",
183
184
  Layout: "section"
184
185
  };
185
- /** The field types a kind:'block' model may hold (backend block-model-mapping.ts FIELD_PRIMITIVE). */
186
- var BLOCK_FIELD_TYPES = /* @__PURE__ */ new Set([
187
- "text",
188
- "longtext",
189
- "richtext",
190
- "image",
191
- "link",
192
- "slug",
193
- "email",
194
- "phone",
195
- "color",
196
- "select",
197
- "number",
198
- "rating",
199
- "date",
200
- "datetime",
201
- "boolean"
202
- ]);
186
+ /** The field types a kind:'block' model holds today: the ones a block primitive renders (types, staged to G7). */
187
+ var BLOCK_FIELD_TYPES = new Set(BLOCK_FIELD_TYPES_RENDERABLE_NOW);
203
188
  /** A slot prop's config.minItems / maxItems cap (SLOT_ITEMS_CAP, componentPropDefSchema). */
204
189
  var SLOT_ITEMS_CAP = 50;
205
190
  /** A table prop's rows and an array prop's items: their config.minItems / maxItems cap (LIST_ITEMS_CAP). */
@@ -358,23 +343,24 @@ function shapeOf(f, lv, ctx, top, nest) {
358
343
  };
359
344
  return shape;
360
345
  }
361
- /** backend content.ts keyRuleProblem: keys a resolver would misread (KEY_RESERVED), and a key's format (KEY_FORMAT). */
362
- var MODEL_RESERVED_KEYS = /* @__PURE__ */ new Set([
363
- "derived",
364
- "layout",
365
- "page"
366
- ]);
367
- /** The key a model field is stored under: a reserved or malformed V2 name, renamed. */
346
+ /**
347
+ * The key a model field is stored under: a V2 name the API refuses (types' isReservedKey, the API lane: `derived`,
348
+ * `layout`, `page`, a forbidden key or a leading `_`; or one off KEY_FORMAT), renamed. V2 authoring follows the API
349
+ * lane, so `id` is a field key like any other (only the derive lane, which mints keys, reserves it).
350
+ */
368
351
  function modelKeyOf(name) {
352
+ if (KEY_FORMAT.test(name) && !isReservedKey(name)) return name;
369
353
  let k = name.replace(/^_+/, "").replace(/[^A-Za-z0-9_-]/g, "");
370
354
  if (!/^[A-Za-z]/.test(k)) k = `f${k}`;
371
- return MODEL_RESERVED_KEYS.has(k) ? `${k}Field` : k;
355
+ return isReservedKey(k) ? `${k}Field` : k;
372
356
  }
357
+ /** The config keys a model's primitive list holds (types' PRIMITIVE_ARRAY_RULE). */
358
+ var MODEL_LIST_KEYS = new Set(PRIMITIVE_ARRAY_RULE.configKeys);
373
359
  /** A slot's V2 allow list as the backend keeps it: 1–50 distinct block names of 1–64 characters (slotAllowIssues). */
374
360
  var slotAllowOk = (allow) => Array.isArray(allow) && allow.length >= 1 && allow.length <= SLOT_ALLOW_MAX && new Set(allow).size === allow.length && allow.every((n) => typeof n === "string" && n === n.trim() && n.length >= 1 && n.length <= SLOT_ALLOW_NAME_MAX);
375
361
  function shapeOfField(f, lv, ctx, top) {
376
362
  const props = ctx.lane === "props";
377
- const deep = lv >= 10;
363
+ const deep = lv >= MAX_FIELD_DEPTH;
378
364
  const of = Array.isArray(f.of) ? f.of : void 0;
379
365
  /** a prop reference names a content model or a page / form / collection target (refTargetNamed): with none it is stored as json */
380
366
  const noEntry = (r) => props && !(r?.to ?? []).some((t) => ENTRY_TARGET(t) || REF_TARGET_KINDS.includes(t));
@@ -498,6 +484,36 @@ var trunc = (ctx, at, s, max, feature) => {
498
484
  lose(ctx, at, feature);
499
485
  return s.slice(0, max);
500
486
  };
487
+ /** The prod field types that store a rich text and its features (config.features). */
488
+ var RICH_TYPES = /* @__PURE__ */ new Set(["richtext", "document"]);
489
+ /** Every feature, canonical: RICHTEXT_FEATURES through normaliseRichTextFeatures, so no alias is ever in it. */
490
+ var ALL_RICH_FEATURES = normaliseRichTextFeatures(RICHTEXT_FEATURES).features;
491
+ /**
492
+ * A rich text's features through types normaliseRichTextFeatures (its aliases expand there: `headings` is h1–h6), distinct,
493
+ * in the order given. `named`: something was not carried (a name outside RICHTEXT_FEATURES, a repeat, a non-list).
494
+ */
495
+ /** A content model's id, as the backend's config.references rule reads one. */
496
+ var MODEL_ID = /^[A-Za-z0-9_-]{1,64}$/;
497
+ /** A rich text's references: posts and authors, each a model id; `named` when anything else was there. */
498
+ function richRefs(v) {
499
+ if (!v || typeof v !== "object" || Array.isArray(v)) return { named: true };
500
+ const r = v;
501
+ const kept = {};
502
+ for (const k of ["posts", "authors"]) if (typeof r[k] === "string" && MODEL_ID.test(r[k])) kept[k] = r[k];
503
+ const named = Object.keys(r).some((k) => k !== "posts" && k !== "authors" || r[k] !== void 0 && kept[k] === void 0);
504
+ return {
505
+ kept: Object.keys(kept).length ? kept : void 0,
506
+ named
507
+ };
508
+ }
509
+ function richFeatures(v) {
510
+ const names = Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
511
+ const { features, unknown } = normaliseRichTextFeatures(names);
512
+ return {
513
+ kept: [...new Set(features)],
514
+ named: !Array.isArray(v) || names.length !== v.length || new Set(names).size !== names.length || unknown.length > 0
515
+ };
516
+ }
501
517
  function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = false, inSetting = false) {
502
518
  const props = ctx.lane === "props";
503
519
  const shape = shapeOf(f, lv, ctx, top, inTable ? "rows" : inItem ? "item" : inSetting ? "setting" : void 0);
@@ -554,15 +570,15 @@ function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = f
554
570
  case "title":
555
571
  case "type": break;
556
572
  case "description":
557
- node.helpText = trunc(ctx, p, f.description, props ? 200 : 500, "help>limit");
573
+ node.helpText = trunc(ctx, p, f.description, props ? PROP_HELP_MAX : FIELD_HELP_MAX, "help>limit");
558
574
  break;
559
575
  case "helpMore":
560
576
  node.helpMore = trunc(ctx, p, f.helpMore, HELP_MORE_MAX, "help>limit");
561
577
  break;
562
578
  case "placeholder":
563
- if (props) node.placeholder = trunc(ctx, p, f.placeholder, 120, "help>limit");
579
+ if (props) node.placeholder = trunc(ctx, p, f.placeholder, PROP_PLACEHOLDER_MAX, "help>limit");
564
580
  else if (looseConfig) node.placeholder = f.placeholder;
565
- else node.ui.placeholder = trunc(ctx, p, f.placeholder, 120, "help>limit");
581
+ else node.ui.placeholder = trunc(ctx, p, f.placeholder, UI_PLACEHOLDER_MAX, "help>limit");
566
582
  break;
567
583
  case "initialValue":
568
584
  if (props && (shape.type === "reference" || shape.type === "multi-reference" || shape.kind === "slot")) cat(ctx, p, "seeded instance");
@@ -703,10 +719,27 @@ function convertField(f, at, lv, ctx, siblings, top, inTable = false, inItem = f
703
719
  if (shape.kind === "leaf" && shape.type === "table") Object.assign(node.config, tableConfigFromOptions(f.table));
704
720
  else lose(ctx, p, "type:table");
705
721
  break;
722
+ case "references":
723
+ if (!RICH_TYPES.has(shape.type)) lose(ctx, p, "unsupported key");
724
+ else {
725
+ const { kept, named } = richRefs(f.references);
726
+ if (named) lose(ctx, p, "richtext references");
727
+ if (kept) node.config.references = kept;
728
+ }
729
+ break;
730
+ case "features":
731
+ if (!RICH_TYPES.has(shape.type)) lose(ctx, p, "unsupported key");
732
+ else {
733
+ const { kept, named } = richFeatures(f.features);
734
+ if (named) lose(ctx, p, "richtext features");
735
+ node.config.features = kept;
736
+ }
737
+ break;
706
738
  default: lose(ctx, p, "unsupported key");
707
739
  }
708
740
  }
709
741
  if (props && f.description === void 0) node.helpText = null;
742
+ if (RICH_TYPES.has(shape.type) && shape.kind === "leaf" && f.features === void 0) node.config.features = [...ALL_RICH_FEATURES];
710
743
  if (f.itemNoun === void 0 && shape.kind === "zones" && node.ui.itemLabel !== void 0) cat(ctx, `${at}/itemNoun`, "itemNoun (derived)");
711
744
  placeInSet(f, node, at, ctx, top, siblings);
712
745
  if (f.type === "rating" && node.type === "rating" && f.numeric?.step === void 0) {
@@ -787,7 +820,7 @@ function propGroupOf(s, ctx) {
787
820
  if (ctx.groupOrder) g.order = Math.min(99, ctx.propOrder.get(s.name) ?? 0);
788
821
  return g;
789
822
  }
790
- var groupDescriptionOk = (d) => typeof d === "string" && d === d.trim() && d.length >= 1 && d.length <= 200;
823
+ var groupDescriptionOk = (d) => typeof d === "string" && d === d.trim() && d.length >= 1 && d.length <= PROP_GROUP_DESCRIPTION_MAX;
791
824
  /** The zone a datetime field fixes, if any (what lets a stored instant read back with its [Zone]). */
792
825
  var fixedZone = (f) => typeof f.timezone === "string" && f.timezone.startsWith("fixed:") ? f.timezone.slice(6) : void 0;
793
826
  /**
@@ -1226,7 +1259,7 @@ function optionsToProd(f, shape, node, at, ctx) {
1226
1259
  }
1227
1260
  const d = o.description;
1228
1261
  if (d !== void 0) {
1229
- if (typeof d === "string" && d.trim() !== "" && !/[\r\n]/.test(d) && d.length <= 140) out.description = d;
1262
+ if (typeof d === "string" && d.trim() !== "" && !/[\r\n]/.test(d) && d.length <= OPTION_DESCRIPTION_MAX) out.description = d;
1230
1263
  else lose(ctx, `${at}/${i}/description`, "option description");
1231
1264
  }
1232
1265
  for (const k of Object.keys(o)) if (![
@@ -1435,7 +1468,7 @@ function ofToProd(f, shape, node, at, lv, ctx) {
1435
1468
  if (shape.kind === "itemType") node.config.itemType = shape.itemType;
1436
1469
  itemIdentity(item, conventionItem(f.name, f.title), node, ip, ctx);
1437
1470
  const settings = {};
1438
- const scalars = shape.kind === "itemType" && !shape.shopify && ctx.lane === "props";
1471
+ const scalars = shape.kind === "itemType" && !shape.shopify && (ctx.lane === "props" || MODEL_LIST_KEYS.has("item"));
1439
1472
  for (const k of Object.keys(item)) {
1440
1473
  const v = item[k];
1441
1474
  if (v === void 0) continue;
@@ -1446,7 +1479,7 @@ function ofToProd(f, shape, node, at, lv, ctx) {
1446
1479
  if (shape.kind === "itemType" && item.type === "text") lose(ctx, p, "item settings");
1447
1480
  } else if (k === "reference" && shape.kind === "refs") referenceToConfig(item.reference, node, p, ctx);
1448
1481
  else if (k === "reference" && shape.kind === "itemType" && shape.shopify) continue;
1449
- else if (scalars && k === "description" && typeof v === "string" && v.trim() === v && v.length >= 1 && v.length <= 200) settings.helpText = v;
1482
+ else if (scalars && k === "description" && typeof v === "string" && v.trim() === v && v.length >= 1 && v.length <= PROP_HELP_MAX) settings.helpText = v;
1450
1483
  else if (scalars && k === "localized" && typeof v === "boolean") settings.localized = v;
1451
1484
  else if (scalars && k === "validation") itemValidationToProd(item, shape.itemType, settings, p, ctx);
1452
1485
  else lose(ctx, p, "item settings");
@@ -2021,7 +2054,7 @@ function fieldsetsFor(v2, ctx, out) {
2021
2054
  lose(ctx, p, why);
2022
2055
  };
2023
2056
  if (ctx.tabs.has(g.name) || names.has(folded)) return drop("group name collision");
2024
- if (out.length >= 3) return drop("groups>3");
2057
+ if (out.length >= TAB_MAX$1) return drop("groups>3");
2025
2058
  names.add(folded);
2026
2059
  const tab = {
2027
2060
  id: g.name,
@@ -2066,7 +2099,7 @@ function fieldsetsFor(v2, ctx, out) {
2066
2099
  const v = fs[k];
2067
2100
  if (v === void 0 || k === "name" || k === "title") continue;
2068
2101
  if (k === "description") {
2069
- if (v.length <= 500) set.description = v;
2102
+ if (v.length <= FIELDSET_DESCRIPTION_MAX) set.description = v;
2070
2103
  else lose(ctx, `${p}/${k}`, "help>limit");
2071
2104
  } else if (k === "collapsed" || k === "collapsible" || k === "columns" || k === "layout") set[k] = v;
2072
2105
  else lose(ctx, `${p}/${k}`, "unsupported key");
@@ -2095,7 +2128,7 @@ function propTabsFor(v2, ctx) {
2095
2128
  const label = g.title.slice(0, 40).trim();
2096
2129
  const folded = label.toLowerCase();
2097
2130
  if (kept.some((k) => k.g.name === g.name) || labels.has(folded)) return drop("group name collision");
2098
- if (kept.length >= 8 || g.name.length < 1 || g.name.length > 40) return drop("prop tab limit");
2131
+ if (kept.length >= PROP_TAB_MAX || g.name.length < 1 || g.name.length > 40) return drop("prop tab limit");
2099
2132
  if (!label) return drop("group title");
2100
2133
  labels.add(folded);
2101
2134
  const tab = {
@@ -2198,7 +2231,7 @@ function propSetsFor(v2, ctx) {
2198
2231
  firstSeen.push(f.fieldset);
2199
2232
  if (!named.has(f.fieldset)) undeclared.push(f.fieldset);
2200
2233
  }
2201
- if (lv >= 10) continue;
2234
+ if (lv >= MAX_FIELD_DEPTH) continue;
2202
2235
  const kids = previewKids(f);
2203
2236
  if (kids) visit(kids, lv + 1);
2204
2237
  }
@@ -2562,6 +2595,18 @@ function readToV2(n, at, siblings, ctx, top, lane) {
2562
2595
  const useUi = (...k) => k.forEach((x) => usedUi.add(x));
2563
2596
  if (lane === "props") useUi("group");
2564
2597
  if (lane === "props") useUi("tab");
2598
+ if (RICH_TYPES.has(n.type) && cfg.references !== void 0) {
2599
+ use("references");
2600
+ const { kept, named } = richRefs(cfg.references);
2601
+ if (named) loss("config/references", "richtext references", FEATURES["richtext references"].reason);
2602
+ if (kept) f.references = kept;
2603
+ }
2604
+ if (RICH_TYPES.has(n.type) && cfg.features !== void 0) {
2605
+ use("features");
2606
+ const { kept, named } = richFeatures(cfg.features);
2607
+ if (named) loss("config/features", "richtext features", FEATURES["richtext features"].reason);
2608
+ if (kept.length < ALL_RICH_FEATURES.length) f.features = kept;
2609
+ }
2565
2610
  if ([
2566
2611
  "text",
2567
2612
  "longtext",