@bettercms-ai/kit 2.0.0 → 2.0.1

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 (120) hide show
  1. package/dist/adapters/lossy.d.ts +12 -4
  2. package/dist/adapters/lossy.js +19 -8
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/prod-types.d.ts +46 -14
  5. package/dist/adapters/prod-types.js +37 -35
  6. package/dist/adapters/prod-types.js.map +1 -1
  7. package/dist/adapters/schema.d.ts +39 -0
  8. package/dist/adapters/schema.js +281 -82
  9. package/dist/adapters/schema.js.map +1 -1
  10. package/dist/context.d.ts +39 -0
  11. package/dist/context.js +40 -1
  12. package/dist/context.js.map +1 -1
  13. package/dist/controls/form-picker-register.d.ts +7 -1
  14. package/dist/controls/form-picker-register.js +1 -5
  15. package/dist/controls/form-picker-register.js.map +1 -1
  16. package/dist/controls/icon.d.ts +1 -1
  17. package/dist/controls/icon.js +1 -1
  18. package/dist/controls/icon.js.map +1 -1
  19. package/dist/controls/link.d.ts +11 -4
  20. package/dist/controls/link.js +120 -202
  21. package/dist/controls/link.js.map +1 -1
  22. package/dist/controls/location.js +3 -8
  23. package/dist/controls/location.js.map +1 -1
  24. package/dist/controls/media.d.ts +0 -14
  25. package/dist/controls/media.js +52 -95
  26. package/dist/controls/media.js.map +1 -1
  27. package/dist/controls/reference-services.d.ts +23 -2
  28. package/dist/controls/reference.d.ts +2 -2
  29. package/dist/controls/reference.js +79 -28
  30. package/dist/controls/reference.js.map +1 -1
  31. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  32. package/dist/controls/rich-text/article-shell.js +514 -0
  33. package/dist/controls/rich-text/article-shell.js.map +1 -0
  34. package/dist/controls/rich-text/author.d.ts +25 -0
  35. package/dist/controls/rich-text/author.js +107 -0
  36. package/dist/controls/rich-text/author.js.map +1 -0
  37. package/dist/controls/rich-text/blocks.d.ts +19 -2
  38. package/dist/controls/rich-text/blocks.js +275 -638
  39. package/dist/controls/rich-text/blocks.js.map +1 -1
  40. package/dist/controls/rich-text/button.d.ts +23 -0
  41. package/dist/controls/rich-text/button.js +81 -0
  42. package/dist/controls/rich-text/button.js.map +1 -0
  43. package/dist/controls/rich-text/catalog.d.ts +2 -5
  44. package/dist/controls/rich-text/catalog.js +121 -7
  45. package/dist/controls/rich-text/catalog.js.map +1 -1
  46. package/dist/controls/rich-text/checklist.d.ts +24 -0
  47. package/dist/controls/rich-text/checklist.js +115 -0
  48. package/dist/controls/rich-text/checklist.js.map +1 -0
  49. package/dist/controls/rich-text/codec.d.ts +15 -1
  50. package/dist/controls/rich-text/codec.js +11 -1
  51. package/dist/controls/rich-text/codec.js.map +1 -1
  52. package/dist/controls/rich-text/columns.d.ts +41 -0
  53. package/dist/controls/rich-text/columns.js +181 -0
  54. package/dist/controls/rich-text/columns.js.map +1 -0
  55. package/dist/controls/rich-text/control.js +1 -0
  56. package/dist/controls/rich-text/control.js.map +1 -1
  57. package/dist/controls/rich-text/dom.d.ts +84 -4
  58. package/dist/controls/rich-text/dom.js +171 -10
  59. package/dist/controls/rich-text/dom.js.map +1 -1
  60. package/dist/controls/rich-text/editor.d.ts +4 -2
  61. package/dist/controls/rich-text/editor.js +199 -26
  62. package/dist/controls/rich-text/editor.js.map +1 -1
  63. package/dist/controls/rich-text/embed.d.ts +28 -0
  64. package/dist/controls/rich-text/embed.js +210 -0
  65. package/dist/controls/rich-text/embed.js.map +1 -0
  66. package/dist/controls/rich-text/footnote.d.ts +41 -0
  67. package/dist/controls/rich-text/footnote.js +185 -0
  68. package/dist/controls/rich-text/footnote.js.map +1 -0
  69. package/dist/controls/rich-text/gallery.d.ts +28 -0
  70. package/dist/controls/rich-text/gallery.js +167 -0
  71. package/dist/controls/rich-text/gallery.js.map +1 -0
  72. package/dist/controls/rich-text/link-form.d.ts +13 -1
  73. package/dist/controls/rich-text/link-form.js +41 -7
  74. package/dist/controls/rich-text/link-form.js.map +1 -1
  75. package/dist/controls/rich-text/ops.js +6 -0
  76. package/dist/controls/rich-text/ops.js.map +1 -1
  77. package/dist/controls/rich-text/related.d.ts +49 -0
  78. package/dist/controls/rich-text/related.js +233 -0
  79. package/dist/controls/rich-text/related.js.map +1 -0
  80. package/dist/controls/rich-text/toc.d.ts +47 -0
  81. package/dist/controls/rich-text/toc.js +160 -0
  82. package/dist/controls/rich-text/toc.js.map +1 -0
  83. package/dist/controls/slot-register.d.ts +6 -1
  84. package/dist/controls/slot-register.js +1 -4
  85. package/dist/controls/slot-register.js.map +1 -1
  86. package/dist/core/core.d.ts +11 -3
  87. package/dist/core/core.js +24 -6
  88. package/dist/core/core.js.map +1 -1
  89. package/dist/core/facets.d.ts +16 -0
  90. package/dist/core/facets.js +17 -1
  91. package/dist/core/facets.js.map +1 -1
  92. package/dist/core/index.js +2 -2
  93. package/dist/index.js +16 -5
  94. package/dist/index.js.map +1 -1
  95. package/dist/ledgers/exclusions.v1.js +141 -0
  96. package/dist/ledgers/exclusions.v1.js.map +1 -0
  97. package/dist/library/coverage.d.ts +13 -1
  98. package/dist/library/coverage.js +12 -1
  99. package/dist/library/coverage.js.map +1 -1
  100. package/dist/library/kit-catalog.json +156 -153
  101. package/dist/schema/types.d.ts +17 -0
  102. package/dist/schema/types.js.map +1 -1
  103. package/dist/styles.css +1 -1
  104. package/dist/testing/coverage-extras.d.ts +8 -0
  105. package/dist/testing/coverage-extras.js +44 -0
  106. package/dist/testing/coverage-extras.js.map +1 -0
  107. package/dist/testing/exclusions.d.ts +30 -0
  108. package/dist/testing/exclusions.js +13 -0
  109. package/dist/testing/exclusions.js.map +1 -0
  110. package/dist/ui/autocomplete.d.ts +29 -1
  111. package/dist/ui/autocomplete.js +102 -47
  112. package/dist/ui/autocomplete.js.map +1 -1
  113. package/dist/ui/button.js +3 -5
  114. package/dist/ui/button.js.map +1 -1
  115. package/dist/ui/index.js +2 -2
  116. package/dist/ui/overlay.d.ts +4 -1
  117. package/dist/ui/overlay.js +2 -1
  118. package/dist/ui/overlay.js.map +1 -1
  119. package/dist/ui/toast.js +1 -1
  120. package/package.json +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","names":[],"sources":["../../src/controls/media.tsx"],"sourcesContent":["/**\n * MEDIA — image · gallery · file · video (V2 HEAD 9829bf1 kit/controls/media.tsx, DESIGN.md 8.15).\n *\n * Production parity: dashed drop well (\"Add an image / Or drop or paste one here\"), filled 16:9 preview with Replace and\n * Remove pills, the caption \"{file} · W × H · No alt text\" and a ⋯ whose \"Alt text and details\" opens a popover (alt\n * text, focal point, file name). The media library picker, the upload and the asset metadata are KitServices\n * (media-services.ts): the kit never imports a feature, and a missing service is named in words, never faked.\n *\n * Kit deviations from V2, each because of what the backend stores (adapters/values.ts):\n * - \"Crop for this placement\" is V2's five-crop dropdown, stored as the rect prod keeps (cut from the picture's own size,\n * centred on the focal point); a stored rect reads back as its preset when the size is known, and is kept as it is\n * otherwise. With no size yet, the dropdown waits, and says why;\n * - a picked asset's width / height / size are read for the caption, never written into the value (prod rebuilds the\n * value from url, id, name, altText and focal; the rest would be refused);\n * - where the host stores the URL string only (`imageStoresUrl`, the dock's top-level image props) the value stays a\n * string, and alt text and focal point are the media library's (said in the details popover);\n * - no built-in demo picker, no simulated upload, no stock poster frames;\n * - the gallery sorts with the engine's `useDragReorder` (@dnd-kit is not on the kit allow-list);\n * - a typed video URL is held as a draft until it is one prod stores (http(s) or a site path), so the dock never\n * refuses a half-typed address.\n */\nimport * as React from \"react\";\nimport {\n IconAlertTriangle,\n IconCrop,\n IconDots,\n IconDownload,\n IconExternalLink,\n IconFileText,\n IconFocusCentered,\n IconLink,\n IconPhoto,\n IconPlayerPlay,\n IconPlus,\n IconRefresh,\n IconReplace,\n IconTrash,\n IconUpload,\n IconVideo,\n IconWorld,\n IconX,\n} from \"@tabler/icons-react\";\nimport type {} from \"./media-services\";\nimport { Button, IconButton } from \"../ui/button\";\nimport { Input, Textarea } from \"../ui/input\";\nimport { Progress } from \"../ui/controls\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from \"../ui/overlay\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { useDragReorder } from \"../engine/item-list\";\nimport { RowChrome } from \"../engine/bits\";\nimport { Select } from \"../ui/select\";\nimport { cropPreset, cropRect, isCropRect, type V2ImageCrop } from \"../adapters/values\";\nimport type { ProdImageCrop } from \"../adapters/prod-types\";\nimport { useKitEnv, useKitServices, type KitMediaAsset, type KitServices, type KitSiteIcon } from \"../context\";\nimport type { ControlProps } from \"../types\";\nimport { isIconImage } from \"../lib/icon-image\";\n\n/* ── Values ─────────────────────────────────────────────────────────── */\n/** The image value the kit edits (V2 ImageValue, minus what prod cannot store: caption, width, height, size). */\nexport interface ImageValue {\n url: string;\n alt?: string;\n /** percent */\n focal?: { x: number; y: number };\n /** This placement's crop, as prod stores it (0–1 edges of the picture). Absent: the whole picture. */\n crop?: ProdImageCrop | V2ImageCrop;\n name?: string;\n id?: string;\n [key: string]: unknown;\n}\n\nexport const fileNameFromUrl = (url: string) => {\n // An inline (data:) image has no file and no host. It was labelled \"Uploaded image\", which is false for most of\n // them: a fresh Image block's 800 × 600 stand-in is one, and nobody uploaded it. Its source is named by what the\n // URI does carry, its type: \"Embedded SVG image\".\n const inline = /^data:image\\/([a-z0-9.+-]+)/i.exec(url.trim());\n if (inline) return `Embedded ${inline[1].replace(/\\+xml$/i, \"\").replace(/^jpeg$/i, \"jpg\").toUpperCase()} image`;\n // V2 `lib/image-edit.ts` fileNameFromUrl: the last path segment that has an extension, else \"Image from <host>\". A\n // URL with no file in it (picsum's `/800/600`) printed its last segment (\"600\") as the name.\n try {\n const u = new URL(url, typeof window === \"undefined\" ? \"https://x.invalid\" : window.location.href);\n if (u.protocol === \"data:\" || u.protocol === \"blob:\") return \"Image\";\n const file = u.pathname.split(\"/\").filter(Boolean).reverse().find((x) => /\\.[a-z0-9]{2,5}$/i.test(x));\n return file ? decodeURIComponent(file) : `Image from ${u.hostname.replace(/^www\\./, \"\")}`;\n } catch {\n return \"Image\";\n }\n};\n\nexport const normImage = (v: unknown): ImageValue | null => {\n if (typeof v === \"string\") return v ? { url: v } : null;\n return isObj(v) && typeof v.url === \"string\" && v.url ? (v as ImageValue) : null;\n};\n\n/** What an asset becomes in a value: the keys prod keeps (url, id, name, alt), nothing measured. */\nexport const fromAsset = (a: KitMediaAsset): ImageValue => {\n // an icon picked from the site by its url alone has no asset id\n const out: ImageValue = a.id ? { url: a.url, id: a.id } : { url: a.url };\n if (a.name) out.name = a.name;\n if (a.alt) out.alt = a.alt;\n return out;\n};\n\nexport const formatBytes = (n: number) => (n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)} MB` : `${Math.max(1, Math.round(n / 1000))} KB`);\n\nconst HTTP = /^https?:\\/\\/\\S+$/i;\n/** An http(s) URL or a site path: what prod's video value takes (video-value.ts isVideoUrl). */\nexport const isVideoUrl = (s: string) => s === \"\" || HTTP.test(s.trim()) || /^\\/(?!\\/)\\S*$/.test(s.trim());\n\nconst NO_ASSET = () => undefined;\nconst NO_ICONS = (): KitSiteIcon[] => [];\nconst NO_SRC = (u: string) => u;\n\n/** The services the media controls read, each hook stable across renders. */\nfunction useMedia() {\n const s = useKitServices();\n return { s, useAsset: s.useMediaAsset ?? NO_ASSET, src: s.mediaSrc ?? NO_SRC };\n}\n\n/** Files the field takes, by `accept` (an `image/*`, `.pdf`, `*` list). */\nexport function acceptsFile(accept: string, file: Pick<File, \"type\" | \"name\">): boolean {\n return accept.split(\",\").some((raw) => {\n const rule = raw.trim().toLowerCase();\n if (!rule || rule === \"*\" || rule === \"*/*\") return true;\n if (rule.startsWith(\".\")) return file.name.toLowerCase().endsWith(rule);\n if (rule.endsWith(\"/*\")) return file.type.toLowerCase().startsWith(rule.slice(0, -1));\n return file.type.toLowerCase() === rule;\n });\n}\n\n/* ── Picker and upload (services) ─────────────────────────────────────── */\nexport function MediaPicker(p: React.ComponentProps<NonNullable<KitServices[\"MediaPicker\"]>>) {\n const Picker = useKitServices().MediaPicker;\n return Picker ? <Picker {...p} /> : null;\n}\n\n/**\n * Upload through the host's media library: progress while it runs, the assets handed to `onDone`, and a named reason\n * when it fails or a file is the wrong kind. `run` is undefined when the host has no upload service.\n */\nexport function useUpload(accept: string, kind: string, onDone: (a: KitMediaAsset[]) => void) {\n const { uploadMedia, onUploaded, toast } = useKitServices();\n const [progress, setProgress] = React.useState<number | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n const alive = React.useRef(true);\n React.useEffect(\n () => () => {\n alive.current = false;\n },\n [],\n );\n const run = uploadMedia\n ? (files: File[]) => {\n if (!files.length || progress != null) return;\n const bad = files.find((f) => !acceptsFile(accept, f));\n if (bad) {\n setError(`${bad.name || \"That file\"} isn't ${kind === \"file\" ? \"a file this field takes\" : `an ${kind}`}.`);\n return;\n }\n setError(null);\n setProgress(0);\n uploadMedia(files, { onProgress: (f) => alive.current && setProgress(Math.round(Math.min(1, Math.max(0, f)) * 100)) })\n .then((assets) => {\n if (!alive.current) return;\n setProgress(null);\n onUploaded?.(assets);\n onDone(assets);\n toast?.success(files.length > 1 ? `${files.length} files uploaded` : `${assets[0]?.name ?? files[0].name} uploaded`, { description: \"Added to the media library\" });\n })\n .catch((e: unknown) => {\n if (!alive.current) return;\n setProgress(null);\n setError(`Upload failed: ${e instanceof Error ? e.message : String(e)}`);\n });\n }\n : undefined;\n return { progress, error, setError, run };\n}\n\n/** A line under a control that says why something did not happen (role=\"alert\": it is the answer to an action). */\nfunction Reason({ children, tone = \"danger\" }: { children: React.ReactNode; tone?: \"danger\" | \"muted\" }) {\n return (\n <p role={tone === \"danger\" ? \"alert\" : \"note\"} className={cn(\"text-kit-xs\", tone === \"danger\" ? \"text-kit-danger-fg\" : \"text-kit-fg-3\")}>\n {children}\n </p>\n );\n}\n\n/* ── Drop well (drag · paste · upload · library · URL) ─────────────── */\nfunction DropWell({\n id,\n title,\n hint,\n accept,\n multiple,\n icon,\n disabled,\n onFiles,\n onLibrary,\n onUrl,\n refuse,\n progress,\n}: {\n id?: string;\n title: string;\n hint: string;\n accept: string;\n multiple?: boolean;\n icon: React.ReactNode;\n disabled?: boolean;\n /** undefined: the host has no upload service (no Upload button, drop or paste) */\n onFiles?: (f: File[]) => void;\n /** undefined: the host has no media library */\n onLibrary?: () => void;\n onUrl?: (url: string) => void;\n /** set: Media library and Upload stay drawn (V2's well) when the host has no such service, and a click, drop or\n * paste says why through this instead */\n refuse?: (reason: string) => void;\n progress: number | null;\n}) {\n const [over, setOver] = React.useState(false);\n const [urlMode, setUrlMode] = React.useState(false);\n const [url, setUrl] = React.useState(\"\");\n const [urlError, setUrlError] = React.useState<string | null>(null);\n const input = React.useRef<HTMLInputElement>(null);\n const takesFiles = (!!onFiles || !!refuse) && !disabled;\n const files = (f: File[]) => (onFiles ? onFiles(f) : refuse?.(NO_UPLOAD));\n const pickFiles = () => (onFiles ? input.current?.click() : refuse?.(NO_UPLOAD));\n return (\n <div\n id={id}\n tabIndex={disabled ? -1 : 0}\n role=\"group\"\n aria-label={takesFiles ? `${title}. Paste an image or press Enter to upload` : title}\n onPaste={(e) => {\n const pasted = Array.from(e.clipboardData.files);\n if (pasted.length && takesFiles) {\n e.preventDefault();\n files(pasted);\n }\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && e.target === e.currentTarget && takesFiles) {\n e.preventDefault();\n pickFiles();\n }\n }}\n onDragOver={(e) => {\n if (!takesFiles) return;\n e.preventDefault();\n setOver(true);\n }}\n onDragLeave={(e) => {\n // entering a child (the URL button, the input) fires dragleave on the well: only leaving the well clears it\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setOver(false);\n }}\n onDrop={(e) => {\n if (!takesFiles) return;\n e.preventDefault();\n setOver(false);\n files(Array.from(e.dataTransfer.files));\n }}\n data-slot=\"kit-drop-well\"\n className={cn(\n \"relative flex flex-col items-center gap-2.5 rounded-kit-lg border border-dashed px-4 py-5 text-center transition-colors\",\n over ? \"border-kit-accent bg-kit-accent-softer\" : \"border-kit-line-strong bg-kit-subtle hover:border-kit-field-border-hover\",\n )}\n >\n <span className={cn(\"flex size-9 items-center justify-center rounded-kit-lg border border-kit-line bg-kit-control-bg text-kit-fg-3 [&_svg]:size-[18px]\", over && \"text-kit-accent-fg\")}>{icon}</span>\n <div>\n <div className=\"text-kit-sm font-medium text-kit-fg\">{over ? \"Drop to upload\" : title}</div>\n {takesFiles ? <div className=\"text-kit-xs text-kit-fg-3\">{hint}</div> : null}\n </div>\n {urlMode && onUrl ? (\n <>\n <form\n className=\"flex w-full max-w-sm items-center gap-1.5\"\n onSubmit={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const v = url.trim();\n if (HTTP.test(v)) {\n onUrl(v);\n setUrlMode(false);\n setUrl(\"\");\n setUrlError(null);\n } else setUrlError(\"Use a full image URL, like https://…/photo.jpg\");\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n setUrlMode(false);\n setUrlError(null);\n }\n }}\n >\n <Input\n autoFocus\n size=\"sm\"\n value={url}\n aria-label=\"Image URL\"\n aria-invalid={urlError ? true : undefined}\n onChange={(e) => setUrl(e.target.value)}\n placeholder=\"https://…/photo.jpg\"\n leading={<IconLink stroke={1.5} />}\n />\n <Button size=\"sm\" type=\"submit\" variant=\"primary\">\n Add\n </Button>\n </form>\n {/* V2 says this in a toast; the kit says it in place, under the form (a toast service may be absent) */}\n {urlError ? <Reason>{urlError}</Reason> : null}\n </>\n ) : (\n <div className=\"flex flex-wrap justify-center gap-1.5\">\n {onLibrary || refuse ? (\n <Button size=\"sm\" variant=\"secondary\" onClick={onLibrary ?? (() => refuse!(NO_LIBRARY))} disabled={disabled}>\n Media library\n </Button>\n ) : null}\n {onFiles || refuse ? (\n <Button size=\"sm\" variant=\"ghost\" leftIcon={<IconUpload stroke={1.5} />} onClick={pickFiles} disabled={disabled}>\n Upload\n </Button>\n ) : null}\n {onUrl ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setUrlMode(true)} disabled={disabled}>\n Paste URL\n </Button>\n ) : null}\n </div>\n )}\n {onFiles ? (\n <input\n ref={input}\n type=\"file\"\n hidden\n tabIndex={-1}\n aria-hidden\n accept={accept}\n multiple={multiple}\n onChange={(e) => {\n onFiles(Array.from(e.target.files ?? []));\n e.target.value = \"\";\n }}\n />\n ) : null}\n {progress != null ? (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 rounded-kit-lg bg-kit-surface px-8\">\n <span className=\"text-kit-sm text-kit-fg-2\">\n <span role=\"status\">Uploading…</span> {progress}%\n </span>\n <Progress value={progress} tone=\"ink\" label=\"Upload progress\" className=\"max-w-56\" />\n </div>\n ) : null}\n </div>\n );\n}\n\n/** Why the drop well offers nothing to pick with (no library, no upload): said once, in words. */\nconst NO_SOURCE = \"No media library or upload is connected to this editor, so nothing can be chosen here.\";\nconst NO_LIBRARY = \"No media library is connected to this editor, so nothing can be picked from it here.\";\nconst NO_UPLOAD = \"No upload is connected to this editor, so files can't be uploaded here.\";\n\n/* ── Image ─────────────────────────────────────────────────────────── */\n/** Transparency checker on the kit tokens (white in light, dimmed in dark), as the media grid draws it. */\nconst CHECKER =\n \"bg-kit-checker-a [background-image:conic-gradient(var(--kit-checker-b)_25%,var(--kit-checker-a)_0_50%,var(--kit-checker-b)_0_75%,var(--kit-checker-a)_0)] [background-size:12px_12px]\";\n\n/** The preview frame's shape bounds: a tall or panoramic picture never makes the dock tall or a sliver. */\nconst FRAME_MIN = 1;\nconst FRAME_MAX = 2;\n\n/**\n * How a preview frames a picture of any shape: the frame follows the picture's ratio between square and 2:1, and the\n * picture fits inside it WHOLE, filling the frame's width or height (a portrait is boxed at the sides, a panorama above\n * and below, on the checker). With no known size (still loading, or an SVG with no intrinsic size) the frame is 16:9\n * and the picture is contained. Before 2026-10-16 every picture was cropped to a fixed 16:9 (`object-cover`).\n */\nexport function frameFit(size: { w: number; h: number } | undefined): { frame: number; image: number | null; fill: \"width\" | \"height\" | \"contain\" } {\n if (!size || !(size.w > 0) || !(size.h > 0)) return { frame: 16 / 9, image: null, fill: \"contain\" };\n const image = size.w / size.h;\n const frame = Math.min(FRAME_MAX, Math.max(FRAME_MIN, image));\n return { frame, image, fill: image < frame ? \"height\" : \"width\" };\n}\n\n/** The picture's classes for a fit: it keeps its own ratio and the frame's width or height, never cut. */\nconst FIT_CLASS: Record<ReturnType<typeof frameFit>[\"fill\"], string> = {\n width: \"h-auto max-h-full w-full object-contain\",\n height: \"h-full w-auto max-w-full object-contain\",\n contain: \"size-full object-contain\",\n};\n\n/** V2's five crops (kit media.tsx CROPS, D46). */\nconst CROPS: { value: V2ImageCrop; label: string; ratio: string; description: string }[] = [\n { value: \"original\", label: \"Original\", ratio: \"auto\", description: \"Keep the uploaded shape\" },\n { value: \"16:9\", label: \"16:9\", ratio: \"16/9\", description: \"Widescreen\" },\n { value: \"4:3\", label: \"4:3\", ratio: \"4/3\", description: \"Landscape\" },\n { value: \"1:1\", label: \"1:1\", ratio: \"1/1\", description: \"Square\" },\n { value: \"4:5\", label: \"4:5\", ratio: \"4/5\", description: \"Portrait\" },\n];\nconst CUSTOM_CROP = \"custom\";\n\n/** The crop a value shows: its preset, a stored rect read against the picture's size, or a rect that is none of them. */\nexport function cropChoice(crop: ImageValue[\"crop\"], size?: { w: number; h: number }): V2ImageCrop | typeof CUSTOM_CROP {\n if (!crop) return \"original\";\n if (typeof crop === \"string\") return crop;\n if (!isCropRect(crop)) return \"original\";\n return (size && cropPreset(crop, size.w, size.h)) || CUSTOM_CROP;\n}\n\n/** A custom rect's own shape (its fractions of the picture, in pixels), when the picture's size is known. */\nfunction customRatio(crop: ImageValue[\"crop\"], size?: { w: number; h: number }): string | undefined {\n if (!size || !crop || typeof crop === \"string\" || !isCropRect(crop)) return undefined;\n const w = (1 - crop.left - crop.right) * size.w;\n const h = (1 - crop.top - crop.bottom) * size.h;\n return w > 0 && h > 0 ? String(w / h) : undefined;\n}\n\n/** The value with `choice` cut from the picture (centred on its focal point), or with no crop for Original. */\nexport function withCrop(v: ImageValue, choice: V2ImageCrop, size: { w: number; h: number }): ImageValue {\n const next = { ...v };\n delete next.crop;\n const rect = choice === \"original\" ? undefined : cropRect(choice, size.w, size.h, v.focal);\n if (rect) next.crop = rect;\n return next;\n}\n\nfunction ImageDetails({\n v,\n onChange,\n readOnly,\n label,\n urlOnly,\n altOnly = false,\n size,\n asset,\n}: {\n v: ImageValue;\n onChange: (n: ImageValue) => void;\n readOnly?: boolean;\n label: string;\n urlOnly: boolean;\n /** Only the alt text is kept with this image (`imageAltOnly`). */\n altOnly?: boolean;\n size?: { w: number; h: number };\n asset?: KitMediaAsset;\n}) {\n const { src } = useMedia();\n const focal = v.focal ?? { x: 50, y: 50 };\n const choice = cropChoice(v.crop, size);\n const crop = CROPS.find((c) => c.value === choice);\n // The click pad is the shape the picture is shown in, so a click lands on the subject: a preset crop's shape, a\n // custom rect's, else the picture's own (fitted whole, as the preview). 3:2 only before the size is known.\n const own = choice === \"original\" && size ? frameFit(size) : null;\n const pad = own?.image ? own : null;\n const padRatio =\n crop && crop.ratio !== \"auto\" ? crop.ratio : pad ? String(pad.image) : customRatio(v.crop, size) ?? \"3/2\";\n // A preset crop is cut around the focal point (V2 centres the crop on it): moving the point recuts the window.\n const setFocal = (x: number, y: number) => {\n const next: ImageValue = { ...v, focal: { x: Math.round(Math.min(100, Math.max(0, x))), y: Math.round(Math.min(100, Math.max(0, y))) } };\n onChange(crop && crop.value !== \"original\" && size ? withCrop(next, crop.value, size) : next);\n };\n const fromPointer = (e: React.PointerEvent<HTMLDivElement>) => {\n const r = e.currentTarget.getBoundingClientRect();\n if (!r.width || !r.height) return;\n setFocal(((e.clientX - r.left) / r.width) * 100, ((e.clientY - r.top) / r.height) * 100);\n };\n return (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-kit-sm font-medium text-kit-fg\">Alt text and details</span>\n {size ? (\n <span className=\"tabular-nums text-kit-2xs text-kit-fg-3\">\n {size.w} × {size.h}\n </span>\n ) : null}\n </div>\n {urlOnly ? (\n <>\n <Reason tone=\"muted\">This placement stores the image address only, so its alt text and focal point are the media library's.</Reason>\n {asset?.alt ? (\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-kit-xs text-kit-fg-3\">Alt text in the media library</span>\n <span className=\"text-kit-sm text-kit-fg\">{asset.alt}</span>\n </div>\n ) : null}\n </>\n ) : (\n <>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">Alt text</span>\n <Textarea\n rows={2}\n value={v.alt ?? \"\"}\n readOnly={readOnly}\n onChange={(e) => {\n const alt = e.target.value;\n const next = { ...v };\n if (alt) next.alt = alt;\n else delete next.alt;\n onChange(next);\n }}\n placeholder=\"Describe the image for accessibility\"\n className=\"min-h-14 text-kit-sm\"\n aria-label={`${label} alt text`}\n />\n </label>\n {altOnly ? (\n <Reason tone=\"muted\">This image block keeps its address and alt text. A crop or focal point isn't stored with it.</Reason>\n ) : (\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-1 text-kit-xs text-kit-fg-3\">\n <IconCrop className=\"size-3.5\" stroke={1.5} aria-hidden />\n Crop for this placement\n </span>\n <span className=\"flex items-center gap-1 text-kit-2xs text-kit-fg-3\">\n <IconFocusCentered className=\"size-3\" stroke={1.5} aria-hidden />\n Focal {focal.x}%, {focal.y}%\n </span>\n </div>\n {/* V2 D46: five crops as a dropdown. A crop is cut from the picture's own size, so it waits for it. */}\n <Select\n size=\"sm\"\n aria-label={`${label} crop`}\n disabled={readOnly || !size}\n triggerClassName=\"w-full\"\n value={choice}\n onValueChange={(c) => size && c !== CUSTOM_CROP && onChange(withCrop(v, c as V2ImageCrop, size))}\n options={[\n ...CROPS.map((c) => ({ value: c.value, label: c.label, meta: c.description })),\n ...(choice === CUSTOM_CROP ? [{ value: CUSTOM_CROP, label: \"Custom\", meta: \"Cut elsewhere\", disabled: true }] : []),\n ]}\n />\n {!size && !readOnly ? <span className=\"text-kit-2xs text-kit-fg-3\">The crop is cut from the picture's size, which is still loading.</span> : null}\n <div\n className={cn(pad ? \"mt-1 flex items-center justify-center overflow-hidden rounded-kit-md border border-kit-line\" : \"contents\", pad && CHECKER)}\n style={pad ? { aspectRatio: pad.frame } : undefined}\n >\n <div\n role=\"slider\"\n aria-label=\"Focal point. Click the subject.\"\n aria-valuetext={`${focal.x}% across, ${focal.y}% down`}\n aria-valuenow={focal.x}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-readonly={readOnly || undefined}\n tabIndex={0}\n onPointerDown={(e) => !readOnly && fromPointer(e)}\n onKeyDown={(e) => {\n const d = e.shiftKey ? 10 : 2;\n const m: Record<string, [number, number]> = { ArrowLeft: [-d, 0], ArrowRight: [d, 0], ArrowUp: [0, -d], ArrowDown: [0, d] };\n const step = m[e.key];\n if (!step || readOnly) return;\n e.preventDefault();\n setFocal(focal.x + step[0], focal.y + step[1]);\n }}\n data-pad-ratio={padRatio}\n // V2's pad; inside the AD-FRAMEFIT frame (Original, size known) it is the picture's own box in it\n className={\n pad\n ? cn(\"relative cursor-crosshair overflow-hidden\", pad.fill === \"height\" ? \"h-full\" : \"w-full\")\n : \"relative mt-1 cursor-crosshair overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted\"\n }\n style={{ aspectRatio: padRatio }}\n >\n <img src={src(v.url)} alt=\"\" draggable={false} className=\"pointer-events-none size-full select-none object-cover transition-[object-position] duration-200\" style={{ objectPosition: `${focal.x}% ${focal.y}%` }} />\n <span\n aria-hidden\n className=\"pointer-events-none absolute size-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-kit-media-handle bg-kit-media-handle-ring shadow-kit-md transition-[left,top] duration-150\"\n style={{ left: `${focal.x}%`, top: `${focal.y}%` }}\n />\n </div>\n </div>\n <span className=\"text-kit-2xs text-kit-fg-3\">Click the subject. It stays in frame on every screen size.</span>\n </div>\n )}\n </>\n )}\n {urlOnly || altOnly ? (\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">File name</span>\n <span className=\"truncate font-kit-mono text-kit-xs text-kit-fg\">{asset?.name ?? v.name ?? fileNameFromUrl(v.url)}</span>\n </div>\n ) : (\n // V2: the file name this placement shows, editable (stored as the value's `name`).\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">File name</span>\n <Input\n size=\"sm\"\n value={v.name ?? asset?.name ?? fileNameFromUrl(v.url)}\n readOnly={readOnly}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => {\n const next = { ...v };\n if (e.target.value) next.name = e.target.value;\n else delete next.name;\n onChange(next);\n }}\n className=\"font-kit-mono [&_input]:font-kit-mono\"\n aria-label={`${label} file name`}\n />\n </label>\n )}\n </div>\n );\n}\n\n/** The width × height a stored image value carries (positive numbers only), else undefined. */\nfunction storedSize(value: unknown): { w: number; h: number } | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const { width, height } = value as { width?: unknown; height?: unknown };\n return typeof width === \"number\" && typeof height === \"number\" && width > 0 && height > 0 ? { w: width, h: height } : undefined;\n}\n\n/* ── Icon: an inline-SVG image is one 32px row, not a picture card ─── */\n/**\n * V2's icon control shape (controls/icon.tsx): ONE button — a 24px glyph tile, the field's name, a quiet replace cue —\n * that opens the library. No Replace pill, no ×, no alt text, crop or details: an icon's alt text is \"\" (aria-hidden on\n * the page) and Remove sits in the picker's footer. Empty: a dashed tile, \"Add icon\", and an SVG dropped on it uploads.\n */\nfunction IconImageRow({\n id,\n title,\n url,\n readOnly,\n onOpen,\n onFiles,\n busy,\n pickerOpen,\n}: {\n id: string;\n title: string;\n url?: string;\n readOnly?: boolean;\n onOpen?: () => void;\n onFiles?: (files: File[]) => void;\n busy: boolean;\n pickerOpen: boolean;\n}) {\n const row = React.useRef<HTMLButtonElement>(null);\n const [over, setOver] = React.useState(false);\n // However the picker closes (Escape, Cancel, a pick, Remove), focus comes back to the row that opened it.\n const wasOpen = React.useRef(false);\n React.useEffect(() => {\n if (wasOpen.current && !pickerOpen) row.current?.focus({ preventScroll: true });\n wasOpen.current = pickerOpen;\n }, [pickerOpen]);\n const empty = !url;\n const inert = readOnly || busy || !onOpen;\n const droppable = empty && !inert && !!onFiles;\n // the field's own chrome (comments, presence, the field menu): the shell draws no label row for an icon, so the row\n // carries it at its trailing edge, as NavRow does\n const chrome = React.useContext(RowChrome);\n return (\n <div\n className={cn(\n \"flex h-8 min-w-0 items-center rounded-kit-md border bg-kit-field-bg pointer-coarse:min-h-11\",\n \"transition-colors duration-[120ms] ease-out motion-reduce:transition-none\",\n over ? \"border-kit-emphasis-line bg-kit-hover\" : \"border-kit-line-strong\",\n inert ? \"opacity-60\" : \"[@media(hover:hover)]:hover:bg-kit-hover\",\n )}\n >\n <Tooltip content={title}>\n <button\n ref={row}\n id={id}\n type=\"button\"\n data-slot=\"kit-icon-row\"\n disabled={inert}\n onClick={onOpen}\n aria-label={empty ? `Add icon, ${title}` : `Replace ${title}`}\n onDragOver={droppable ? (e) => { e.preventDefault(); setOver(true); } : undefined}\n onDragLeave={droppable ? () => setOver(false) : undefined}\n onDrop={droppable ? (e) => { e.preventDefault(); setOver(false); onFiles(Array.from(e.dataTransfer.files)); } : undefined}\n className=\"flex min-w-0 flex-1 touch-manipulation items-center gap-3 self-stretch rounded-[5px] pl-[3px] pr-2 text-left text-kit-sm focus-visible:-outline-offset-2 disabled:cursor-not-allowed\"\n >\n <span\n aria-hidden\n className={cn(\n \"grid size-6 shrink-0 place-items-center overflow-hidden rounded-kit-sm border\",\n empty ? \"border-dashed border-kit-emphasis-line\" : cn(\"border-kit-line p-1\", CHECKER),\n )}\n >\n {empty ? <IconPlus className=\"size-3.5 text-kit-fg-3\" stroke={1.5} /> : <img src={url} alt=\"\" className=\"size-full object-contain\" />}\n </span>\n <span aria-hidden className={cn(\"min-w-0 flex-1 truncate\", empty ? \"text-kit-fg-3\" : \"text-kit-fg\")}>\n {empty ? (busy ? \"Uploading…\" : \"Add icon\") : title}\n </span>\n {empty ? null : <IconRefresh aria-hidden className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} />}\n </button>\n </Tooltip>\n {chrome ? <span data-slot=\"kit-icon-row-chrome\" className=\"flex shrink-0 items-center gap-0.5 pr-1 empty:hidden\">{chrome}</span> : null}\n </div>\n );\n}\n\nexport function ImageControl({ field, value, onChange: write, readOnly, id, path }: ControlProps) {\n const { s, useAsset, src } = useMedia();\n const env = useKitEnv();\n const urlOnly = !!s.imageStoresUrl?.(path);\n const altOnly = !urlOnly && !!s.imageAltOnly?.(path);\n const legacyString = typeof value === \"string\" || field.valueShape === \"string\";\n const v = normImage(value);\n const asset = useAsset({ id: v?.id, url: v?.url ?? \"\" });\n // an inline-SVG icon takes SVG files only: a raster there never reaches the page (publish answers svgUnavailable)\n const accept = field.svgOnly ? \"image/svg+xml\" : \"image/*\";\n const kinds: (\"image\" | \"svg\")[] = field.svgOnly ? [\"svg\"] : [\"image\", \"svg\"];\n /*\n * The loaded preview's size, keyed to the URL it was read from. It used to be cleared by an effect on [url], which\n * also ran on MOUNT: a cached picture (the Values popover opened again) finished loading before that effect ran, so\n * the reset wiped the size its load had just set and the caption lost \"· 2400 × 1600\". A picture that is already\n * complete when it mounts is read there too, since its load may have fired before the handler was attached.\n */\n const [loaded, setLoaded] = React.useState<{ url: string; w: number; h: number } | undefined>();\n const natural = loaded && v && loaded.url === v.url ? { w: loaded.w, h: loaded.h } : undefined;\n const readNatural = (img: HTMLImageElement | null) => {\n if (!img || !v || !img.complete || !img.naturalWidth || !img.naturalHeight) return;\n const next = { url: v.url, w: img.naturalWidth, h: img.naturalHeight };\n setLoaded((prev) => (prev && prev.url === next.url && prev.w === next.w && prev.h === next.h ? prev : next));\n };\n // V2's order: the library asset's dimensions, then the ones stored on the value (an imported or retina source keeps\n // its real size there), and only then the loaded preview's natural size (a resized preview reads smaller)\n const stored = storedSize(value);\n const size = asset?.width && asset.height ? { w: asset.width, h: asset.height } : stored ?? natural;\n\n /* the URL-string placements write the URL. Elsewhere a value stored as a URL string becomes V2's object as soon as\n it carries more than the URL (a name, alt text, a focal point or a crop): an older string is still read as is. */\n const onChange = (n: ImageValue | null) => {\n if (!n) return write(urlOnly ? \"\" : null);\n if (urlOnly) return write(n.url);\n if (legacyString && !n.alt && !n.focal && !n.crop && !n.name && !n.id) return write(n.url);\n write(n);\n };\n const [picker, setPicker] = React.useState(false);\n const [details, setDetails] = React.useState(false);\n const up = useUpload(accept, \"image\", (a) => a[0] && onChange(fromAsset(a[0])));\n const library = s.MediaPicker && !readOnly ? () => setPicker(true) : undefined;\n const known = (s.useSiteIcons ?? NO_ICONS)();\n\n if (isIconImage(field, value)) {\n // This field's own icon leads, marked, so the author sees what they are replacing.\n const icons = s.useSiteIcons\n ? [\n ...(v ? [{ url: v.url, value, current: true }] : []),\n ...known.filter((i) => i.url !== v?.url && !(v?.id && i.assetId === v.id)).map(({ url, value: stored }) => ({ url, value: stored })),\n ]\n : undefined;\n const pickIcon = (stored: unknown) => {\n const n = normImage(stored);\n if (n) onChange(fromAsset({ id: n.id ?? \"\", url: n.url, name: n.name, alt: n.alt ?? (typeof n.altText === \"string\" ? n.altText : undefined), kind: \"svg\" }));\n setPicker(false);\n };\n return (\n <div className=\"flex flex-col gap-1.5\">\n <IconImageRow\n id={id}\n title={field.title}\n url={v ? src(v.url) : undefined}\n readOnly={readOnly}\n onOpen={library}\n onFiles={up.run}\n busy={up.progress != null}\n pickerOpen={picker}\n />\n {up.error ? <Reason>{up.error}</Reason> : null}\n {!readOnly && !library ? <Reason tone=\"muted\">{NO_LIBRARY}</Reason> : null}\n <MediaPicker\n open={picker}\n onOpenChange={setPicker}\n accept={[\"svg\"]}\n title={v ? \"Replace icon\" : \"Select an icon\"}\n onPick={(a) => a[0] && onChange(fromAsset(a[0]))}\n onRemove={v && !readOnly ? () => { onChange(null); setPicker(false); } : undefined}\n icons={icons}\n onPickIcon={readOnly ? undefined : pickIcon}\n />\n </div>\n );\n }\n\n if (!v)\n return (\n <div className=\"flex flex-col gap-1.5\">\n <DropWell\n id={id}\n title=\"Add an image\"\n hint=\"Or drop or paste one here\"\n accept={accept}\n icon={<IconPhoto stroke={1.5} />}\n onFiles={up.run}\n onLibrary={library}\n onUrl={readOnly ? undefined : (url) => onChange({ url, name: fileNameFromUrl(url) || undefined })}\n refuse={up.setError}\n disabled={readOnly}\n progress={up.progress}\n />\n {up.error ? <Reason>{up.error}</Reason> : null}\n <MediaPicker open={picker} onOpenChange={setPicker} accept={kinds} onPick={(a) => a[0] && onChange(fromAsset(a[0]))} />\n </div>\n );\n\n const fit = frameFit(size);\n // A raster is never blown up past its own pixels (a 32px icon at the dock's width is a blur); an SVG scales sharp.\n const vector = asset?.kind === \"svg\" || !!field.svgOnly || /\\.svg(?:$|[?#])/i.test(v.url);\n const cap = fit.image && size && !vector ? size : undefined;\n const alt = urlOnly ? asset?.alt : v.alt;\n const name = asset?.name ?? v.name ?? fileNameFromUrl(v.url);\n const replace = (a: KitMediaAsset) => {\n const next = fromAsset(a);\n if (!next.alt && v.alt) next.alt = v.alt;\n if (v.focal) next.focal = v.focal;\n onChange(next);\n };\n const openDetails = () => window.setTimeout(() => setDetails(true), 0);\n return (\n <Popover open={details} onOpenChange={setDetails}>\n <PopoverAnchor\n className={cn(\"flex flex-col gap-1.5\", env.variant === \"document\" && \"max-w-xl\")}\n onPaste={(e: React.ClipboardEvent) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length && up.run && !readOnly) {\n e.preventDefault();\n up.run(files);\n }\n }}\n >\n <div\n data-slot=\"kit-image-frame\"\n data-frame-ratio={String(fit.frame)}\n className={cn(\"group/img relative overflow-hidden rounded-kit-lg border border-kit-line\", CHECKER)}\n style={{ aspectRatio: fit.frame }}\n >\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n onClick={() => (library ? library() : openDetails())}\n aria-label={library ? `Replace ${field.title}` : `${field.title} details`}\n className=\"flex size-full items-center justify-center outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none\"\n >\n <img\n src={src(v.url)}\n alt={alt ?? \"\"}\n ref={readNatural}\n onLoad={(e) => readNatural(e.currentTarget)}\n data-fill={fit.fill}\n data-image-ratio={fit.image ?? undefined}\n data-cap={cap ? `${cap.w}x${cap.h}` : undefined}\n className={FIT_CLASS[fit.fill]}\n style={\n fit.image\n ? { aspectRatio: fit.image, ...(cap ? { maxWidth: `min(100%, ${cap.w}px)`, maxHeight: `min(100%, ${cap.h}px)` } : {}) }\n : undefined\n }\n />\n </button>\n {readOnly ? null : (\n <div className=\"absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity focus-within:opacity-100 group-hover/img:opacity-100 [@media(pointer:coarse)]:opacity-100\">\n {library ? (\n <button type=\"button\" onClick={library} className=\"flex h-7 items-center gap-1 rounded-full border border-kit-swatch-ring bg-kit-media-control px-2.5 text-kit-xs font-medium text-kit-media-control-fg shadow-kit-sm\">\n <IconReplace className=\"size-3.5\" stroke={1.5} aria-hidden />\n Replace\n </button>\n ) : null}\n <Tooltip content=\"Remove image\">\n <button type=\"button\" aria-label=\"Remove image\" onClick={() => onChange(null)} className=\"flex size-7 items-center justify-center rounded-full border border-kit-swatch-ring bg-kit-media-control text-kit-media-control-fg shadow-kit-sm\">\n <IconX className=\"size-3.5\" stroke={1.5} aria-hidden />\n </button>\n </Tooltip>\n </div>\n )}\n {up.progress != null ? (\n <div className=\"absolute inset-x-3 bottom-3\">\n <Progress value={up.progress} tone=\"ink\" size=\"sm\" label=\"Upload progress\" />\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-0 items-center gap-1.5 pl-0.5\">\n <span data-slot=\"kit-image-caption\" className=\"min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3\">\n {name}\n {size ? (\n <>\n {\" · \"}\n <span className=\"tabular-nums\">\n {size.w} × {size.h}\n </span>\n </>\n ) : null}\n {\" · \"}\n {alt ? (\n <span className=\"text-kit-fg-2\">Alt text set</span>\n ) : (\n <span className=\"inline-flex items-center gap-0.5 text-kit-warning-fg\">\n <IconAlertTriangle className=\"size-3\" stroke={1.5} aria-hidden />\n No alt text\n </span>\n )}\n </span>\n <Menu>\n <MenuTrigger\n aria-label=\"Image actions\"\n className=\"flex size-6 shrink-0 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg data-[popup-open]:bg-kit-hover\"\n >\n <IconDots className=\"size-4\" stroke={1.5} aria-hidden />\n </MenuTrigger>\n <MenuContent align=\"end\" className=\"w-52\">\n <MenuItem icon={<IconFocusCentered stroke={1.5} />} onClick={openDetails}>\n Alt text and details\n </MenuItem>\n {/* V2: Replace and Remove are always listed, disabled when they can't act (read-only, or no library) */}\n <MenuItem icon={<IconReplace stroke={1.5} />} disabled={!library} onClick={library}>\n Replace\n </MenuItem>\n <MenuItem icon={<IconExternalLink stroke={1.5} />} onClick={() => window.open(src(v.url), \"_blank\", \"noopener\")}>\n Open original\n </MenuItem>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} disabled={readOnly} onClick={() => !readOnly && onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n </div>\n {up.error ? <Reason>{up.error}</Reason> : null}\n </PopoverAnchor>\n <PopoverContent className=\"w-[320px]\" align=\"start\" side=\"bottom\">\n <ImageDetails v={v} onChange={onChange} readOnly={readOnly} label={field.title} urlOnly={urlOnly} altOnly={altOnly} size={size} asset={asset} />\n </PopoverContent>\n <MediaPicker open={picker} onOpenChange={setPicker} accept={kinds} onPick={(a) => a[0] && replace(a[0])} />\n </Popover>\n );\n}\n\n/* ── Gallery (array of images) ─────────────────────────────────────── */\ntype GItem = { key: string; v: ImageValue; raw: unknown };\n\nfunction Thumb({\n item,\n label,\n readOnly,\n sort,\n onRemove,\n onOpen,\n}: {\n item: GItem;\n label: string;\n readOnly?: boolean;\n sort: ReturnType<typeof useDragReorder>;\n onRemove: () => void;\n onOpen: () => void;\n}) {\n const { src } = useMedia();\n const handle = sort.handle(item.key);\n return (\n <div\n ref={sort.register(item.key)}\n role=\"listitem\"\n style={sort.style(item.key)}\n // V2's thumb; the checker in place of bg-kit-muted is AD-FRAMEFIT\n className={cn(\n \"group/thumb relative aspect-square cursor-grab touch-none overflow-hidden rounded-kit-md border border-kit-line active:cursor-grabbing\",\n CHECKER,\n sort.active === item.key && \"z-10 opacity-90 shadow-kit-lg ring-2 ring-kit-line-strong\",\n )}\n >\n <div\n {...(readOnly ? {} : handle)}\n role={undefined}\n tabIndex={0}\n aria-label={readOnly ? label : `${label}, drag to reorder`}\n onDoubleClick={onOpen}\n onKeyDown={(e) => {\n if (!readOnly && (e.key === \"Delete\" || e.key === \"Backspace\")) {\n e.preventDefault();\n onRemove();\n return;\n }\n if (e.key === \"Enter\") {\n e.preventDefault();\n onOpen();\n return;\n }\n if (!readOnly) handle.onKeyDown(e);\n }}\n className=\"size-full outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none\"\n >\n {/* the whole picture, any shape, on the checker (a cover crop hid a portrait's subject and a logo's edges) */}\n <img src={src(item.v.url)} alt={item.v.alt ?? \"\"} data-slot=\"kit-gallery-thumb\" className=\"pointer-events-none size-full select-none object-contain\" draggable={false} />\n </div>\n {!item.v.alt ? <span role=\"img\" className=\"absolute bottom-1 left-1 size-1.5 rounded-full bg-kit-warning ring-2 ring-kit-surface\" aria-label=\"No alt text\" /> : null}\n {readOnly ? null : (\n <button\n type=\"button\"\n // AD-A11Y-GALLERY: V2's classes, plus a name per picture and a touch-only reveal (no hover on touch)\n aria-label={(() => {\n const what = item.v.alt || item.v.name || fileNameFromUrl(item.v.url);\n return what ? `Remove ${what}` : \"Remove image\";\n })()}\n onPointerDown={(e) => e.stopPropagation()}\n onClick={onRemove}\n className=\"absolute right-1 top-1 flex size-6 items-center justify-center rounded-kit-md bg-kit-inverse/80 text-kit-fg-inverse opacity-0 transition-opacity focus-visible:opacity-100 group-hover/thumb:opacity-100 pointer-coarse:opacity-100\"\n >\n <IconX className=\"size-3.5\" stroke={1.5} aria-hidden />\n </button>\n )}\n </div>\n );\n}\n\n/** An array of images: a sortable grid of tiles with a dashed \"Add images\" tile last (hidden at `max`). */\nexport function GalleryControl({ value, onChange, readOnly, field, id, path }: ControlProps) {\n const { s, src } = useMedia();\n const env = useKitEnv();\n const raw = Array.isArray(value) ? value : [];\n /* a key that survives a move (keyboard reorder refocuses the grip by key); an index suffix only for duplicates */\n const seen = new Map<string, number>();\n const items: GItem[] = raw.map((x) => {\n const v = normImage(x) ?? { url: \"\" };\n const base = v.id ?? v.url;\n const n = seen.get(base) ?? 0;\n seen.set(base, n + 1);\n return { key: n ? `${base}#${n}` : base, v, raw: x };\n });\n /* strings stay strings (a legacy list of URLs); a picked asset joins as the object prod stores */\n const asStrings = raw.length > 0 && raw.every((x) => typeof x === \"string\");\n const out = (v: ImageValue) => (asStrings && !v.alt && !v.focal ? v.url : v);\n const write = (list: unknown[]) => onChange(list);\n const add = (assets: KitMediaAsset[]) => write([...raw, ...assets.map((a) => out(fromAsset(a)))]);\n const [picker, setPicker] = React.useState(false);\n const up = useUpload(\"image/*\", \"image\", add);\n const keys = items.map((it) => it.key);\n const sort = useDragReorder(\n keys,\n (from, to) => {\n const next = [...raw];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n write(next);\n },\n { axis: \"grid\", disabled: readOnly },\n );\n const max = field.validation?.max;\n const canAdd = !readOnly && (max == null || items.length < max) && (s.MediaPicker || up.run);\n const noun = (i: number, it: GItem) => it.v.name ?? (fileNameFromUrl(it.v.url) || `Image ${i + 1}`);\n return (\n <div className=\"flex flex-col gap-2\">\n <div id={id} role=\"list\" aria-label={field.title} className=\"grid grid-cols-3 gap-1.5 @[520px]:grid-cols-5\">\n {items.map((it, i) => (\n <Thumb\n key={it.key}\n item={it}\n label={noun(i, it)}\n readOnly={readOnly}\n sort={sort}\n // the host's image editor where it has one (`editImage`), else the picture itself\n onOpen={() => (s.editImage && !readOnly ? s.editImage({ docId: env.docId, path: [...path, i], title: noun(i, it) }) : window.open(src(it.v.url), \"_blank\", \"noopener\"))}\n onRemove={() => write(raw.filter((_, j) => j !== i))}\n />\n ))}\n {canAdd ? (\n // a real grid cell, not `display: contents`: V2 draws the tile as the grid's own child, and a box-less wrapper\n // would put the tile beside nothing (the Panel walker measures its gap from the thumbs beside it)\n <div role=\"listitem\" className=\"grid\">\n <button\n type=\"button\"\n onClick={() => (s.MediaPicker ? setPicker(true) : up.run && document.getElementById(`${id}-files`)?.click())}\n onPaste={(e) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length && up.run) {\n e.preventDefault();\n up.run(files);\n }\n }}\n onDragOver={(e) => up.run && e.preventDefault()}\n onDrop={(e) => {\n if (!up.run) return;\n e.preventDefault();\n up.run(Array.from(e.dataTransfer.files));\n }}\n className=\"flex aspect-square flex-col items-center justify-center gap-1 rounded-kit-md border border-dashed border-kit-line-strong bg-kit-subtle text-kit-xs text-kit-fg-3 transition-colors hover:border-kit-field-border-hover hover:text-kit-fg\"\n >\n <IconPlus className=\"size-4\" stroke={1.5} aria-hidden />\n Add images\n </button>\n </div>\n ) : null}\n </div>\n {sort.a11y}\n {up.run && !s.MediaPicker ? (\n <input\n id={`${id}-files`}\n type=\"file\"\n hidden\n tabIndex={-1}\n aria-hidden\n accept=\"image/*\"\n multiple\n onChange={(e) => {\n up.run?.(Array.from(e.target.files ?? []));\n e.target.value = \"\";\n }}\n />\n ) : null}\n {up.progress != null ? <Progress value={up.progress} tone=\"ink\" size=\"sm\" label=\"Upload progress\" /> : null}\n {up.error ? <Reason>{up.error}</Reason> : null}\n {!readOnly && !s.MediaPicker && !up.run ? <Reason tone=\"muted\">{NO_SOURCE}</Reason> : null}\n <MediaPicker open={picker} onOpenChange={setPicker} multiple accept={[\"image\", \"svg\"]} onPick={(a) => a.length && add(max != null ? a.slice(0, Math.max(0, max - items.length)) : a)} />\n </div>\n );\n}\n\n/* ── File ──────────────────────────────────────────────────────────── */\n/** A file value prod stores: the same envelope as an image, `{ url, id?, name? }` (or a legacy URL string). */\ntype FileValue = { url: string; id?: string; name?: string; [key: string]: unknown };\nconst normFile = (v: unknown): FileValue | null => {\n if (typeof v === \"string\") return v ? { url: v } : null;\n return isObj(v) && typeof v.url === \"string\" && v.url ? (v as FileValue) : null;\n};\nconst fileFromAsset = (a: KitMediaAsset): FileValue => ({ url: a.url, id: a.id, ...(a.name ? { name: a.name } : {}) });\n\nexport function FileControl({ value, onChange, readOnly, id }: ControlProps) {\n const { s, useAsset, src } = useMedia();\n const v = normFile(value);\n const asset = useAsset({ id: v?.id, url: v?.url ?? \"\" });\n const [picker, setPicker] = React.useState(false);\n const up = useUpload(\"*\", \"file\", (a) => a[0] && onChange(fileFromAsset(a[0])));\n const library = s.MediaPicker && !readOnly ? () => setPicker(true) : undefined;\n const pickerEl = <MediaPicker open={picker} onOpenChange={setPicker} accept={[\"file\"]} onPick={(a) => a[0] && onChange(fileFromAsset(a[0]))} />;\n if (!v)\n return (\n <div className=\"flex flex-col gap-1.5\">\n <DropWell id={id} title=\"Add a file\" hint=\"Or drop or paste one here\" accept=\"*\" icon={<IconFileText stroke={1.5} />} onFiles={up.run} onLibrary={library} refuse={up.setError} disabled={readOnly} progress={up.progress} />\n {up.error ? <Reason>{up.error}</Reason> : null}\n {pickerEl}\n </div>\n );\n const name = asset?.name ?? v.name ?? fileNameFromUrl(v.url);\n const ext = (name.includes(\".\") ? name.split(\".\").pop() : \"\")?.toUpperCase() || \"FILE\";\n const meta = [ext.toLowerCase(), asset?.size ? formatBytes(asset.size) : null].filter(Boolean).join(\" · \");\n return (\n <div className=\"flex items-center gap-3 rounded-kit-lg border border-kit-line bg-kit-control-bg p-2\">\n <span aria-hidden className=\"flex size-14 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle font-kit-mono text-kit-2xs font-medium text-kit-fg-2\">\n {ext}\n </span>\n <div className=\"min-w-0 flex-1\">\n <a id={id} href={src(v.url)} target=\"_blank\" rel=\"noreferrer\" className=\"block truncate text-kit-sm font-medium text-kit-accent-fg hover:underline\">\n {name}\n </a>\n <div className=\"text-kit-xs text-kit-fg-3\">{meta}</div>\n </div>\n {library ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={library}>\n Replace\n </Button>\n ) : null}\n <Menu>\n <MenuTrigger render={<IconButton label=\"File actions\" size=\"sm\" />}>\n <IconDots stroke={1.5} />\n </MenuTrigger>\n <MenuContent align=\"end\">\n <MenuItem icon={<IconDownload stroke={1.5} />} onClick={() => window.open(src(v.url), \"_blank\", \"noopener\")}>\n Open\n </MenuItem>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} disabled={readOnly} onClick={() => !readOnly && onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n {pickerEl}\n </div>\n );\n}\n\n/* ── Video (paste a URL → preview) ─────────────────────────────────── */\nexport const videoProvider = (url: string) =>\n /youtu/.test(url) ? \"YouTube\" : /vimeo/.test(url) ? \"Vimeo\" : /loom/.test(url) ? \"Loom\" : /\\.(mp4|webm|mov)(\\?|$)/i.test(url) ? \"MP4\" : url ? \"Link\" : \"\";\nexport const youTubeId = (url: string) => url.match(/(?:youtu\\.be\\/|v=|embed\\/|shorts\\/)([\\w-]{11})/)?.[1];\nconst isFileVideo = (url: string) => /\\.(mp4|webm|mov)(\\?|$)/i.test(url);\n\nexport function VideoPreview({ url, poster, title }: { url: string; poster?: string; title: string }) {\n const { src } = useMedia();\n const [playing, setPlaying] = React.useState(false);\n React.useEffect(() => setPlaying(false), [url]);\n const yt = youTubeId(url);\n const thumb = poster ? src(poster) : yt ? `https://i.ytimg.com/vi/${yt}/hqdefault.jpg` : undefined;\n if (playing && yt)\n return <iframe title={title} src={`https://www.youtube-nocookie.com/embed/${yt}?autoplay=1`} allow=\"autoplay; encrypted-media\" className=\"aspect-video w-full rounded-kit-lg border border-kit-line\" />;\n if (playing && isFileVideo(url)) return <video src={src(url)} poster={thumb} controls autoPlay className=\"aspect-video w-full rounded-kit-lg border border-kit-line bg-kit-media-backdrop\" />;\n const playable = !!yt || isFileVideo(url);\n return (\n <div className=\"relative aspect-video overflow-hidden rounded-kit-lg border border-kit-line bg-kit-media-backdrop\">\n {thumb ? <img src={thumb} alt={`${title} poster`} className=\"size-full object-cover opacity-85\" /> : null}\n <button\n type=\"button\"\n aria-label={playable ? \"Play preview\" : \"Open video link\"}\n onClick={() => (playable ? setPlaying(true) : window.open(src(url), \"_blank\", \"noopener\"))}\n className=\"absolute inset-0 m-auto flex size-12 items-center justify-center rounded-full bg-kit-media-control text-kit-media-control-fg shadow-kit-lg transition-transform hover:scale-105\"\n >\n {playable ? <IconPlayerPlay className=\"size-5\" stroke={1.5} aria-hidden /> : <IconExternalLink className=\"size-5\" stroke={1.5} aria-hidden />}\n </button>\n <span className=\"absolute left-2 top-2 inline-flex items-center gap-1 rounded-kit-md bg-kit-scrim px-1.5 py-0.5 text-kit-xs text-kit-on-scrim\">\n <IconVideo className=\"size-3.5\" stroke={1.5} aria-hidden />\n {videoProvider(url)}\n </span>\n </div>\n );\n}\n\n/**\n * A URL input with a live preview. The value keeps its stored shape: a URL string stays a string, a `{ url, poster… }`\n * object keeps its other keys. What is typed is a draft until it is an address prod stores (http(s) or a site path);\n * until then the field keeps the saved value and says why under the input.\n */\nexport function VideoControl({ field, value, onChange, readOnly, id, onBlur }: ControlProps) {\n const obj = isObj(value) && typeof value.url === \"string\" ? (value as { url: string; poster?: string }) : null;\n const stored = typeof value === \"string\" ? value : (obj?.url ?? \"\");\n const [draft, setDraft] = React.useState(stored);\n const [touched, setTouched] = React.useState(false);\n React.useEffect(() => setDraft(stored), [stored]);\n const commit = (raw: string) => {\n const url = raw.trim();\n if (url === stored || !isVideoUrl(url)) return;\n if (url === \"\") return onChange(obj ? null : \"\");\n onChange(obj ? { ...obj, url } : url);\n };\n const bad = draft.trim() !== \"\" && !isVideoUrl(draft);\n const errorId = `${id}-error`;\n return (\n <div className=\"flex flex-col gap-2\">\n <Input\n id={id}\n value={draft}\n readOnly={readOnly}\n aria-invalid={bad && touched ? true : undefined}\n aria-describedby={bad && touched ? errorId : undefined}\n onBlur={() => {\n setTouched(true);\n onBlur?.();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\" && draft !== stored) {\n e.stopPropagation();\n setDraft(stored);\n }\n }}\n placeholder=\"Paste a YouTube, Vimeo, Loom or MP4 link\"\n leading={<IconWorld stroke={1.5} />}\n onChange={(e) => {\n setDraft(e.target.value);\n commit(e.target.value);\n }}\n />\n {bad && touched ? (\n <p id={errorId} role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n Not saved: use a full link starting with https://, or a site path starting with /.\n </p>\n ) : null}\n {/* V2 promises \"a poster frame automatically\", which nothing here makes; this note says what is true and, like V2's,\n wraps to two lines at Panel widths (420 and 360) */}\n {stored ? <VideoPreview url={stored} poster={obj?.poster} title={field.title} /> : <p className=\"text-kit-xs text-kit-fg-3\">No video yet. The embed lazy-loads on the page, so it doesn't block the first paint.</p>}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"media.js","names":[],"sources":["../../src/controls/media.tsx"],"sourcesContent":["/**\n * MEDIA — image · gallery · file · video (V2 HEAD 9829bf1 kit/controls/media.tsx, DESIGN.md 8.15).\n *\n * Production parity: dashed drop well (\"Add an image / Or drop or paste one here\"), filled 16:9 preview with Replace and\n * Remove pills, the caption \"{file} · W × H · No alt text\" and a ⋯ whose \"Alt text and details\" opens a popover (alt\n * text, focal point, file name). The media library picker, the upload and the asset metadata are KitServices\n * (media-services.ts): the kit never imports a feature, and a missing service is named in words, never faked.\n *\n * Kit deviations from V2, each because of what the backend stores (adapters/values.ts):\n * - \"Crop for this placement\" is V2's five-crop dropdown, stored as the rect prod keeps (cut from the picture's own size,\n * centred on the focal point); a stored rect reads back as its preset when the size is known, and is kept as it is\n * otherwise. With no size yet, the dropdown waits, and says why;\n * - a picked asset's width / height / size are read for the caption, never written into the value (prod rebuilds the\n * value from url, id, name, altText and focal; the rest would be refused);\n * - where the host stores the URL string only (`imageStoresUrl`, the dock's top-level image props) the value stays a\n * string, and alt text and focal point are the media library's (said in the details popover);\n * - no built-in demo picker, no simulated upload, no stock poster frames;\n * - the gallery sorts with the engine's `useDragReorder` (@dnd-kit is not on the kit allow-list);\n * - a typed video URL is held as a draft until it is one prod stores (http(s) or a site path), so the dock never\n * refuses a half-typed address.\n */\nimport * as React from \"react\";\nimport {\n IconAlertTriangle,\n IconCrop,\n IconDots,\n IconDownload,\n IconExternalLink,\n IconFileText,\n IconFocusCentered,\n IconLink,\n IconPhoto,\n IconPlayerPlay,\n IconPlus,\n IconRefresh,\n IconReplace,\n IconTrash,\n IconUpload,\n IconVideo,\n IconWorld,\n IconX,\n} from \"@tabler/icons-react\";\nimport type {} from \"./media-services\";\nimport { Button, IconButton } from \"../ui/button\";\nimport { Input, Textarea } from \"../ui/input\";\nimport { Progress } from \"../ui/controls\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from \"../ui/overlay\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { useDragReorder } from \"../engine/item-list\";\nimport { RowChrome } from \"../engine/bits\";\nimport { Select } from \"../ui/select\";\nimport { cropPreset, cropRect, isCropRect, type V2ImageCrop } from \"../adapters/values\";\nimport type { ProdImageCrop } from \"../adapters/prod-types\";\nimport { useKitEnv, useKitServices, type KitMediaAsset, type KitServices, type KitSiteIcon } from \"../context\";\nimport type { ControlProps } from \"../types\";\nimport { isIconImage } from \"../lib/icon-image\";\n\n/* ── Values ─────────────────────────────────────────────────────────── */\n/** The image value the kit edits (V2 ImageValue, minus what prod cannot store: caption, width, height, size). */\nexport interface ImageValue {\n url: string;\n alt?: string;\n /** percent */\n focal?: { x: number; y: number };\n /** This placement's crop, as prod stores it (0–1 edges of the picture). Absent: the whole picture. */\n crop?: ProdImageCrop | V2ImageCrop;\n name?: string;\n id?: string;\n [key: string]: unknown;\n}\n\nexport const fileNameFromUrl = (url: string) => {\n // An inline (data:) image has no file and no host. It was labelled \"Uploaded image\", which is false for most of\n // them: a fresh Image block's 800 × 600 stand-in is one, and nobody uploaded it. Its source is named by what the\n // URI does carry, its type: \"Embedded SVG image\".\n const inline = /^data:image\\/([a-z0-9.+-]+)/i.exec(url.trim());\n if (inline) return `Embedded ${inline[1].replace(/\\+xml$/i, \"\").replace(/^jpeg$/i, \"jpg\").toUpperCase()} image`;\n // V2 `lib/image-edit.ts` fileNameFromUrl: the last path segment that has an extension, else \"Image from <host>\". A\n // URL with no file in it (picsum's `/800/600`) printed its last segment (\"600\") as the name.\n try {\n const u = new URL(url, typeof window === \"undefined\" ? \"https://x.invalid\" : window.location.href);\n if (u.protocol === \"data:\" || u.protocol === \"blob:\") return \"Image\";\n const file = u.pathname.split(\"/\").filter(Boolean).reverse().find((x) => /\\.[a-z0-9]{2,5}$/i.test(x));\n return file ? decodeURIComponent(file) : `Image from ${u.hostname.replace(/^www\\./, \"\")}`;\n } catch {\n return \"Image\";\n }\n};\n\nexport const normImage = (v: unknown): ImageValue | null => {\n if (typeof v === \"string\") return v ? { url: v } : null;\n return isObj(v) && typeof v.url === \"string\" && v.url ? (v as ImageValue) : null;\n};\n\n/** What an asset becomes in a value: the keys prod keeps (url, id, name, alt), nothing measured. */\nexport const fromAsset = (a: KitMediaAsset): ImageValue => {\n // an icon picked from the site by its url alone has no asset id\n const out: ImageValue = a.id ? { url: a.url, id: a.id } : { url: a.url };\n if (a.name) out.name = a.name;\n if (a.alt) out.alt = a.alt;\n return out;\n};\n\nexport const formatBytes = (n: number) => (n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)} MB` : `${Math.max(1, Math.round(n / 1000))} KB`);\n\nconst HTTP = /^https?:\\/\\/\\S+$/i;\n/** An http(s) URL or a site path: what prod's video value takes (video-value.ts isVideoUrl). */\nexport const isVideoUrl = (s: string) => s === \"\" || HTTP.test(s.trim()) || /^\\/(?!\\/)\\S*$/.test(s.trim());\n\nconst NO_ASSET = () => undefined;\nconst NO_ICONS = (): KitSiteIcon[] => [];\nconst NO_SRC = (u: string) => u;\n\n/** The services the media controls read, each hook stable across renders. */\nfunction useMedia() {\n const s = useKitServices();\n return { s, useAsset: s.useMediaAsset ?? NO_ASSET, src: s.mediaSrc ?? NO_SRC };\n}\n\n/** Files the field takes, by `accept` (an `image/*`, `.pdf`, `*` list). */\nexport function acceptsFile(accept: string, file: Pick<File, \"type\" | \"name\">): boolean {\n return accept.split(\",\").some((raw) => {\n const rule = raw.trim().toLowerCase();\n if (!rule || rule === \"*\" || rule === \"*/*\") return true;\n if (rule.startsWith(\".\")) return file.name.toLowerCase().endsWith(rule);\n if (rule.endsWith(\"/*\")) return file.type.toLowerCase().startsWith(rule.slice(0, -1));\n return file.type.toLowerCase() === rule;\n });\n}\n\n/* ── Picker and upload (services) ─────────────────────────────────────── */\nexport function MediaPicker(p: React.ComponentProps<NonNullable<KitServices[\"MediaPicker\"]>>) {\n const Picker = useKitServices().MediaPicker;\n return Picker ? <Picker {...p} /> : null;\n}\n\n/**\n * Upload through the host's media library: progress while it runs, the assets handed to `onDone`, and a named reason\n * when it fails or a file is the wrong kind. `run` is undefined when the host has no upload service.\n */\nexport function useUpload(accept: string, kind: string, onDone: (a: KitMediaAsset[]) => void) {\n const { uploadMedia, onUploaded, toast } = useKitServices();\n const [progress, setProgress] = React.useState<number | null>(null);\n const [error, setError] = React.useState<string | null>(null);\n const alive = React.useRef(true);\n React.useEffect(\n () => () => {\n alive.current = false;\n },\n [],\n );\n const run = uploadMedia\n ? (files: File[]) => {\n if (!files.length || progress != null) return;\n const bad = files.find((f) => !acceptsFile(accept, f));\n if (bad) {\n setError(`${bad.name || \"That file\"} isn't ${kind === \"file\" ? \"a file this field takes\" : `an ${kind}`}.`);\n return;\n }\n setError(null);\n setProgress(0);\n uploadMedia(files, { onProgress: (f) => alive.current && setProgress(Math.round(Math.min(1, Math.max(0, f)) * 100)) })\n .then((assets) => {\n if (!alive.current) return;\n setProgress(null);\n onUploaded?.(assets);\n onDone(assets);\n toast?.success(files.length > 1 ? `${files.length} files uploaded` : `${assets[0]?.name ?? files[0].name} uploaded`, { description: \"Added to the media library\" });\n })\n .catch((e: unknown) => {\n if (!alive.current) return;\n setProgress(null);\n setError(`Upload failed: ${e instanceof Error ? e.message : String(e)}`);\n });\n }\n : undefined;\n return { progress, error, setError, run };\n}\n\n/** A line under a control that says why something did not happen (role=\"alert\": it is the answer to an action). */\nfunction Reason({ children, tone = \"danger\" }: { children: React.ReactNode; tone?: \"danger\" | \"muted\" }) {\n return (\n <p role={tone === \"danger\" ? \"alert\" : \"note\"} className={cn(\"text-kit-xs\", tone === \"danger\" ? \"text-kit-danger-fg\" : \"text-kit-fg-3\")}>\n {children}\n </p>\n );\n}\n\n/* ── Drop well (drag · paste · upload · library · URL) ─────────────── */\nfunction DropWell({\n id,\n title,\n hint,\n accept,\n multiple,\n icon,\n disabled,\n onFiles,\n onLibrary,\n onUrl,\n refuse,\n progress,\n}: {\n id?: string;\n title: string;\n hint: string;\n accept: string;\n multiple?: boolean;\n icon: React.ReactNode;\n disabled?: boolean;\n /** undefined: the host has no upload service (no Upload button, drop or paste) */\n onFiles?: (f: File[]) => void;\n /** undefined: the host has no media library */\n onLibrary?: () => void;\n onUrl?: (url: string) => void;\n /** set: Media library and Upload stay drawn (V2's well) when the host has no such service, and a click, drop or\n * paste says why through this instead */\n refuse?: (reason: string) => void;\n progress: number | null;\n}) {\n const [over, setOver] = React.useState(false);\n const [urlMode, setUrlMode] = React.useState(false);\n const [url, setUrl] = React.useState(\"\");\n const [urlError, setUrlError] = React.useState<string | null>(null);\n const input = React.useRef<HTMLInputElement>(null);\n const takesFiles = (!!onFiles || !!refuse) && !disabled;\n const files = (f: File[]) => (onFiles ? onFiles(f) : refuse?.(NO_UPLOAD));\n const pickFiles = () => (onFiles ? input.current?.click() : refuse?.(NO_UPLOAD));\n return (\n <div\n id={id}\n tabIndex={disabled ? -1 : 0}\n role=\"group\"\n aria-label={takesFiles ? `${title}. Paste an image or press Enter to upload` : title}\n onPaste={(e) => {\n const pasted = Array.from(e.clipboardData.files);\n if (pasted.length && takesFiles) {\n e.preventDefault();\n files(pasted);\n }\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && e.target === e.currentTarget && takesFiles) {\n e.preventDefault();\n pickFiles();\n }\n }}\n onDragOver={(e) => {\n if (!takesFiles) return;\n e.preventDefault();\n setOver(true);\n }}\n onDragLeave={(e) => {\n // entering a child (the URL button, the input) fires dragleave on the well: only leaving the well clears it\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) setOver(false);\n }}\n onDrop={(e) => {\n if (!takesFiles) return;\n e.preventDefault();\n setOver(false);\n files(Array.from(e.dataTransfer.files));\n }}\n data-slot=\"kit-drop-well\"\n className={cn(\n \"relative flex flex-col items-center gap-2.5 rounded-kit-lg border border-dashed px-4 py-5 text-center transition-colors\",\n over ? \"border-kit-accent bg-kit-accent-softer\" : \"border-kit-line-strong bg-kit-subtle hover:border-kit-field-border-hover\",\n )}\n >\n <span className={cn(\"flex size-9 items-center justify-center rounded-kit-lg border border-kit-line bg-kit-control-bg text-kit-fg-3 [&_svg]:size-[18px]\", over && \"text-kit-accent-fg\")}>{icon}</span>\n <div>\n <div className=\"text-kit-sm font-medium text-kit-fg\">{over ? \"Drop to upload\" : title}</div>\n {takesFiles ? <div className=\"text-kit-xs text-kit-fg-3\">{hint}</div> : null}\n </div>\n {urlMode && onUrl ? (\n <>\n <form\n className=\"flex w-full max-w-sm items-center gap-1.5\"\n onSubmit={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const v = url.trim();\n if (HTTP.test(v)) {\n onUrl(v);\n setUrlMode(false);\n setUrl(\"\");\n setUrlError(null);\n } else setUrlError(\"Use a full image URL, like https://…/photo.jpg\");\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n setUrlMode(false);\n setUrlError(null);\n }\n }}\n >\n <Input\n autoFocus\n size=\"sm\"\n value={url}\n aria-label=\"Image URL\"\n aria-invalid={urlError ? true : undefined}\n onChange={(e) => setUrl(e.target.value)}\n placeholder=\"https://…/photo.jpg\"\n leading={<IconLink stroke={1.5} />}\n />\n <Button size=\"sm\" type=\"submit\" variant=\"primary\">\n Add\n </Button>\n </form>\n {/* V2 says this in a toast; the kit says it in place, under the form (a toast service may be absent) */}\n {urlError ? <Reason>{urlError}</Reason> : null}\n </>\n ) : (\n <div className=\"flex flex-wrap justify-center gap-1.5\">\n {onLibrary || refuse ? (\n <Button size=\"sm\" variant=\"secondary\" onClick={onLibrary ?? (() => refuse!(NO_LIBRARY))} disabled={disabled}>\n Media library\n </Button>\n ) : null}\n {onFiles || refuse ? (\n <Button size=\"sm\" variant=\"ghost\" leftIcon={<IconUpload stroke={1.5} />} onClick={pickFiles} disabled={disabled}>\n Upload\n </Button>\n ) : null}\n {onUrl ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setUrlMode(true)} disabled={disabled}>\n Paste URL\n </Button>\n ) : null}\n </div>\n )}\n {onFiles ? (\n <input\n ref={input}\n type=\"file\"\n hidden\n tabIndex={-1}\n aria-hidden\n accept={accept}\n multiple={multiple}\n onChange={(e) => {\n onFiles(Array.from(e.target.files ?? []));\n e.target.value = \"\";\n }}\n />\n ) : null}\n {progress != null ? (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-2 rounded-kit-lg bg-kit-surface px-8\">\n <span className=\"text-kit-sm text-kit-fg-2\">\n <span role=\"status\">Uploading…</span> {progress}%\n </span>\n <Progress value={progress} tone=\"ink\" label=\"Upload progress\" className=\"max-w-56\" />\n </div>\n ) : null}\n </div>\n );\n}\n\n/** Why the drop well offers nothing to pick with (no library, no upload): said once, in words. */\nconst NO_SOURCE = \"No media library or upload is connected to this editor, so nothing can be chosen here.\";\nconst NO_LIBRARY = \"No media library is connected to this editor, so nothing can be picked from it here.\";\nconst NO_UPLOAD = \"No upload is connected to this editor, so files can't be uploaded here.\";\n\n/* ── Image ─────────────────────────────────────────────────────────── */\n/** Transparency checker on the kit tokens (white in light, dimmed in dark), as the media grid draws it. */\nconst CHECKER =\n \"bg-kit-checker-a [background-image:conic-gradient(var(--kit-checker-b)_25%,var(--kit-checker-a)_0_50%,var(--kit-checker-b)_0_75%,var(--kit-checker-a)_0)] [background-size:12px_12px]\";\n\n/** V2's five crops (kit media.tsx CROPS, D46). */\nconst CROPS: { value: V2ImageCrop; label: string; ratio: string; description: string }[] = [\n { value: \"original\", label: \"Original\", ratio: \"auto\", description: \"Keep the uploaded shape\" },\n { value: \"16:9\", label: \"16:9\", ratio: \"16/9\", description: \"Widescreen\" },\n { value: \"4:3\", label: \"4:3\", ratio: \"4/3\", description: \"Landscape\" },\n { value: \"1:1\", label: \"1:1\", ratio: \"1/1\", description: \"Square\" },\n { value: \"4:5\", label: \"4:5\", ratio: \"4/5\", description: \"Portrait\" },\n];\nconst CUSTOM_CROP = \"custom\";\n\n/** The crop a value shows: its preset, a stored rect read against the picture's size, or a rect that is none of them. */\nexport function cropChoice(crop: ImageValue[\"crop\"], size?: { w: number; h: number }): V2ImageCrop | typeof CUSTOM_CROP {\n if (!crop) return \"original\";\n if (typeof crop === \"string\") return crop;\n if (!isCropRect(crop)) return \"original\";\n return (size && cropPreset(crop, size.w, size.h)) || CUSTOM_CROP;\n}\n\n/** A custom rect's own shape (its fractions of the picture, in pixels), when the picture's size is known. */\nfunction customRatio(crop: ImageValue[\"crop\"], size?: { w: number; h: number }): string | undefined {\n if (!size || !crop || typeof crop === \"string\" || !isCropRect(crop)) return undefined;\n const w = (1 - crop.left - crop.right) * size.w;\n const h = (1 - crop.top - crop.bottom) * size.h;\n return w > 0 && h > 0 ? String(w / h) : undefined;\n}\n\n/** The value with `choice` cut from the picture (centred on its focal point), or with no crop for Original. */\nexport function withCrop(v: ImageValue, choice: V2ImageCrop, size: { w: number; h: number }): ImageValue {\n const next = { ...v };\n delete next.crop;\n const rect = choice === \"original\" ? undefined : cropRect(choice, size.w, size.h, v.focal);\n if (rect) next.crop = rect;\n return next;\n}\n\nfunction ImageDetails({\n v,\n onChange,\n readOnly,\n label,\n urlOnly,\n altOnly = false,\n size,\n asset,\n}: {\n v: ImageValue;\n onChange: (n: ImageValue) => void;\n readOnly?: boolean;\n label: string;\n urlOnly: boolean;\n /** Only the alt text is kept with this image (`imageAltOnly`). */\n altOnly?: boolean;\n size?: { w: number; h: number };\n asset?: KitMediaAsset;\n}) {\n const { src } = useMedia();\n const focal = v.focal ?? { x: 50, y: 50 };\n const choice = cropChoice(v.crop, size);\n const crop = CROPS.find((c) => c.value === choice);\n // V2 (media.tsx:299-300): the click pad is a preset crop's shape, else 3:2, the picture cropped to it (object-cover);\n // a custom rect (the kit's, cut elsewhere) keeps its own shape\n const padRatio = crop && crop.ratio !== \"auto\" ? crop.ratio : customRatio(v.crop, size) ?? \"3/2\";\n // A preset crop is cut around the focal point (V2 centres the crop on it): moving the point recuts the window.\n const setFocal = (x: number, y: number) => {\n const next: ImageValue = { ...v, focal: { x: Math.round(Math.min(100, Math.max(0, x))), y: Math.round(Math.min(100, Math.max(0, y))) } };\n onChange(crop && crop.value !== \"original\" && size ? withCrop(next, crop.value, size) : next);\n };\n const fromPointer = (e: React.PointerEvent<HTMLDivElement>) => {\n const r = e.currentTarget.getBoundingClientRect();\n if (!r.width || !r.height) return;\n setFocal(((e.clientX - r.left) / r.width) * 100, ((e.clientY - r.top) / r.height) * 100);\n };\n return (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-kit-sm font-medium text-kit-fg\">Alt text and details</span>\n {size ? (\n <span className=\"tabular-nums text-kit-2xs text-kit-fg-3\">\n {size.w} × {size.h}\n </span>\n ) : null}\n </div>\n {urlOnly ? (\n <>\n <Reason tone=\"muted\">This placement stores the image address only, so its alt text and focal point are the media library's.</Reason>\n {asset?.alt ? (\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-kit-xs text-kit-fg-3\">Alt text in the media library</span>\n <span className=\"text-kit-sm text-kit-fg\">{asset.alt}</span>\n </div>\n ) : null}\n </>\n ) : (\n <>\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">Alt text</span>\n <Textarea\n rows={2}\n value={v.alt ?? \"\"}\n readOnly={readOnly}\n onChange={(e) => {\n const alt = e.target.value;\n const next = { ...v };\n if (alt) next.alt = alt;\n else delete next.alt;\n onChange(next);\n }}\n placeholder=\"Describe the image for accessibility\"\n className=\"min-h-14 text-kit-sm\"\n aria-label={`${label} alt text`}\n />\n </label>\n {altOnly ? (\n <Reason tone=\"muted\">This image block keeps its address and alt text. A crop or focal point isn't stored with it.</Reason>\n ) : (\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <span className=\"flex items-center gap-1 text-kit-xs text-kit-fg-3\">\n <IconCrop className=\"size-3.5\" stroke={1.5} aria-hidden />\n Crop for this placement\n </span>\n <span className=\"flex items-center gap-1 text-kit-2xs text-kit-fg-3\">\n <IconFocusCentered className=\"size-3\" stroke={1.5} aria-hidden />\n Focal {focal.x}%, {focal.y}%\n </span>\n </div>\n {/* V2 D46: five crops as a dropdown. A crop is cut from the picture's own size, so it waits for it. */}\n <Select\n size=\"sm\"\n aria-label={`${label} crop`}\n disabled={readOnly || !size}\n triggerClassName=\"w-full\"\n value={choice}\n onValueChange={(c) => size && c !== CUSTOM_CROP && onChange(withCrop(v, c as V2ImageCrop, size))}\n options={[\n ...CROPS.map((c) => ({ value: c.value, label: c.label, meta: c.description })),\n ...(choice === CUSTOM_CROP ? [{ value: CUSTOM_CROP, label: \"Custom\", meta: \"Cut elsewhere\", disabled: true }] : []),\n ]}\n />\n {!size && !readOnly ? <span className=\"text-kit-2xs text-kit-fg-3\">The crop is cut from the picture's size, which is still loading.</span> : null}\n <div\n role=\"slider\"\n aria-label=\"Focal point. Click the subject.\"\n aria-valuetext={`${focal.x}% across, ${focal.y}% down`}\n aria-valuenow={focal.x}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-readonly={readOnly || undefined}\n tabIndex={0}\n onPointerDown={(e) => !readOnly && fromPointer(e)}\n onKeyDown={(e) => {\n const d = e.shiftKey ? 10 : 2;\n const m: Record<string, [number, number]> = { ArrowLeft: [-d, 0], ArrowRight: [d, 0], ArrowUp: [0, -d], ArrowDown: [0, d] };\n const step = m[e.key];\n if (!step || readOnly) return;\n e.preventDefault();\n setFocal(focal.x + step[0], focal.y + step[1]);\n }}\n data-pad-ratio={padRatio}\n // V2's pad (media.tsx:299)\n className=\"relative mt-1 cursor-crosshair overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted\"\n style={{ aspectRatio: padRatio }}\n >\n <img src={src(v.url)} alt=\"\" draggable={false} className=\"pointer-events-none size-full select-none object-cover transition-[object-position] duration-200\" style={{ objectPosition: `${focal.x}% ${focal.y}%` }} />\n <span\n aria-hidden\n className=\"pointer-events-none absolute size-5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-kit-media-handle bg-kit-media-handle-ring shadow-kit-md transition-[left,top] duration-150\"\n style={{ left: `${focal.x}%`, top: `${focal.y}%` }}\n />\n </div>\n <span className=\"text-kit-2xs text-kit-fg-3\">Click the subject. It stays in frame on every screen size.</span>\n </div>\n )}\n </>\n )}\n {urlOnly || altOnly ? (\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">File name</span>\n <span className=\"truncate font-kit-mono text-kit-xs text-kit-fg\">{asset?.name ?? v.name ?? fileNameFromUrl(v.url)}</span>\n </div>\n ) : (\n // V2: the file name this placement shows, editable (stored as the value's `name`).\n <label className=\"flex flex-col gap-1.5\">\n <span className=\"text-kit-xs text-kit-fg-3\">File name</span>\n <Input\n size=\"sm\"\n value={v.name ?? asset?.name ?? fileNameFromUrl(v.url)}\n readOnly={readOnly}\n spellCheck={false}\n autoComplete=\"off\"\n onChange={(e) => {\n const next = { ...v };\n if (e.target.value) next.name = e.target.value;\n else delete next.name;\n onChange(next);\n }}\n className=\"font-kit-mono [&_input]:font-kit-mono\"\n aria-label={`${label} file name`}\n />\n </label>\n )}\n </div>\n );\n}\n\n/** The width × height a stored image value carries (positive numbers only), else undefined. */\nfunction storedSize(value: unknown): { w: number; h: number } | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const { width, height } = value as { width?: unknown; height?: unknown };\n return typeof width === \"number\" && typeof height === \"number\" && width > 0 && height > 0 ? { w: width, h: height } : undefined;\n}\n\n/* ── Icon: an inline-SVG image is one 32px row, not a picture card ─── */\n/**\n * V2's icon control shape (controls/icon.tsx): ONE button — a 24px glyph tile, the field's name, a quiet replace cue —\n * that opens the library. No Replace pill, no ×, no alt text, crop or details: an icon's alt text is \"\" (aria-hidden on\n * the page) and Remove sits in the picker's footer. Empty: a dashed tile, \"Add icon\", and an SVG dropped on it uploads.\n */\nfunction IconImageRow({\n id,\n title,\n url,\n readOnly,\n onOpen,\n onFiles,\n busy,\n pickerOpen,\n}: {\n id: string;\n title: string;\n url?: string;\n readOnly?: boolean;\n onOpen?: () => void;\n onFiles?: (files: File[]) => void;\n busy: boolean;\n pickerOpen: boolean;\n}) {\n const row = React.useRef<HTMLButtonElement>(null);\n const [over, setOver] = React.useState(false);\n // However the picker closes (Escape, Cancel, a pick, Remove), focus comes back to the row that opened it.\n const wasOpen = React.useRef(false);\n React.useEffect(() => {\n if (wasOpen.current && !pickerOpen) row.current?.focus({ preventScroll: true });\n wasOpen.current = pickerOpen;\n }, [pickerOpen]);\n const empty = !url;\n const inert = readOnly || busy || !onOpen;\n const droppable = empty && !inert && !!onFiles;\n // the field's own chrome (comments, presence, the field menu): the shell draws no label row for an icon, so the row\n // carries it at its trailing edge, as NavRow does\n const chrome = React.useContext(RowChrome);\n return (\n <div\n className={cn(\n \"flex h-8 min-w-0 items-center rounded-kit-md border bg-kit-field-bg pointer-coarse:min-h-11\",\n \"transition-colors duration-[120ms] ease-out motion-reduce:transition-none\",\n over ? \"border-kit-emphasis-line bg-kit-hover\" : \"border-kit-line-strong\",\n inert ? \"opacity-60\" : \"[@media(hover:hover)]:hover:bg-kit-hover\",\n )}\n >\n <Tooltip content={title}>\n <button\n ref={row}\n id={id}\n type=\"button\"\n data-slot=\"kit-icon-row\"\n disabled={inert}\n onClick={onOpen}\n aria-label={empty ? `Add icon, ${title}` : `Replace ${title}`}\n onDragOver={droppable ? (e) => { e.preventDefault(); setOver(true); } : undefined}\n onDragLeave={droppable ? () => setOver(false) : undefined}\n onDrop={droppable ? (e) => { e.preventDefault(); setOver(false); onFiles(Array.from(e.dataTransfer.files)); } : undefined}\n className=\"flex min-w-0 flex-1 touch-manipulation items-center gap-3 self-stretch rounded-[5px] pl-[3px] pr-2 text-left text-kit-sm focus-visible:-outline-offset-2 disabled:cursor-not-allowed\"\n >\n <span\n aria-hidden\n className={cn(\n \"grid size-6 shrink-0 place-items-center overflow-hidden rounded-kit-sm border\",\n empty ? \"border-dashed border-kit-emphasis-line\" : cn(\"border-kit-line p-1\", CHECKER),\n )}\n >\n {empty ? <IconPlus className=\"size-3.5 text-kit-fg-3\" stroke={1.5} /> : <img src={url} alt=\"\" className=\"size-full object-contain\" />}\n </span>\n <span aria-hidden className={cn(\"min-w-0 flex-1 truncate\", empty ? \"text-kit-fg-3\" : \"text-kit-fg\")}>\n {empty ? (busy ? \"Uploading…\" : \"Add icon\") : title}\n </span>\n {empty ? null : <IconRefresh aria-hidden className=\"size-3.5 shrink-0 text-kit-fg-3\" stroke={1.5} />}\n </button>\n </Tooltip>\n {chrome ? <span data-slot=\"kit-icon-row-chrome\" className=\"flex shrink-0 items-center gap-0.5 pr-1 empty:hidden\">{chrome}</span> : null}\n </div>\n );\n}\n\nexport function ImageControl({ field, value, onChange: write, readOnly, id, path }: ControlProps) {\n const { s, useAsset, src } = useMedia();\n const env = useKitEnv();\n const urlOnly = !!s.imageStoresUrl?.(path);\n const altOnly = !urlOnly && !!s.imageAltOnly?.(path);\n const legacyString = typeof value === \"string\" || field.valueShape === \"string\";\n const v = normImage(value);\n const asset = useAsset({ id: v?.id, url: v?.url ?? \"\" });\n // an inline-SVG icon takes SVG files only: a raster there never reaches the page (publish answers svgUnavailable)\n const accept = field.svgOnly ? \"image/svg+xml\" : \"image/*\";\n const kinds: (\"image\" | \"svg\")[] = field.svgOnly ? [\"svg\"] : [\"image\", \"svg\"];\n /*\n * The loaded preview's size, keyed to the URL it was read from. It used to be cleared by an effect on [url], which\n * also ran on MOUNT: a cached picture (the Values popover opened again) finished loading before that effect ran, so\n * the reset wiped the size its load had just set and the caption lost \"· 2400 × 1600\". A picture that is already\n * complete when it mounts is read there too, since its load may have fired before the handler was attached.\n */\n const [loaded, setLoaded] = React.useState<{ url: string; w: number; h: number } | undefined>();\n const natural = loaded && v && loaded.url === v.url ? { w: loaded.w, h: loaded.h } : undefined;\n const readNatural = (img: HTMLImageElement | null) => {\n if (!img || !v || !img.complete || !img.naturalWidth || !img.naturalHeight) return;\n const next = { url: v.url, w: img.naturalWidth, h: img.naturalHeight };\n setLoaded((prev) => (prev && prev.url === next.url && prev.w === next.w && prev.h === next.h ? prev : next));\n };\n // V2's order: the library asset's dimensions, then the ones stored on the value (an imported or retina source keeps\n // its real size there), and only then the loaded preview's natural size (a resized preview reads smaller)\n const stored = storedSize(value);\n const size = asset?.width && asset.height ? { w: asset.width, h: asset.height } : stored ?? natural;\n\n /* the URL-string placements write the URL. Elsewhere a value stored as a URL string becomes V2's object as soon as\n it carries more than the URL (a name, alt text, a focal point or a crop): an older string is still read as is. */\n const onChange = (n: ImageValue | null) => {\n if (!n) return write(urlOnly ? \"\" : null);\n if (urlOnly) return write(n.url);\n if (legacyString && !n.alt && !n.focal && !n.crop && !n.name && !n.id) return write(n.url);\n write(n);\n };\n const [picker, setPicker] = React.useState(false);\n const [details, setDetails] = React.useState(false);\n const up = useUpload(accept, \"image\", (a) => a[0] && onChange(fromAsset(a[0])));\n const library = s.MediaPicker && !readOnly ? () => setPicker(true) : undefined;\n const known = (s.useSiteIcons ?? NO_ICONS)();\n\n if (isIconImage(field, value)) {\n // This field's own icon leads, marked, so the author sees what they are replacing.\n const icons = s.useSiteIcons\n ? [\n ...(v ? [{ url: v.url, value, current: true }] : []),\n ...known.filter((i) => i.url !== v?.url && !(v?.id && i.assetId === v.id)).map(({ url, value: stored }) => ({ url, value: stored })),\n ]\n : undefined;\n const pickIcon = (stored: unknown) => {\n const n = normImage(stored);\n if (n) onChange(fromAsset({ id: n.id ?? \"\", url: n.url, name: n.name, alt: n.alt ?? (typeof n.altText === \"string\" ? n.altText : undefined), kind: \"svg\" }));\n setPicker(false);\n };\n return (\n <div className=\"flex flex-col gap-1.5\">\n <IconImageRow\n id={id}\n title={field.title}\n url={v ? src(v.url) : undefined}\n readOnly={readOnly}\n onOpen={library}\n onFiles={up.run}\n busy={up.progress != null}\n pickerOpen={picker}\n />\n {up.error ? <Reason>{up.error}</Reason> : null}\n {!readOnly && !library ? <Reason tone=\"muted\">{NO_LIBRARY}</Reason> : null}\n <MediaPicker\n open={picker}\n onOpenChange={setPicker}\n accept={[\"svg\"]}\n title={v ? \"Replace icon\" : \"Select an icon\"}\n onPick={(a) => a[0] && onChange(fromAsset(a[0]))}\n onRemove={v && !readOnly ? () => { onChange(null); setPicker(false); } : undefined}\n icons={icons}\n onPickIcon={readOnly ? undefined : pickIcon}\n />\n </div>\n );\n }\n\n if (!v)\n return (\n <div className=\"flex flex-col gap-1.5\">\n <DropWell\n id={id}\n title=\"Add an image\"\n hint=\"Or drop or paste one here\"\n accept={accept}\n icon={<IconPhoto stroke={1.5} />}\n onFiles={up.run}\n onLibrary={library}\n onUrl={readOnly ? undefined : (url) => onChange({ url, name: fileNameFromUrl(url) || undefined })}\n refuse={up.setError}\n disabled={readOnly}\n progress={up.progress}\n />\n {up.error ? <Reason>{up.error}</Reason> : null}\n <MediaPicker open={picker} onOpenChange={setPicker} accept={kinds} onPick={(a) => a[0] && onChange(fromAsset(a[0]))} />\n </div>\n );\n\n // V2 (media.tsx:368-379, owner D1 2026-10-24): a preset crop's shape, else 16:9, the picture cropped to fill it\n // (object-cover) at its focal point. This reverses the 2026-10-16 fit-whole-on-the-checker preview.\n const frameRatio = CROPS.find((c) => c.value === cropChoice(v.crop, size))?.ratio;\n const focal = v.focal ?? { x: 50, y: 50 };\n const alt = urlOnly ? asset?.alt : v.alt;\n const name = asset?.name ?? v.name ?? fileNameFromUrl(v.url);\n const replace = (a: KitMediaAsset) => {\n const next = fromAsset(a);\n if (!next.alt && v.alt) next.alt = v.alt;\n if (v.focal) next.focal = v.focal;\n onChange(next);\n };\n const openDetails = () => window.setTimeout(() => setDetails(true), 0);\n return (\n <Popover open={details} onOpenChange={setDetails}>\n <PopoverAnchor\n className={cn(\"flex flex-col gap-1.5\", env.variant === \"document\" && \"max-w-xl\")}\n onPaste={(e: React.ClipboardEvent) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length && up.run && !readOnly) {\n e.preventDefault();\n up.run(files);\n }\n }}\n >\n <div\n data-slot=\"kit-image-frame\"\n className=\"group/img relative overflow-hidden rounded-kit-lg border border-kit-line bg-kit-muted\"\n style={{ aspectRatio: frameRatio && frameRatio !== \"auto\" ? frameRatio : \"16/9\" }}\n >\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n onClick={() => (library ? library() : openDetails())}\n aria-label={library ? `Replace ${field.title}` : `${field.title} details`}\n className=\"flex size-full items-center justify-center outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none\"\n >\n <img\n src={src(v.url)}\n alt={alt ?? \"\"}\n ref={readNatural}\n onLoad={(e) => readNatural(e.currentTarget)}\n className=\"size-full object-cover\"\n style={{ objectPosition: `${focal.x}% ${focal.y}%` }}\n />\n </button>\n {readOnly ? null : (\n <div className=\"absolute right-2 top-2 flex gap-1 opacity-0 transition-opacity focus-within:opacity-100 group-hover/img:opacity-100 [@media(pointer:coarse)]:opacity-100\">\n {library ? (\n <button type=\"button\" onClick={library} className=\"flex h-7 items-center gap-1 rounded-full border border-kit-swatch-ring bg-kit-media-control px-2.5 text-kit-xs font-medium text-kit-media-control-fg shadow-kit-sm\">\n <IconReplace className=\"size-3.5\" stroke={1.5} aria-hidden />\n Replace\n </button>\n ) : null}\n <Tooltip content=\"Remove image\">\n <button type=\"button\" aria-label=\"Remove image\" onClick={() => onChange(null)} className=\"flex size-7 items-center justify-center rounded-full border border-kit-swatch-ring bg-kit-media-control text-kit-media-control-fg shadow-kit-sm\">\n <IconX className=\"size-3.5\" stroke={1.5} aria-hidden />\n </button>\n </Tooltip>\n </div>\n )}\n {up.progress != null ? (\n <div className=\"absolute inset-x-3 bottom-3\">\n <Progress value={up.progress} tone=\"ink\" size=\"sm\" label=\"Upload progress\" />\n </div>\n ) : null}\n </div>\n <div className=\"flex min-w-0 items-center gap-1.5 pl-0.5\">\n <span data-slot=\"kit-image-caption\" className=\"min-w-0 flex-1 truncate text-kit-xs text-kit-fg-3\">\n {name}\n {size ? (\n <>\n {\" · \"}\n <span className=\"tabular-nums\">\n {size.w} × {size.h}\n </span>\n </>\n ) : null}\n {\" · \"}\n {alt ? (\n <span className=\"text-kit-fg-2\">Alt text set</span>\n ) : (\n <span className=\"inline-flex items-center gap-0.5 text-kit-warning-fg\">\n <IconAlertTriangle className=\"size-3\" stroke={1.5} aria-hidden />\n No alt text\n </span>\n )}\n </span>\n <Menu>\n <MenuTrigger\n aria-label=\"Image actions\"\n className=\"flex size-6 shrink-0 items-center justify-center rounded-kit-md text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg data-[popup-open]:bg-kit-hover\"\n >\n <IconDots className=\"size-4\" stroke={1.5} aria-hidden />\n </MenuTrigger>\n <MenuContent align=\"end\" className=\"w-52\">\n <MenuItem icon={<IconFocusCentered stroke={1.5} />} onClick={openDetails}>\n Alt text and details\n </MenuItem>\n {/* V2: Replace and Remove are always listed, disabled when they can't act (read-only, or no library) */}\n <MenuItem icon={<IconReplace stroke={1.5} />} disabled={!library} onClick={library}>\n Replace\n </MenuItem>\n <MenuItem icon={<IconExternalLink stroke={1.5} />} onClick={() => window.open(src(v.url), \"_blank\", \"noopener\")}>\n Open original\n </MenuItem>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} disabled={readOnly} onClick={() => !readOnly && onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n </div>\n {up.error ? <Reason>{up.error}</Reason> : null}\n </PopoverAnchor>\n <PopoverContent className=\"w-[320px]\" align=\"start\" side=\"bottom\">\n <ImageDetails v={v} onChange={onChange} readOnly={readOnly} label={field.title} urlOnly={urlOnly} altOnly={altOnly} size={size} asset={asset} />\n </PopoverContent>\n <MediaPicker open={picker} onOpenChange={setPicker} accept={kinds} onPick={(a) => a[0] && replace(a[0])} />\n </Popover>\n );\n}\n\n/* ── Gallery (array of images) ─────────────────────────────────────── */\ntype GItem = { key: string; v: ImageValue; raw: unknown };\n\nfunction Thumb({\n item,\n label,\n readOnly,\n sort,\n onRemove,\n onOpen,\n}: {\n item: GItem;\n label: string;\n readOnly?: boolean;\n sort: ReturnType<typeof useDragReorder>;\n onRemove: () => void;\n onOpen: () => void;\n}) {\n const { src } = useMedia();\n const handle = sort.handle(item.key);\n return (\n <div\n ref={sort.register(item.key)}\n role=\"listitem\"\n style={sort.style(item.key)}\n // V2's thumb (media.tsx:443)\n className={cn(\n \"group/thumb relative aspect-square cursor-grab touch-none overflow-hidden rounded-kit-md border border-kit-line bg-kit-muted active:cursor-grabbing\",\n sort.active === item.key && \"z-10 opacity-90 shadow-kit-lg ring-2 ring-kit-line-strong\",\n )}\n >\n <div\n {...(readOnly ? {} : handle)}\n role={undefined}\n tabIndex={0}\n aria-label={readOnly ? label : `${label}, drag to reorder`}\n onDoubleClick={onOpen}\n onKeyDown={(e) => {\n if (!readOnly && (e.key === \"Delete\" || e.key === \"Backspace\")) {\n e.preventDefault();\n onRemove();\n return;\n }\n if (e.key === \"Enter\") {\n e.preventDefault();\n onOpen();\n return;\n }\n if (!readOnly) handle.onKeyDown(e);\n }}\n className=\"size-full outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-kit-focus-ring focus-visible:[outline-style:solid] [html[data-input-modality=pointer]_&]:focus-visible:outline-none\"\n >\n <img src={src(item.v.url)} alt={item.v.alt ?? \"\"} data-slot=\"kit-gallery-thumb\" className=\"pointer-events-none size-full select-none object-cover\" draggable={false} />\n </div>\n {!item.v.alt ? <span role=\"img\" className=\"absolute bottom-1 left-1 size-1.5 rounded-full bg-kit-warning ring-2 ring-kit-surface\" aria-label=\"No alt text\" /> : null}\n {readOnly ? null : (\n <button\n type=\"button\"\n // AD-A11Y-GALLERY: V2's classes, plus a name per picture and a touch-only reveal (no hover on touch)\n aria-label={(() => {\n const what = item.v.alt || item.v.name || fileNameFromUrl(item.v.url);\n return what ? `Remove ${what}` : \"Remove image\";\n })()}\n onPointerDown={(e) => e.stopPropagation()}\n onClick={onRemove}\n className=\"absolute right-1 top-1 flex size-6 items-center justify-center rounded-kit-md bg-kit-inverse/80 text-kit-fg-inverse opacity-0 transition-opacity focus-visible:opacity-100 group-hover/thumb:opacity-100 pointer-coarse:opacity-100\"\n >\n <IconX className=\"size-3.5\" stroke={1.5} aria-hidden />\n </button>\n )}\n </div>\n );\n}\n\n/** An array of images: a sortable grid of tiles with a dashed \"Add images\" tile last (hidden at `max`). */\nexport function GalleryControl({ value, onChange, readOnly, field, id, path }: ControlProps) {\n const { s, src } = useMedia();\n const env = useKitEnv();\n const raw = Array.isArray(value) ? value : [];\n /* a key that survives a move (keyboard reorder refocuses the grip by key); an index suffix only for duplicates */\n const seen = new Map<string, number>();\n const items: GItem[] = raw.map((x) => {\n const v = normImage(x) ?? { url: \"\" };\n const base = v.id ?? v.url;\n const n = seen.get(base) ?? 0;\n seen.set(base, n + 1);\n return { key: n ? `${base}#${n}` : base, v, raw: x };\n });\n /* strings stay strings (a legacy list of URLs); a picked asset joins as the object prod stores */\n const asStrings = raw.length > 0 && raw.every((x) => typeof x === \"string\");\n const out = (v: ImageValue) => (asStrings && !v.alt && !v.focal ? v.url : v);\n const write = (list: unknown[]) => onChange(list);\n const add = (assets: KitMediaAsset[]) => write([...raw, ...assets.map((a) => out(fromAsset(a)))]);\n const [picker, setPicker] = React.useState(false);\n const up = useUpload(\"image/*\", \"image\", add);\n const keys = items.map((it) => it.key);\n const sort = useDragReorder(\n keys,\n (from, to) => {\n const next = [...raw];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved);\n write(next);\n },\n { axis: \"grid\", disabled: readOnly },\n );\n const max = field.validation?.max;\n const canAdd = !readOnly && (max == null || items.length < max) && (s.MediaPicker || up.run);\n const noun = (i: number, it: GItem) => it.v.name ?? (fileNameFromUrl(it.v.url) || `Image ${i + 1}`);\n return (\n <div className=\"flex flex-col gap-2\">\n <div id={id} role=\"list\" aria-label={field.title} className=\"grid grid-cols-3 gap-1.5 @[520px]:grid-cols-5\">\n {items.map((it, i) => (\n <Thumb\n key={it.key}\n item={it}\n label={noun(i, it)}\n readOnly={readOnly}\n sort={sort}\n // the host's image editor where it has one (`editImage`), else the picture itself\n onOpen={() => (s.editImage && !readOnly ? s.editImage({ docId: env.docId, path: [...path, i], title: noun(i, it) }) : window.open(src(it.v.url), \"_blank\", \"noopener\"))}\n onRemove={() => write(raw.filter((_, j) => j !== i))}\n />\n ))}\n {canAdd ? (\n // a real grid cell, not `display: contents`: V2 draws the tile as the grid's own child, and a box-less wrapper\n // would put the tile beside nothing (the Panel walker measures its gap from the thumbs beside it)\n <div role=\"listitem\" className=\"grid\">\n <button\n type=\"button\"\n onClick={() => (s.MediaPicker ? setPicker(true) : up.run && document.getElementById(`${id}-files`)?.click())}\n onPaste={(e) => {\n const files = Array.from(e.clipboardData.files);\n if (files.length && up.run) {\n e.preventDefault();\n up.run(files);\n }\n }}\n onDragOver={(e) => up.run && e.preventDefault()}\n onDrop={(e) => {\n if (!up.run) return;\n e.preventDefault();\n up.run(Array.from(e.dataTransfer.files));\n }}\n className=\"flex aspect-square flex-col items-center justify-center gap-1 rounded-kit-md border border-dashed border-kit-line-strong bg-kit-subtle text-kit-xs text-kit-fg-3 transition-colors hover:border-kit-field-border-hover hover:text-kit-fg\"\n >\n <IconPlus className=\"size-4\" stroke={1.5} aria-hidden />\n Add images\n </button>\n </div>\n ) : null}\n </div>\n {sort.a11y}\n {up.run && !s.MediaPicker ? (\n <input\n id={`${id}-files`}\n type=\"file\"\n hidden\n tabIndex={-1}\n aria-hidden\n accept=\"image/*\"\n multiple\n onChange={(e) => {\n up.run?.(Array.from(e.target.files ?? []));\n e.target.value = \"\";\n }}\n />\n ) : null}\n {up.progress != null ? <Progress value={up.progress} tone=\"ink\" size=\"sm\" label=\"Upload progress\" /> : null}\n {up.error ? <Reason>{up.error}</Reason> : null}\n {!readOnly && !s.MediaPicker && !up.run ? <Reason tone=\"muted\">{NO_SOURCE}</Reason> : null}\n <MediaPicker open={picker} onOpenChange={setPicker} multiple accept={[\"image\", \"svg\"]} onPick={(a) => a.length && add(max != null ? a.slice(0, Math.max(0, max - items.length)) : a)} />\n </div>\n );\n}\n\n/* ── File ──────────────────────────────────────────────────────────── */\n/** A file value prod stores: the same envelope as an image, `{ url, id?, name? }` (or a legacy URL string). */\ntype FileValue = { url: string; id?: string; name?: string; [key: string]: unknown };\nconst normFile = (v: unknown): FileValue | null => {\n if (typeof v === \"string\") return v ? { url: v } : null;\n return isObj(v) && typeof v.url === \"string\" && v.url ? (v as FileValue) : null;\n};\nconst fileFromAsset = (a: KitMediaAsset): FileValue => ({ url: a.url, id: a.id, ...(a.name ? { name: a.name } : {}) });\n\nexport function FileControl({ value, onChange, readOnly, id }: ControlProps) {\n const { s, useAsset, src } = useMedia();\n const v = normFile(value);\n const asset = useAsset({ id: v?.id, url: v?.url ?? \"\" });\n const [picker, setPicker] = React.useState(false);\n const up = useUpload(\"*\", \"file\", (a) => a[0] && onChange(fileFromAsset(a[0])));\n const library = s.MediaPicker && !readOnly ? () => setPicker(true) : undefined;\n const pickerEl = <MediaPicker open={picker} onOpenChange={setPicker} accept={[\"file\"]} onPick={(a) => a[0] && onChange(fileFromAsset(a[0]))} />;\n if (!v)\n return (\n <div className=\"flex flex-col gap-1.5\">\n <DropWell id={id} title=\"Add a file\" hint=\"Or drop or paste one here\" accept=\"*\" icon={<IconFileText stroke={1.5} />} onFiles={up.run} onLibrary={library} refuse={up.setError} disabled={readOnly} progress={up.progress} />\n {up.error ? <Reason>{up.error}</Reason> : null}\n {pickerEl}\n </div>\n );\n const name = asset?.name ?? v.name ?? fileNameFromUrl(v.url);\n const ext = (name.includes(\".\") ? name.split(\".\").pop() : \"\")?.toUpperCase() || \"FILE\";\n const meta = [ext.toLowerCase(), asset?.size ? formatBytes(asset.size) : null].filter(Boolean).join(\" · \");\n return (\n <div className=\"flex items-center gap-3 rounded-kit-lg border border-kit-line bg-kit-control-bg p-2\">\n <span aria-hidden className=\"flex size-14 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle font-kit-mono text-kit-2xs font-medium text-kit-fg-2\">\n {ext}\n </span>\n <div className=\"min-w-0 flex-1\">\n <a id={id} href={src(v.url)} target=\"_blank\" rel=\"noreferrer\" className=\"block truncate text-kit-sm font-medium text-kit-accent-fg hover:underline\">\n {name}\n </a>\n <div className=\"text-kit-xs text-kit-fg-3\">{meta}</div>\n </div>\n {library ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={library}>\n Replace\n </Button>\n ) : null}\n <Menu>\n <MenuTrigger render={<IconButton label=\"File actions\" size=\"sm\" />}>\n <IconDots stroke={1.5} />\n </MenuTrigger>\n <MenuContent align=\"end\">\n <MenuItem icon={<IconDownload stroke={1.5} />} onClick={() => window.open(src(v.url), \"_blank\", \"noopener\")}>\n Open\n </MenuItem>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} disabled={readOnly} onClick={() => !readOnly && onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n {pickerEl}\n </div>\n );\n}\n\n/* ── Video (paste a URL → preview) ─────────────────────────────────── */\nexport const videoProvider = (url: string) =>\n /youtu/.test(url) ? \"YouTube\" : /vimeo/.test(url) ? \"Vimeo\" : /loom/.test(url) ? \"Loom\" : /\\.(mp4|webm|mov)(\\?|$)/i.test(url) ? \"MP4\" : url ? \"Link\" : \"\";\nexport const youTubeId = (url: string) => url.match(/(?:youtu\\.be\\/|v=|embed\\/|shorts\\/)([\\w-]{11})/)?.[1];\nconst isFileVideo = (url: string) => /\\.(mp4|webm|mov)(\\?|$)/i.test(url);\n\nexport function VideoPreview({ url, poster, title }: { url: string; poster?: string; title: string }) {\n const { src } = useMedia();\n const [playing, setPlaying] = React.useState(false);\n React.useEffect(() => setPlaying(false), [url]);\n const yt = youTubeId(url);\n const thumb = poster ? src(poster) : yt ? `https://i.ytimg.com/vi/${yt}/hqdefault.jpg` : undefined;\n if (playing && yt)\n return <iframe title={title} src={`https://www.youtube-nocookie.com/embed/${yt}?autoplay=1`} allow=\"autoplay; encrypted-media\" className=\"aspect-video w-full rounded-kit-lg border border-kit-line\" />;\n if (playing && isFileVideo(url)) return <video src={src(url)} poster={thumb} controls autoPlay className=\"aspect-video w-full rounded-kit-lg border border-kit-line bg-kit-media-backdrop\" />;\n const playable = !!yt || isFileVideo(url);\n return (\n <div className=\"relative aspect-video overflow-hidden rounded-kit-lg border border-kit-line bg-kit-media-backdrop\">\n {thumb ? <img src={thumb} alt={`${title} poster`} className=\"size-full object-cover opacity-85\" /> : null}\n <button\n type=\"button\"\n aria-label={playable ? \"Play preview\" : \"Open video link\"}\n onClick={() => (playable ? setPlaying(true) : window.open(src(url), \"_blank\", \"noopener\"))}\n className=\"absolute inset-0 m-auto flex size-12 items-center justify-center rounded-full bg-kit-media-control text-kit-media-control-fg shadow-kit-lg transition-transform hover:scale-105\"\n >\n {playable ? <IconPlayerPlay className=\"size-5\" stroke={1.5} aria-hidden /> : <IconExternalLink className=\"size-5\" stroke={1.5} aria-hidden />}\n </button>\n <span className=\"absolute left-2 top-2 inline-flex items-center gap-1 rounded-kit-md bg-kit-scrim px-1.5 py-0.5 text-kit-xs text-kit-on-scrim\">\n <IconVideo className=\"size-3.5\" stroke={1.5} aria-hidden />\n {videoProvider(url)}\n </span>\n </div>\n );\n}\n\n/**\n * A URL input with a live preview. The value keeps its stored shape: a URL string stays a string, a `{ url, poster… }`\n * object keeps its other keys. What is typed is a draft until it is an address prod stores (http(s) or a site path);\n * until then the field keeps the saved value and says why under the input.\n */\nexport function VideoControl({ field, value, onChange, readOnly, id, onBlur }: ControlProps) {\n const obj = isObj(value) && typeof value.url === \"string\" ? (value as { url: string; poster?: string }) : null;\n const stored = typeof value === \"string\" ? value : (obj?.url ?? \"\");\n const [draft, setDraft] = React.useState(stored);\n const [touched, setTouched] = React.useState(false);\n React.useEffect(() => setDraft(stored), [stored]);\n const commit = (raw: string) => {\n const url = raw.trim();\n if (url === stored || !isVideoUrl(url)) return;\n if (url === \"\") return onChange(obj ? null : \"\");\n onChange(obj ? { ...obj, url } : url);\n };\n const bad = draft.trim() !== \"\" && !isVideoUrl(draft);\n const errorId = `${id}-error`;\n return (\n <div className=\"flex flex-col gap-2\">\n <Input\n id={id}\n value={draft}\n readOnly={readOnly}\n aria-invalid={bad && touched ? true : undefined}\n aria-describedby={bad && touched ? errorId : undefined}\n onBlur={() => {\n setTouched(true);\n onBlur?.();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\" && draft !== stored) {\n e.stopPropagation();\n setDraft(stored);\n }\n }}\n placeholder=\"Paste a YouTube, Vimeo, Loom or MP4 link\"\n leading={<IconWorld stroke={1.5} />}\n onChange={(e) => {\n setDraft(e.target.value);\n commit(e.target.value);\n }}\n />\n {bad && touched ? (\n <p id={errorId} role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n Not saved: use a full link starting with https://, or a site path starting with /.\n </p>\n ) : null}\n {/* V2 promises \"a poster frame automatically\", which nothing here makes; this note says what is true and, like V2's,\n wraps to two lines at Panel widths (420 and 360) */}\n {stored ? <VideoPreview url={stored} poster={obj?.poster} title={field.title} /> : <p className=\"text-kit-xs text-kit-fg-3\">No video yet. The embed lazy-loads on the page, so it doesn't block the first paint.</p>}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEA,IAAa,mBAAmB,QAAgB;CAI9C,MAAM,SAAS,+BAA+B,KAAK,IAAI,KAAK,CAAC;CAC7D,IAAI,QAAQ,OAAO,YAAY,OAAO,EAAE,CAAC,QAAQ,WAAW,EAAE,CAAC,CAAC,QAAQ,WAAW,KAAK,CAAC,CAAC,YAAY,EAAE;CAGxG,IAAI;EACF,MAAM,IAAI,IAAI,IAAI,KAAK,OAAO,WAAW,cAAc,sBAAsB,OAAO,SAAS,IAAI;EACjG,IAAI,EAAE,aAAa,WAAW,EAAE,aAAa,SAAS,OAAO;EAC7D,MAAM,OAAO,EAAE,SAAS,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,MAAM,oBAAoB,KAAK,CAAC,CAAC;EACpG,OAAO,OAAO,mBAAmB,IAAI,IAAI,cAAc,EAAE,SAAS,QAAQ,UAAU,EAAE;CACxF,QAAQ;EACN,OAAO;CACT;AACF;AAEA,IAAa,aAAa,MAAkC;CAC1D,IAAI,OAAO,MAAM,UAAU,OAAO,IAAI,EAAE,KAAK,EAAE,IAAI;CACnD,OAAO,MAAM,CAAC,KAAK,OAAO,EAAE,QAAQ,YAAY,EAAE,MAAO,IAAmB;AAC9E;;AAGA,IAAa,aAAa,MAAiC;CAEzD,MAAM,MAAkB,EAAE,KAAK;EAAE,KAAK,EAAE;EAAK,IAAI,EAAE;CAAG,IAAI,EAAE,KAAK,EAAE,IAAI;CACvE,IAAI,EAAE,MAAM,IAAI,OAAO,EAAE;CACzB,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE;CACvB,OAAO;AACT;AAEA,IAAa,eAAe,MAAe,KAAK,MAAY,IAAI,IAAI,IAAA,CAAW,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,GAAI,CAAC,EAAE;AAEtI,IAAM,OAAO;;AAEb,IAAa,cAAc,MAAc,MAAM,MAAM,KAAK,KAAK,EAAE,KAAK,CAAC,KAAK,gBAAgB,KAAK,EAAE,KAAK,CAAC;AAEzG,IAAM,iBAAiB,KAAA;AACvB,IAAM,iBAAgC,CAAC;AACvC,IAAM,UAAU,MAAc;;AAG9B,SAAS,WAAW;CAClB,MAAM,IAAI,eAAe;CACzB,OAAO;EAAE;EAAG,UAAU,EAAE,iBAAiB;EAAU,KAAK,EAAE,YAAY;CAAO;AAC/E;;AAGA,SAAgB,YAAY,QAAgB,MAA4C;CACtF,OAAO,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM,QAAQ;EACrC,MAAM,OAAO,IAAI,KAAK,CAAC,CAAC,YAAY;EACpC,IAAI,CAAC,QAAQ,SAAS,OAAO,SAAS,OAAO,OAAO;EACpD,IAAI,KAAK,WAAW,GAAG,GAAG,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,SAAS,IAAI;EACtE,IAAI,KAAK,SAAS,IAAI,GAAG,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,WAAW,KAAK,MAAM,GAAG,EAAE,CAAC;EACpF,OAAO,KAAK,KAAK,YAAY,MAAM;CACrC,CAAC;AACH;AAGA,SAAgB,YAAY,GAAkE;CAC5F,MAAM,SAAS,eAAe,CAAC,CAAC;CAChC,OAAO,SAAS,oBAAC,QAAD,EAAQ,GAAI,EAAI,CAAA,IAAI;AACtC;;;;;AAMA,SAAgB,UAAU,QAAgB,MAAc,QAAsC;CAC5F,MAAM,EAAE,aAAa,YAAY,UAAU,eAAe;CAC1D,MAAM,CAAC,UAAU,eAAe,MAAM,SAAwB,IAAI;CAClE,MAAM,CAAC,OAAO,YAAY,MAAM,SAAwB,IAAI;CAC5D,MAAM,QAAQ,MAAM,OAAO,IAAI;CAC/B,MAAM,sBACQ;EACV,MAAM,UAAU;CAClB,GACA,CAAC,CACH;CA0BA,OAAO;EAAE;EAAU;EAAO;EAAU,KAzBxB,eACP,UAAkB;GACjB,IAAI,CAAC,MAAM,UAAU,YAAY,MAAM;GACvC,MAAM,MAAM,MAAM,MAAM,MAAM,CAAC,YAAY,QAAQ,CAAC,CAAC;GACrD,IAAI,KAAK;IACP,SAAS,GAAG,IAAI,QAAQ,YAAY,SAAS,SAAS,SAAS,4BAA4B,MAAM,OAAO,EAAE;IAC1G;GACF;GACA,SAAS,IAAI;GACb,YAAY,CAAC;GACb,YAAY,OAAO,EAAE,aAAa,MAAM,MAAM,WAAW,YAAY,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CACnH,MAAM,WAAW;IAChB,IAAI,CAAC,MAAM,SAAS;IACpB,YAAY,IAAI;IAChB,aAAa,MAAM;IACnB,OAAO,MAAM;IACb,OAAO,QAAQ,MAAM,SAAS,IAAI,GAAG,MAAM,OAAO,mBAAmB,GAAG,OAAO,EAAE,EAAE,QAAQ,MAAM,EAAE,CAAC,KAAK,YAAY,EAAE,aAAa,6BAA6B,CAAC;GACpK,CAAC,CAAC,CACD,OAAO,MAAe;IACrB,IAAI,CAAC,MAAM,SAAS;IACpB,YAAY,IAAI;IAChB,SAAS,kBAAkB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,GAAG;GACzE,CAAC;EACL,IACA,KAAA;CACoC;AAC1C;;AAGA,SAAS,OAAO,EAAE,UAAU,OAAO,YAAsE;CACvG,OACE,oBAAC,KAAD;EAAG,MAAM,SAAS,WAAW,UAAU;EAAQ,WAAW,GAAG,eAAe,SAAS,WAAW,uBAAuB,eAAe;EACnI;CACA,CAAA;AAEP;AAGA,SAAS,SAAS,EAChB,IACA,OACA,MACA,QACA,UACA,MACA,UACA,SACA,WACA,OACA,QACA,YAkBC;CACD,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,KAAK;CAC5C,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,KAAK;CAClD,MAAM,CAAC,KAAK,UAAU,MAAM,SAAS,EAAE;CACvC,MAAM,CAAC,UAAU,eAAe,MAAM,SAAwB,IAAI;CAClE,MAAM,QAAQ,MAAM,OAAyB,IAAI;CACjD,MAAM,cAAc,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC;CAC/C,MAAM,SAAS,MAAe,UAAU,QAAQ,CAAC,IAAI,SAAS,SAAS;CACvE,MAAM,kBAAmB,UAAU,MAAM,SAAS,MAAM,IAAI,SAAS,SAAS;CAC9E,OACE,qBAAC,OAAD;EACM;EACJ,UAAU,WAAW,KAAK;EAC1B,MAAK;EACL,cAAY,aAAa,GAAG,MAAM,6CAA6C;EAC/E,UAAU,MAAM;GACd,MAAM,SAAS,MAAM,KAAK,EAAE,cAAc,KAAK;GAC/C,IAAI,OAAO,UAAU,YAAY;IAC/B,EAAE,eAAe;IACjB,MAAM,MAAM;GACd;EACF;EACA,YAAY,MAAM;GAChB,IAAI,EAAE,QAAQ,WAAW,EAAE,WAAW,EAAE,iBAAiB,YAAY;IACnE,EAAE,eAAe;IACjB,UAAU;GACZ;EACF;EACA,aAAa,MAAM;GACjB,IAAI,CAAC,YAAY;GACjB,EAAE,eAAe;GACjB,QAAQ,IAAI;EACd;EACA,cAAc,MAAM;GAElB,IAAI,CAAC,EAAE,cAAc,SAAS,EAAE,aAA4B,GAAG,QAAQ,KAAK;EAC9E;EACA,SAAS,MAAM;GACb,IAAI,CAAC,YAAY;GACjB,EAAE,eAAe;GACjB,QAAQ,KAAK;GACb,MAAM,MAAM,KAAK,EAAE,aAAa,KAAK,CAAC;EACxC;EACA,aAAU;EACV,WAAW,GACT,2HACA,OAAO,2CAA2C,0EACpD;EArCF,UAAA;GAuCE,oBAAC,QAAD;IAAM,WAAW,GAAG,qIAAqI,QAAQ,oBAAoB;IAAI,UAAA;GAAW,CAAA;GACpM,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,OAAD;IAAK,WAAU;IAAuC,UAAA,OAAO,mBAAmB;GAAW,CAAA,GAC1F,aAAa,oBAAC,OAAD;IAAK,WAAU;IAA6B,UAAA;GAAU,CAAA,IAAI,IACrE,EAAA,CAAA;GACJ,WAAW,QACV,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,QAAD;IACE,WAAU;IACV,WAAW,MAAM;KACf,EAAE,eAAe;KACjB,EAAE,gBAAgB;KAClB,MAAM,IAAI,IAAI,KAAK;KACnB,IAAI,KAAK,KAAK,CAAC,GAAG;MAChB,MAAM,CAAC;MACP,WAAW,KAAK;MAChB,OAAO,EAAE;MACT,YAAY,IAAI;KAClB,OAAO,YAAY,gDAAgD;IACrE;IACA,YAAY,MAAM;KAChB,IAAI,EAAE,QAAQ,UAAU;MACtB,EAAE,gBAAgB;MAClB,WAAW,KAAK;MAChB,YAAY,IAAI;KAClB;IACF;IAnBF,UAAA,CAqBE,oBAAC,OAAD;KACE,WAAA;KACA,MAAK;KACL,OAAO;KACP,cAAW;KACX,gBAAc,WAAW,OAAO,KAAA;KAChC,WAAW,MAAM,OAAO,EAAE,OAAO,KAAK;KACtC,aAAY;KACZ,SAAS,oBAAC,UAAD,EAAU,QAAQ,IAAM,CAAA;IAClC,CAAA,GACD,oBAAC,QAAD;KAAQ,MAAK;KAAK,MAAK;KAAS,SAAQ;KAAU,UAAA;IAE1C,CAAA,CACJ;GAEL,CAAA,GAAA,WAAW,oBAAC,QAAD,EAAA,UAAS,SAAiB,CAAA,IAAI,IAC1C,EAAA,CAAA,IAEF,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACG,aAAa,SACZ,oBAAC,QAAD;MAAQ,MAAK;MAAK,SAAQ;MAAY,SAAS,oBAAoB,OAAQ,UAAU;MAAc;MAAU,UAAA;KAErG,CAAA,IACN;KACH,WAAW,SACV,oBAAC,QAAD;MAAQ,MAAK;MAAK,SAAQ;MAAQ,UAAU,oBAAC,YAAD,EAAY,QAAQ,IAAM,CAAA;MAAG,SAAS;MAAqB;MAAU,UAAA;KAEzG,CAAA,IACN;KACH,QACC,oBAAC,QAAD;MAAQ,MAAK;MAAK,SAAQ;MAAQ,eAAe,WAAW,IAAI;MAAa;MAAU,UAAA;KAE/E,CAAA,IACN;IACD;;GAEN,UACC,oBAAC,SAAD;IACE,KAAK;IACL,MAAK;IACL,QAAA;IACA,UAAU;IACV,eAAA;IACQ;IACE;IACV,WAAW,MAAM;KACf,QAAQ,MAAM,KAAK,EAAE,OAAO,SAAS,CAAC,CAAC,CAAC;KACxC,EAAE,OAAO,QAAQ;IACnB;GACD,CAAA,IACC;GACH,YAAY,OACX,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACE,oBAAC,QAAD;OAAM,MAAK;OAAS,UAAA;MAAgB,CAAA;MAAC;MAAE;MAAS;KAC5C;IACN,CAAA,GAAA,oBAAC,UAAD;KAAU,OAAO;KAAU,MAAK;KAAM,OAAM;KAAkB,WAAU;IAAY,CAAA,CACjF;GACH,CAAA,IAAA;EACD;;AAET;;AAGA,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,YAAY;;AAIlB,IAAM,UACJ;;AAGF,IAAM,QAAqF;CACzF;EAAE,OAAO;EAAY,OAAO;EAAY,OAAO;EAAQ,aAAa;CAA0B;CAC9F;EAAE,OAAO;EAAQ,OAAO;EAAQ,OAAO;EAAQ,aAAa;CAAa;CACzE;EAAE,OAAO;EAAO,OAAO;EAAO,OAAO;EAAO,aAAa;CAAY;CACrE;EAAE,OAAO;EAAO,OAAO;EAAO,OAAO;EAAO,aAAa;CAAS;CAClE;EAAE,OAAO;EAAO,OAAO;EAAO,OAAO;EAAO,aAAa;CAAW;AACtE;AACA,IAAM,cAAc;;AAGpB,SAAgB,WAAW,MAA0B,MAAmE;CACtH,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,OAAO,SAAS,UAAU,OAAO;CACrC,IAAI,CAAC,WAAW,IAAI,GAAG,OAAO;CAC9B,OAAQ,QAAQ,WAAW,MAAM,KAAK,GAAG,KAAK,CAAC,KAAM;AACvD;;AAGA,SAAS,YAAY,MAA0B,MAAqD;CAClG,IAAI,CAAC,QAAQ,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,WAAW,IAAI,GAAG,OAAO,KAAA;CAC5E,MAAM,KAAK,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK;CAC9C,MAAM,KAAK,IAAI,KAAK,MAAM,KAAK,UAAU,KAAK;CAC9C,OAAO,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAA;AAC1C;;AAGA,SAAgB,SAAS,GAAe,QAAqB,MAA4C;CACvG,MAAM,OAAO,EAAE,GAAG,EAAE;CACpB,OAAO,KAAK;CACZ,MAAM,OAAO,WAAW,aAAa,KAAA,IAAY,SAAS,QAAQ,KAAK,GAAG,KAAK,GAAG,EAAE,KAAK;CACzF,IAAI,MAAM,KAAK,OAAO;CACtB,OAAO;AACT;AAEA,SAAS,aAAa,EACpB,GACA,UACA,UACA,OACA,SACA,UAAU,OACV,MACA,SAWC;CACD,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,QAAQ,EAAE,SAAS;EAAE,GAAG;EAAI,GAAG;CAAG;CACxC,MAAM,SAAS,WAAW,EAAE,MAAM,IAAI;CACtC,MAAM,OAAO,MAAM,MAAM,MAAM,EAAE,UAAU,MAAM;CAGjD,MAAM,WAAW,QAAQ,KAAK,UAAU,SAAS,KAAK,QAAQ,YAAY,EAAE,MAAM,IAAI,KAAK;CAE3F,MAAM,YAAY,GAAW,MAAc;EACzC,MAAM,OAAmB;GAAE,GAAG;GAAG,OAAO;IAAE,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;IAAG,GAAG,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC;GAAE;EAAE;EACvI,SAAS,QAAQ,KAAK,UAAU,cAAc,OAAO,SAAS,MAAM,KAAK,OAAO,IAAI,IAAI,IAAI;CAC9F;CACA,MAAM,eAAe,MAA0C;EAC7D,MAAM,IAAI,EAAE,cAAc,sBAAsB;EAChD,IAAI,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ;EAC3B,UAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAS,MAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAU,GAAG;CACzF;CACA,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAAsC,UAAA;IAA0B,CAAA,GAC/E,OACC,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACG,KAAK;MAAE;MAAI,KAAK;KACb;IACJ,CAAA,IAAA,IACD;;GACJ,UACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;IAAQ,MAAK;IAAQ,UAAA;GAA8G,CAAA,GAClI,OAAO,MACN,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAA4B,UAAA;IAAmC,CAAA,GAC/E,oBAAC,QAAD;KAAM,WAAU;KAA2B,UAAA,MAAM;IAAU,CAAA,CACxD;GACH,CAAA,IAAA,IACJ,EAAA,CAAA,IAEF,qBAAA,UAAA,EAAA,UAAA,CACE,qBAAC,SAAD;IAAO,WAAU;IAAjB,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAA4B,UAAA;IAAc,CAAA,GAC1D,oBAAC,UAAD;KACE,MAAM;KACN,OAAO,EAAE,OAAO;KACN;KACV,WAAW,MAAM;MACf,MAAM,MAAM,EAAE,OAAO;MACrB,MAAM,OAAO,EAAE,GAAG,EAAE;MACpB,IAAI,KAAK,KAAK,MAAM;WACf,OAAO,KAAK;MACjB,SAAS,IAAI;KACf;KACA,aAAY;KACZ,WAAU;KACV,cAAY,GAAG,MAAM;IACtB,CAAA,CACI;GACN,CAAA,GAAA,UACC,oBAAC,QAAD;IAAQ,MAAK;IAAQ,UAAA;GAAoG,CAAA,IAE3H,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,qBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA,CACE,oBAAC,UAAD;QAAU,WAAU;QAAW,QAAQ;QAAK,eAAA;OAAa,CAAA,GAAC,yBAEtD;MACN,CAAA,GAAA,qBAAC,QAAD;OAAM,WAAU;OAAhB,UAAA;QACE,oBAAC,mBAAD;SAAmB,WAAU;SAAS,QAAQ;SAAK,eAAA;QAAa,CAAA;QAAC;QAC1D,MAAM;QAAE;QAAI,MAAM;QAAE;OACvB;MACH,CAAA,CAAA;;KAEL,oBAAC,QAAD;MACE,MAAK;MACL,cAAY,GAAG,MAAM;MACrB,UAAU,YAAY,CAAC;MACvB,kBAAiB;MACjB,OAAO;MACP,gBAAgB,MAAM,QAAQ,MAAM,eAAe,SAAS,SAAS,GAAG,GAAkB,IAAI,CAAC;MAC/F,SAAS,CACP,GAAG,MAAM,KAAK,OAAO;OAAE,OAAO,EAAE;OAAO,OAAO,EAAE;OAAO,MAAM,EAAE;MAAY,EAAE,GAC7E,GAAI,WAAW,cAAc,CAAC;OAAE,OAAO;OAAa,OAAO;OAAU,MAAM;OAAiB,UAAU;MAAK,CAAC,IAAI,CAAC,CACnH;KACD,CAAA;KACA,CAAC,QAAQ,CAAC,WAAW,oBAAC,QAAD;MAAM,WAAU;MAA6B,UAAA;KAAsE,CAAA,IAAI;KAC7I,qBAAC,OAAD;MACE,MAAK;MACL,cAAW;MACX,kBAAgB,GAAG,MAAM,EAAE,YAAY,MAAM,EAAE;MAC/C,iBAAe,MAAM;MACrB,iBAAe;MACf,iBAAe;MACf,iBAAe,YAAY,KAAA;MAC3B,UAAU;MACV,gBAAgB,MAAM,CAAC,YAAY,YAAY,CAAC;MAChD,YAAY,MAAM;OAChB,MAAM,IAAI,EAAE,WAAW,KAAK;OAE5B,MAAM,OAAO;QADiC,WAAW,CAAC,CAAC,GAAG,CAAC;QAAG,YAAY,CAAC,GAAG,CAAC;QAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAAG,WAAW,CAAC,GAAG,CAAC;OAC3G,EAAE,EAAE;OACjB,IAAI,CAAC,QAAQ,UAAU;OACvB,EAAE,eAAe;OACjB,SAAS,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,EAAE;MAC/C;MACA,kBAAgB;MAEhB,WAAU;MACV,OAAO,EAAE,aAAa,SAAS;MArBjC,UAAA,CAuBE,oBAAC,OAAD;OAAK,KAAK,IAAI,EAAE,GAAG;OAAG,KAAI;OAAG,WAAW;OAAO,WAAU;OAAmG,OAAO,EAAE,gBAAgB,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,GAAG;MAAI,CAAA,GACnN,oBAAC,QAAD;OACE,eAAA;OACA,WAAU;OACV,OAAO;QAAE,MAAM,GAAG,MAAM,EAAE;QAAI,KAAK,GAAG,MAAM,EAAE;OAAG;MAClD,CAAA,CACE;;KACL,oBAAC,QAAD;MAAM,WAAU;MAA6B,UAAA;KAAgE,CAAA;IAC1G;GAEL,CAAA,CAAA,EAAA,CAAA;GAEH,WAAW,UACV,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAA4B,UAAA;IAAe,CAAA,GAC3D,oBAAC,QAAD;KAAM,WAAU;KAAkD,UAAA,OAAO,QAAQ,EAAE,QAAQ,gBAAgB,EAAE,GAAG;IAAQ,CAAA,CACrH;GAGL,CAAA,IAAA,qBAAC,SAAD;IAAO,WAAU;IAAjB,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAA4B,UAAA;IAAe,CAAA,GAC3D,oBAAC,OAAD;KACE,MAAK;KACL,OAAO,EAAE,QAAQ,OAAO,QAAQ,gBAAgB,EAAE,GAAG;KAC3C;KACV,YAAY;KACZ,cAAa;KACb,WAAW,MAAM;MACf,MAAM,OAAO,EAAE,GAAG,EAAE;MACpB,IAAI,EAAE,OAAO,OAAO,KAAK,OAAO,EAAE,OAAO;WACpC,OAAO,KAAK;MACjB,SAAS,IAAI;KACf;KACA,WAAU;KACV,cAAY,GAAG,MAAM;IACtB,CAAA,CACI;;EAEN;;AAET;;AAGA,SAAS,WAAW,OAAsD;CACxE,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO,KAAA;CAChD,MAAM,EAAE,OAAO,WAAW;CAC1B,OAAO,OAAO,UAAU,YAAY,OAAO,WAAW,YAAY,QAAQ,KAAK,SAAS,IAAI;EAAE,GAAG;EAAO,GAAG;CAAO,IAAI,KAAA;AACxH;;;;;;AAQA,SAAS,aAAa,EACpB,IACA,OACA,KACA,UACA,QACA,SACA,MACA,cAUC;CACD,MAAM,MAAM,MAAM,OAA0B,IAAI;CAChD,MAAM,CAAC,MAAM,WAAW,MAAM,SAAS,KAAK;CAE5C,MAAM,UAAU,MAAM,OAAO,KAAK;CAClC,MAAM,gBAAgB;EACpB,IAAI,QAAQ,WAAW,CAAC,YAAY,IAAI,SAAS,MAAM,EAAE,eAAe,KAAK,CAAC;EAC9E,QAAQ,UAAU;CACpB,GAAG,CAAC,UAAU,CAAC;CACf,MAAM,QAAQ,CAAC;CACf,MAAM,QAAQ,YAAY,QAAQ,CAAC;CACnC,MAAM,YAAY,SAAS,CAAC,SAAS,CAAC,CAAC;CAGvC,MAAM,SAAS,MAAM,WAAW,SAAS;CACzC,OACE,qBAAC,OAAD;EACE,WAAW,GACT,+FACA,6EACA,OAAO,0CAA0C,0BACjD,QAAQ,eAAe,0CACzB;EANF,UAAA,CAQA,oBAAC,SAAD;GAAS,SAAS;GAChB,UAAA,qBAAC,UAAD;IACE,KAAK;IACD;IACJ,MAAK;IACL,aAAU;IACV,UAAU;IACV,SAAS;IACT,cAAY,QAAQ,aAAa,UAAU,WAAW;IACtD,YAAY,aAAa,MAAM;KAAE,EAAE,eAAe;KAAG,QAAQ,IAAI;IAAG,IAAI,KAAA;IACxE,aAAa,kBAAkB,QAAQ,KAAK,IAAI,KAAA;IAChD,QAAQ,aAAa,MAAM;KAAE,EAAE,eAAe;KAAG,QAAQ,KAAK;KAAG,QAAQ,MAAM,KAAK,EAAE,aAAa,KAAK,CAAC;IAAG,IAAI,KAAA;IAChH,WAAU;IAXZ,UAAA;KAaE,oBAAC,QAAD;MACE,eAAA;MACA,WAAW,GACT,iFACA,QAAQ,2CAA2C,GAAG,uBAAuB,OAAO,CACtF;MAEC,UAAA,QAAQ,oBAAC,UAAD;OAAU,WAAU;OAAyB,QAAQ;MAAM,CAAA,IAAI,oBAAC,OAAD;OAAK,KAAK;OAAK,KAAI;OAAG,WAAU;MAA4B,CAAA;KAChI,CAAA;KACN,oBAAC,QAAD;MAAM,eAAA;MAAY,WAAW,GAAG,2BAA2B,QAAQ,kBAAkB,aAAa;MAC/F,UAAA,QAAS,OAAO,eAAe,aAAc;KAC1C,CAAA;KACL,QAAQ,OAAO,oBAAC,aAAD;MAAa,eAAA;MAAY,WAAU;MAAkC,QAAQ;KAAM,CAAA;IAC7F;;EACD,CAAA,GACN,SAAS,oBAAC,QAAD;GAAM,aAAU;GAAsB,WAAU;GAAwD,UAAA;EAAa,CAAA,IAAI,IAChI;;AAET;AAEA,SAAgB,aAAa,EAAE,OAAO,OAAO,UAAU,OAAO,UAAU,IAAI,QAAsB;CAChG,MAAM,EAAE,GAAG,UAAU,QAAQ,SAAS;CACtC,MAAM,MAAM,UAAU;CACtB,MAAM,UAAU,CAAC,CAAC,EAAE,iBAAiB,IAAI;CACzC,MAAM,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,eAAe,IAAI;CACnD,MAAM,eAAe,OAAO,UAAU,YAAY,MAAM,eAAe;CACvE,MAAM,IAAI,UAAU,KAAK;CACzB,MAAM,QAAQ,SAAS;EAAE,IAAI,GAAG;EAAI,KAAK,GAAG,OAAO;CAAG,CAAC;CAEvD,MAAM,SAAS,MAAM,UAAU,kBAAkB;CACjD,MAAM,QAA6B,MAAM,UAAU,CAAC,KAAK,IAAI,CAAC,SAAS,KAAK;CAO5E,MAAM,CAAC,QAAQ,aAAa,MAAM,SAA4D;CAC9F,MAAM,UAAU,UAAU,KAAK,OAAO,QAAQ,EAAE,MAAM;EAAE,GAAG,OAAO;EAAG,GAAG,OAAO;CAAE,IAAI,KAAA;CACrF,MAAM,eAAe,QAAiC;EACpD,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,gBAAgB,CAAC,IAAI,eAAe;EAC5E,MAAM,OAAO;GAAE,KAAK,EAAE;GAAK,GAAG,IAAI;GAAc,GAAG,IAAI;EAAc;EACrE,WAAW,SAAU,QAAQ,KAAK,QAAQ,KAAK,OAAO,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,IAAI,OAAO,IAAK;CAC7G;CAGA,MAAM,SAAS,WAAW,KAAK;CAC/B,MAAM,OAAO,OAAO,SAAS,MAAM,SAAS;EAAE,GAAG,MAAM;EAAO,GAAG,MAAM;CAAO,IAAI,UAAU;CAI5F,MAAM,YAAY,MAAyB;EACzC,IAAI,CAAC,GAAG,OAAO,MAAM,UAAU,KAAK,IAAI;EACxC,IAAI,SAAS,OAAO,MAAM,EAAE,GAAG;EAC/B,IAAI,gBAAgB,CAAC,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,EAAE,IAAI,OAAO,MAAM,EAAE,GAAG;EACzF,MAAM,CAAC;CACT;CACA,MAAM,CAAC,QAAQ,aAAa,MAAM,SAAS,KAAK;CAChD,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,KAAK;CAClD,MAAM,KAAK,UAAU,QAAQ,UAAU,MAAM,EAAE,MAAM,SAAS,UAAU,EAAE,EAAE,CAAC,CAAC;CAC9E,MAAM,UAAU,EAAE,eAAe,CAAC,iBAAiB,UAAU,IAAI,IAAI,KAAA;CACrE,MAAM,SAAS,EAAE,gBAAgB,SAAA,CAAU;CAE3C,IAAI,YAAY,OAAO,KAAK,GAAG;EAE7B,MAAM,QAAQ,EAAE,eACZ,CACE,GAAI,IAAI,CAAC;GAAE,KAAK,EAAE;GAAK;GAAO,SAAS;EAAK,CAAC,IAAI,CAAC,GAClD,GAAG,MAAM,QAAQ,MAAM,EAAE,QAAQ,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,OAAO,cAAc;GAAE;GAAK,OAAO;EAAO,EAAE,CACrI,IACA,KAAA;EACJ,MAAM,YAAY,WAAoB;GACpC,MAAM,IAAI,UAAU,MAAM;GAC1B,IAAI,GAAG,SAAS,UAAU;IAAE,IAAI,EAAE,MAAM;IAAI,KAAK,EAAE;IAAK,MAAM,EAAE;IAAM,KAAK,EAAE,QAAQ,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,KAAA;IAAY,MAAM;GAAM,CAAC,CAAC;GAC3J,UAAU,KAAK;EACjB;EACA,OACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,cAAD;KACM;KACJ,OAAO,MAAM;KACb,KAAK,IAAI,IAAI,EAAE,GAAG,IAAI,KAAA;KACZ;KACV,QAAQ;KACR,SAAS,GAAG;KACZ,MAAM,GAAG,YAAY;KACrB,YAAY;IACb,CAAA;IACA,GAAG,QAAQ,oBAAC,QAAD,EAAA,UAAS,GAAG,MAAc,CAAA,IAAI;IACzC,CAAC,YAAY,CAAC,UAAU,oBAAC,QAAD;KAAQ,MAAK;KAAS,UAAA;IAAmB,CAAA,IAAI;IACtE,oBAAC,aAAD;KACE,MAAM;KACN,cAAc;KACd,QAAQ,CAAC,KAAK;KACd,OAAO,IAAI,iBAAiB;KAC5B,SAAS,MAAM,EAAE,MAAM,SAAS,UAAU,EAAE,EAAE,CAAC;KAC/C,UAAU,KAAK,CAAC,iBAAiB;MAAE,SAAS,IAAI;MAAG,UAAU,KAAK;KAAG,IAAI,KAAA;KAClE;KACP,YAAY,WAAW,KAAA,IAAY;IACpC,CAAA;GACE;;CAET;CAEA,IAAI,CAAC,GACH,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,UAAD;IACM;IACJ,OAAM;IACN,MAAK;IACG;IACR,MAAM,oBAAC,WAAD,EAAW,QAAQ,IAAM,CAAA;IAC/B,SAAS,GAAG;IACZ,WAAW;IACX,OAAO,WAAW,KAAA,KAAa,QAAQ,SAAS;KAAE;KAAK,MAAM,gBAAgB,GAAG,KAAK,KAAA;IAAU,CAAC;IAChG,QAAQ,GAAG;IACX,UAAU;IACV,UAAU,GAAG;GACd,CAAA;GACA,GAAG,QAAQ,oBAAC,QAAD,EAAA,UAAS,GAAG,MAAc,CAAA,IAAI;GAC1C,oBAAC,aAAD;IAAa,MAAM;IAAQ,cAAc;IAAW,QAAQ;IAAO,SAAS,MAAM,EAAE,MAAM,SAAS,UAAU,EAAE,EAAE,CAAC;GAAI,CAAA;EACnH;;CAKT,MAAM,aAAa,MAAM,MAAM,MAAM,EAAE,UAAU,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC,EAAE;CAC5E,MAAM,QAAQ,EAAE,SAAS;EAAE,GAAG;EAAI,GAAG;CAAG;CACxC,MAAM,MAAM,UAAU,OAAO,MAAM,EAAE;CACrC,MAAM,OAAO,OAAO,QAAQ,EAAE,QAAQ,gBAAgB,EAAE,GAAG;CAC3D,MAAM,WAAW,MAAqB;EACpC,MAAM,OAAO,UAAU,CAAC;EACxB,IAAI,CAAC,KAAK,OAAO,EAAE,KAAK,KAAK,MAAM,EAAE;EACrC,IAAI,EAAE,OAAO,KAAK,QAAQ,EAAE;EAC5B,SAAS,IAAI;CACf;CACA,MAAM,oBAAoB,OAAO,iBAAiB,WAAW,IAAI,GAAG,CAAC;CACrE,OACE,qBAAC,SAAD;EAAS,MAAM;EAAS,cAAc;EAAtC,UAAA;GACE,qBAAC,eAAD;IACE,WAAW,GAAG,yBAAyB,IAAI,YAAY,cAAc,UAAU;IAC/E,UAAU,MAA4B;KACpC,MAAM,QAAQ,MAAM,KAAK,EAAE,cAAc,KAAK;KAC9C,IAAI,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU;MACvC,EAAE,eAAe;MACjB,GAAG,IAAI,KAAK;KACd;IACF;IARF,UAAA;KAUE,qBAAC,OAAD;MACE,aAAU;MACV,WAAU;MACV,OAAO,EAAE,aAAa,cAAc,eAAe,SAAS,aAAa,OAAO;MAHlF,UAAA;OAKE,oBAAC,UAAD;QACM;QACJ,MAAK;QACL,UAAU;QACV,eAAgB,UAAU,QAAQ,IAAI,YAAY;QAClD,cAAY,UAAU,WAAW,MAAM,UAAU,GAAG,MAAM,MAAM;QAChE,WAAU;QAEV,UAAA,oBAAC,OAAD;SACE,KAAK,IAAI,EAAE,GAAG;SACd,KAAK,OAAO;SACZ,KAAK;SACL,SAAS,MAAM,YAAY,EAAE,aAAa;SAC1C,WAAU;SACV,OAAO,EAAE,gBAAgB,GAAG,MAAM,EAAE,IAAI,MAAM,EAAE,GAAG;QACpD,CAAA;OACK,CAAA;OACP,WAAW,OACV,qBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACG,UACC,qBAAC,UAAD;SAAQ,MAAK;SAAS,SAAS;SAAS,WAAU;SAAlD,UAAA,CACE,oBAAC,aAAD;UAAa,WAAU;UAAW,QAAQ;UAAK,eAAA;SAAa,CAAA,GAAC,SAEvD;QACN,CAAA,IAAA,MACJ,oBAAC,SAAD;SAAS,SAAQ;SACf,UAAA,oBAAC,UAAD;UAAQ,MAAK;UAAS,cAAW;UAAe,eAAe,SAAS,IAAI;UAAG,WAAU;UACvF,UAAA,oBAAC,OAAD;WAAO,WAAU;WAAW,QAAQ;WAAK,eAAA;UAAa,CAAA;SAChD,CAAA;QACD,CAAA,CACN;;OAEN,GAAG,YAAY,OACd,oBAAC,OAAD;QAAK,WAAU;QACb,UAAA,oBAAC,UAAD;SAAU,OAAO,GAAG;SAAU,MAAK;SAAM,MAAK;SAAK,OAAM;QAAmB,CAAA;OACzE,CAAA,IACH;MACD;;KACL,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,qBAAC,QAAD;OAAM,aAAU;OAAoB,WAAU;OAA9C,UAAA;QACG;QACA,OACC,qBAAA,UAAA,EAAA,UAAA,CACG,OACD,qBAAC,QAAD;SAAM,WAAU;SAAhB,UAAA;UACG,KAAK;UAAE;UAAI,KAAK;SACb;QACN,CAAA,CAAA,EAAA,CAAA,IACA;QACH;QACA,MACC,oBAAC,QAAD;SAAM,WAAU;SAAgB,UAAA;QAAkB,CAAA,IAElD,qBAAC,QAAD;SAAM,WAAU;SAAhB,UAAA,CACE,oBAAC,mBAAD;UAAmB,WAAU;UAAS,QAAQ;UAAK,eAAA;SAAa,CAAA,GAAC,aAE7D;;OAEJ;MACN,CAAA,GAAA,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,aAAD;OACE,cAAW;OACX,WAAU;OAEV,UAAA,oBAAC,UAAD;QAAU,WAAU;QAAS,QAAQ;QAAK,eAAA;OAAa,CAAA;MAC5C,CAAA,GACb,qBAAC,aAAD;OAAa,OAAM;OAAM,WAAU;OAAnC,UAAA;QACE,oBAAC,UAAD;SAAU,MAAM,oBAAC,mBAAD,EAAmB,QAAQ,IAAM,CAAA;SAAG,SAAS;SAAa,UAAA;QAEhE,CAAA;QAEV,oBAAC,UAAD;SAAU,MAAM,oBAAC,aAAD,EAAa,QAAQ,IAAM,CAAA;SAAG,UAAU,CAAC;SAAS,SAAS;SAAS,UAAA;QAE1E,CAAA;QACV,oBAAC,UAAD;SAAU,MAAM,oBAAC,kBAAD,EAAkB,QAAQ,IAAM,CAAA;SAAG,eAAe,OAAO,KAAK,IAAI,EAAE,GAAG,GAAG,UAAU,UAAU;SAAG,UAAA;QAEvG,CAAA;QACV,oBAAC,eAAD,CAAgB,CAAA;QAChB,oBAAC,UAAD;SAAU,QAAA;SAAO,MAAM,oBAAC,WAAD,EAAW,QAAQ,IAAM,CAAA;SAAG,UAAU;SAAU,eAAe,CAAC,YAAY,SAAS,IAAI;SAAG,UAAA;QAEzG,CAAA;OACC;MACT,CAAA,CAAA,EAAA,CAAA,CACH;;KACJ,GAAG,QAAQ,oBAAC,QAAD,EAAA,UAAS,GAAG,MAAc,CAAA,IAAI;IAC7B;;GACf,oBAAC,gBAAD;IAAgB,WAAU;IAAY,OAAM;IAAQ,MAAK;IACvD,UAAA,oBAAC,cAAD;KAAiB;KAAa;KAAoB;KAAU,OAAO,MAAM;KAAgB;KAAkB;KAAe;KAAa;IAAQ,CAAA;GACjI,CAAA;GAChB,oBAAC,aAAD;IAAa,MAAM;IAAQ,cAAc;IAAW,QAAQ;IAAO,SAAS,MAAM,EAAE,MAAM,QAAQ,EAAE,EAAE;GAAI,CAAA;EACnG;;AAEb;AAKA,SAAS,MAAM,EACb,MACA,OACA,UACA,MACA,UACA,UAQC;CACD,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,SAAS,KAAK,OAAO,KAAK,GAAG;CACnC,OACE,qBAAC,OAAD;EACE,KAAK,KAAK,SAAS,KAAK,GAAG;EAC3B,MAAK;EACL,OAAO,KAAK,MAAM,KAAK,GAAG;EAE1B,WAAW,GACT,uJACA,KAAK,WAAW,KAAK,OAAO,2DAC9B;EARF,UAAA;GAUE,oBAAC,OAAD;IACE,GAAK,WAAW,CAAC,IAAI;IACrB,MAAM,KAAA;IACN,UAAU;IACV,cAAY,WAAW,QAAQ,GAAG,MAAM;IACxC,eAAe;IACf,YAAY,MAAM;KAChB,IAAI,CAAC,aAAa,EAAE,QAAQ,YAAY,EAAE,QAAQ,cAAc;MAC9D,EAAE,eAAe;MACjB,SAAS;MACT;KACF;KACA,IAAI,EAAE,QAAQ,SAAS;MACrB,EAAE,eAAe;MACjB,OAAO;MACP;KACF;KACA,IAAI,CAAC,UAAU,OAAO,UAAU,CAAC;IACnC;IACA,WAAU;IAEV,UAAA,oBAAC,OAAD;KAAK,KAAK,IAAI,KAAK,EAAE,GAAG;KAAG,KAAK,KAAK,EAAE,OAAO;KAAI,aAAU;KAAoB,WAAU;KAAyD,WAAW;IAAQ,CAAA;GACnK,CAAA;GACJ,CAAC,KAAK,EAAE,MAAM,oBAAC,QAAD;IAAM,MAAK;IAAM,WAAU;IAAwF,cAAW;GAAe,CAAA,IAAI;GAC/J,WAAW,OACV,oBAAC,UAAD;IACE,MAAK;IAEL,qBAAmB;KACjB,MAAM,OAAO,KAAK,EAAE,OAAO,KAAK,EAAE,QAAQ,gBAAgB,KAAK,EAAE,GAAG;KACpE,OAAO,OAAO,UAAU,SAAS;IACnC,EAAA,CAAG;IACH,gBAAgB,MAAM,EAAE,gBAAgB;IACxC,SAAS;IACT,WAAU;IAEV,UAAA,oBAAC,OAAD;KAAO,WAAU;KAAW,QAAQ;KAAK,eAAA;IAAa,CAAA;GAChD,CAAA;EAEP;;AAET;;AAGA,SAAgB,eAAe,EAAE,OAAO,UAAU,UAAU,OAAO,IAAI,QAAsB;CAC3F,MAAM,EAAE,GAAG,QAAQ,SAAS;CAC5B,MAAM,MAAM,UAAU;CACtB,MAAM,MAAM,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;CAE5C,MAAM,uBAAO,IAAI,IAAoB;CACrC,MAAM,QAAiB,IAAI,KAAK,MAAM;EACpC,MAAM,IAAI,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG;EACpC,MAAM,OAAO,EAAE,MAAM,EAAE;EACvB,MAAM,IAAI,KAAK,IAAI,IAAI,KAAK;EAC5B,KAAK,IAAI,MAAM,IAAI,CAAC;EACpB,OAAO;GAAE,KAAK,IAAI,GAAG,KAAK,GAAG,MAAM;GAAM;GAAG,KAAK;EAAE;CACrD,CAAC;CAED,MAAM,YAAY,IAAI,SAAS,KAAK,IAAI,OAAO,MAAM,OAAO,MAAM,QAAQ;CAC1E,MAAM,OAAO,MAAmB,aAAa,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,MAAM;CAC1E,MAAM,SAAS,SAAoB,SAAS,IAAI;CAChD,MAAM,OAAO,WAA4B,MAAM,CAAC,GAAG,KAAK,GAAG,OAAO,KAAK,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;CAChG,MAAM,CAAC,QAAQ,aAAa,MAAM,SAAS,KAAK;CAChD,MAAM,KAAK,UAAU,WAAW,SAAS,GAAG;CAC5C,MAAM,OAAO,MAAM,KAAK,OAAO,GAAG,GAAG;CACrC,MAAM,OAAO,eACX,OACC,MAAM,OAAO;EACZ,MAAM,OAAO,CAAC,GAAG,GAAG;EACpB,MAAM,CAAC,SAAS,KAAK,OAAO,MAAM,CAAC;EACnC,KAAK,OAAO,IAAI,GAAG,KAAK;EACxB,MAAM,IAAI;CACZ,GACA;EAAE,MAAM;EAAQ,UAAU;CAAS,CACrC;CACA,MAAM,MAAM,MAAM,YAAY;CAC9B,MAAM,SAAS,CAAC,aAAa,OAAO,QAAQ,MAAM,SAAS,SAAS,EAAE,eAAe,GAAG;CACxF,MAAM,QAAQ,GAAW,OAAc,GAAG,EAAE,SAAS,gBAAgB,GAAG,EAAE,GAAG,KAAK,SAAS,IAAI;CAC/F,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAS;IAAI,MAAK;IAAO,cAAY,MAAM;IAAO,WAAU;IAA5D,UAAA,CACG,MAAM,KAAK,IAAI,MACd,oBAAC,OAAD;KAEE,MAAM;KACN,OAAO,KAAK,GAAG,EAAE;KACP;KACJ;KAEN,cAAe,EAAE,aAAa,CAAC,WAAW,EAAE,UAAU;MAAE,OAAO,IAAI;MAAO,MAAM,CAAC,GAAG,MAAM,CAAC;MAAG,OAAO,KAAK,GAAG,EAAE;KAAE,CAAC,IAAI,OAAO,KAAK,IAAI,GAAG,EAAE,GAAG,GAAG,UAAU,UAAU;KACrK,gBAAgB,MAAM,IAAI,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC;IACpD,GARM,GAAG,GAQT,CACF,GACA,SAGC,oBAAC,OAAD;KAAK,MAAK;KAAW,WAAU;KAC7B,UAAA,qBAAC,UAAD;MACE,MAAK;MACL,eAAgB,EAAE,cAAc,UAAU,IAAI,IAAI,GAAG,OAAO,SAAS,eAAe,GAAG,GAAG,OAAO,CAAC,EAAE,MAAM;MAC1G,UAAU,MAAM;OACd,MAAM,QAAQ,MAAM,KAAK,EAAE,cAAc,KAAK;OAC9C,IAAI,MAAM,UAAU,GAAG,KAAK;QAC1B,EAAE,eAAe;QACjB,GAAG,IAAI,KAAK;OACd;MACF;MACA,aAAa,MAAM,GAAG,OAAO,EAAE,eAAe;MAC9C,SAAS,MAAM;OACb,IAAI,CAAC,GAAG,KAAK;OACb,EAAE,eAAe;OACjB,GAAG,IAAI,MAAM,KAAK,EAAE,aAAa,KAAK,CAAC;MACzC;MACA,WAAU;MAhBZ,UAAA,CAkBE,oBAAC,UAAD;OAAU,WAAU;OAAS,QAAQ;OAAK,eAAA;MAAa,CAAA,GAAC,YAElD;;IACL,CAAA,IACH,IACD;;GACJ,KAAK;GACL,GAAG,OAAO,CAAC,EAAE,cACZ,oBAAC,SAAD;IACE,IAAI,GAAG,GAAG;IACV,MAAK;IACL,QAAA;IACA,UAAU;IACV,eAAA;IACA,QAAO;IACP,UAAA;IACA,WAAW,MAAM;KACf,GAAG,MAAM,MAAM,KAAK,EAAE,OAAO,SAAS,CAAC,CAAC,CAAC;KACzC,EAAE,OAAO,QAAQ;IACnB;GACD,CAAA,IACC;GACH,GAAG,YAAY,OAAO,oBAAC,UAAD;IAAU,OAAO,GAAG;IAAU,MAAK;IAAM,MAAK;IAAK,OAAM;GAAmB,CAAA,IAAI;GACtG,GAAG,QAAQ,oBAAC,QAAD,EAAA,UAAS,GAAG,MAAc,CAAA,IAAI;GACzC,CAAC,YAAY,CAAC,EAAE,eAAe,CAAC,GAAG,MAAM,oBAAC,QAAD;IAAQ,MAAK;IAAS,UAAA;GAAkB,CAAA,IAAI;GACtF,oBAAC,aAAD;IAAa,MAAM;IAAQ,cAAc;IAAW,UAAA;IAAS,QAAQ,CAAC,SAAS,KAAK;IAAG,SAAS,MAAM,EAAE,UAAU,IAAI,OAAO,OAAO,EAAE,MAAM,GAAG,KAAK,IAAI,GAAG,MAAM,MAAM,MAAM,CAAC,IAAI,CAAC;GAAI,CAAA;EACpL;;AAET;AAKA,IAAM,YAAY,MAAiC;CACjD,IAAI,OAAO,MAAM,UAAU,OAAO,IAAI,EAAE,KAAK,EAAE,IAAI;CACnD,OAAO,MAAM,CAAC,KAAK,OAAO,EAAE,QAAQ,YAAY,EAAE,MAAO,IAAkB;AAC7E;AACA,IAAM,iBAAiB,OAAiC;CAAE,KAAK,EAAE;CAAK,IAAI,EAAE;CAAI,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAAG;AAEpH,SAAgB,YAAY,EAAE,OAAO,UAAU,UAAU,MAAoB;CAC3E,MAAM,EAAE,GAAG,UAAU,QAAQ,SAAS;CACtC,MAAM,IAAI,SAAS,KAAK;CACxB,MAAM,QAAQ,SAAS;EAAE,IAAI,GAAG;EAAI,KAAK,GAAG,OAAO;CAAG,CAAC;CACvD,MAAM,CAAC,QAAQ,aAAa,MAAM,SAAS,KAAK;CAChD,MAAM,KAAK,UAAU,KAAK,SAAS,MAAM,EAAE,MAAM,SAAS,cAAc,EAAE,EAAE,CAAC,CAAC;CAC9E,MAAM,UAAU,EAAE,eAAe,CAAC,iBAAiB,UAAU,IAAI,IAAI,KAAA;CACrE,MAAM,WAAW,oBAAC,aAAD;EAAa,MAAM;EAAQ,cAAc;EAAW,QAAQ,CAAC,MAAM;EAAG,SAAS,MAAM,EAAE,MAAM,SAAS,cAAc,EAAE,EAAE,CAAC;CAAI,CAAA;CAC9I,IAAI,CAAC,GACH,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,UAAD;IAAc;IAAI,OAAM;IAAa,MAAK;IAA4B,QAAO;IAAI,MAAM,oBAAC,cAAD,EAAc,QAAQ,IAAM,CAAA;IAAG,SAAS,GAAG;IAAK,WAAW;IAAS,QAAQ,GAAG;IAAU,UAAU;IAAU,UAAU,GAAG;GAAW,CAAA;GAC3N,GAAG,QAAQ,oBAAC,QAAD,EAAA,UAAS,GAAG,MAAc,CAAA,IAAI;GACzC;EACE;;CAET,MAAM,OAAO,OAAO,QAAQ,EAAE,QAAQ,gBAAgB,EAAE,GAAG;CAC3D,MAAM,OAAO,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,GAAA,EAAK,YAAY,KAAK;CAChF,MAAM,OAAO,CAAC,IAAI,YAAY,GAAG,OAAO,OAAO,YAAY,MAAM,IAAI,IAAI,IAAI,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK;CACzG,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,QAAD;IAAM,eAAA;IAAY,WAAU;IACzB,UAAA;GACG,CAAA;GACN,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,KAAD;KAAO;KAAI,MAAM,IAAI,EAAE,GAAG;KAAG,QAAO;KAAS,KAAI;KAAa,WAAU;KACrE,UAAA;IACA,CAAA,GACH,oBAAC,OAAD;KAAK,WAAU;KAA6B,UAAA;IAAU,CAAA,CACnD;;GACJ,UACC,oBAAC,QAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,SAAS;IAAS,UAAA;GAE5C,CAAA,IACN;GACJ,qBAAC,MAAD,EAAA,UAAA,CACE,oBAAC,aAAD;IAAa,QAAQ,oBAAC,YAAD;KAAY,OAAM;KAAe,MAAK;IAAM,CAAA;IAC/D,UAAA,oBAAC,UAAD,EAAU,QAAQ,IAAM,CAAA;GACb,CAAA,GACb,qBAAC,aAAD;IAAa,OAAM;IAAnB,UAAA;KACE,oBAAC,UAAD;MAAU,MAAM,oBAAC,cAAD,EAAc,QAAQ,IAAM,CAAA;MAAG,eAAe,OAAO,KAAK,IAAI,EAAE,GAAG,GAAG,UAAU,UAAU;MAAG,UAAA;KAEnG,CAAA;KACV,oBAAC,eAAD,CAAgB,CAAA;KAChB,oBAAC,UAAD;MAAU,QAAA;MAAO,MAAM,oBAAC,WAAD,EAAW,QAAQ,IAAM,CAAA;MAAG,UAAU;MAAU,eAAe,CAAC,YAAY,SAAS,IAAI;MAAG,UAAA;KAEzG,CAAA;IACC;GACT,CAAA,CAAA,EAAA,CAAA;GACL;EACE;;AAET;AAGA,IAAa,iBAAiB,QAC5B,QAAQ,KAAK,GAAG,IAAI,YAAY,QAAQ,KAAK,GAAG,IAAI,UAAU,OAAO,KAAK,GAAG,IAAI,SAAS,0BAA0B,KAAK,GAAG,IAAI,QAAQ,MAAM,SAAS;AACzJ,IAAa,aAAa,QAAgB,IAAI,MAAM,gDAAgD,CAAC,GAAG;AACxG,IAAM,eAAe,QAAgB,0BAA0B,KAAK,GAAG;AAEvE,SAAgB,aAAa,EAAE,KAAK,QAAQ,SAA0D;CACpG,MAAM,EAAE,QAAQ,SAAS;CACzB,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,KAAK;CAClD,MAAM,gBAAgB,WAAW,KAAK,GAAG,CAAC,GAAG,CAAC;CAC9C,MAAM,KAAK,UAAU,GAAG;CACxB,MAAM,QAAQ,SAAS,IAAI,MAAM,IAAI,KAAK,0BAA0B,GAAG,kBAAkB,KAAA;CACzF,IAAI,WAAW,IACb,OAAO,oBAAC,UAAD;EAAe;EAAO,KAAK,0CAA0C,GAAG;EAAc,OAAM;EAA4B,WAAU;CAA6D,CAAA;CACxM,IAAI,WAAW,YAAY,GAAG,GAAG,OAAO,oBAAC,SAAD;EAAO,KAAK,IAAI,GAAG;EAAG,QAAQ;EAAO,UAAA;EAAS,UAAA;EAAS,WAAU;CAAmF,CAAA;CAC5L,MAAM,WAAW,CAAC,CAAC,MAAM,YAAY,GAAG;CACxC,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACG,QAAQ,oBAAC,OAAD;IAAK,KAAK;IAAO,KAAK,GAAG,MAAM;IAAU,WAAU;GAAqC,CAAA,IAAI;GACrG,oBAAC,UAAD;IACE,MAAK;IACL,cAAY,WAAW,iBAAiB;IACxC,eAAgB,WAAW,WAAW,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,GAAG,UAAU,UAAU;IACxF,WAAU;IAET,UAAA,WAAW,oBAAC,gBAAD;KAAgB,WAAU;KAAS,QAAQ;KAAK,eAAA;IAAa,CAAA,IAAI,oBAAC,kBAAD;KAAkB,WAAU;KAAS,QAAQ;KAAK,eAAA;IAAa,CAAA;GACtI,CAAA;GACR,qBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CACE,oBAAC,WAAD;KAAW,WAAU;KAAW,QAAQ;KAAK,eAAA;IAAa,CAAA,GACzD,cAAc,GAAG,CACd;;EACH;;AAET;;;;;;AAOA,SAAgB,aAAa,EAAE,OAAO,OAAO,UAAU,UAAU,IAAI,UAAwB;CAC3F,MAAM,MAAM,MAAM,KAAK,KAAK,OAAO,MAAM,QAAQ,WAAY,QAA6C;CAC1G,MAAM,SAAS,OAAO,UAAU,WAAW,QAAS,KAAK,OAAO;CAChE,MAAM,CAAC,OAAO,YAAY,MAAM,SAAS,MAAM;CAC/C,MAAM,CAAC,SAAS,cAAc,MAAM,SAAS,KAAK;CAClD,MAAM,gBAAgB,SAAS,MAAM,GAAG,CAAC,MAAM,CAAC;CAChD,MAAM,UAAU,QAAgB;EAC9B,MAAM,MAAM,IAAI,KAAK;EACrB,IAAI,QAAQ,UAAU,CAAC,WAAW,GAAG,GAAG;EACxC,IAAI,QAAQ,IAAI,OAAO,SAAS,MAAM,OAAO,EAAE;EAC/C,SAAS,MAAM;GAAE,GAAG;GAAK;EAAI,IAAI,GAAG;CACtC;CACA,MAAM,MAAM,MAAM,KAAK,MAAM,MAAM,CAAC,WAAW,KAAK;CACpD,MAAM,UAAU,GAAG,GAAG;CACtB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,OAAD;IACM;IACJ,OAAO;IACG;IACV,gBAAc,OAAO,UAAU,OAAO,KAAA;IACtC,oBAAkB,OAAO,UAAU,UAAU,KAAA;IAC7C,cAAc;KACZ,WAAW,IAAI;KACf,SAAS;IACX;IACA,YAAY,MAAM;KAChB,IAAI,EAAE,QAAQ,YAAY,UAAU,QAAQ;MAC1C,EAAE,gBAAgB;MAClB,SAAS,MAAM;KACjB;IACF;IACA,aAAY;IACZ,SAAS,oBAAC,WAAD,EAAW,QAAQ,IAAM,CAAA;IAClC,WAAW,MAAM;KACf,SAAS,EAAE,OAAO,KAAK;KACvB,OAAO,EAAE,OAAO,KAAK;IACvB;GACD,CAAA;GACA,OAAO,UACN,oBAAC,KAAD;IAAG,IAAI;IAAS,MAAK;IAAQ,WAAU;IAAiC,UAAA;GAErE,CAAA,IACD;GAGH,SAAS,oBAAC,cAAD;IAAc,KAAK;IAAQ,QAAQ,KAAK;IAAQ,OAAO,MAAM;GAAQ,CAAA,IAAI,oBAAC,KAAD;IAAG,WAAU;IAA4B,UAAA;GAAuF,CAAA;EAChN;;AAET"}
@@ -7,6 +7,8 @@
7
7
  * lookupReferences → the stored ids read back by id (entry / page / form / collection), so a chosen value shows its
8
8
  * title, and a deleted one shows as Missing
9
9
  * createReference → only where a real create path exists (a draft entry in one model); absent hides "Create new"
10
+ * createDisabledReason → when createReference is absent, why (the empty state of a one-model picker says it)
11
+ * useReferenceCreate → per target model: may it take a draft from a title here, else why (over createDisabledReason)
10
12
  *
11
13
  * Each rejects with an Error whose message is the reason in words (the backend's named code included); the control
12
14
  * shows it in place.
@@ -29,7 +31,16 @@ export interface KitReferenceOption {
29
31
  avatar?: boolean;
30
32
  /** the record's cover image (V2 RefOption.cover): the row's square thumbnail when it is not a person */
31
33
  cover?: string | null;
34
+ /** a draft's required fields still empty (a picker-made draft): its chip reads "Draft · N required fields empty" */
35
+ missingRequired?: number;
32
36
  }
37
+ /** Whether one entry model takes a draft from a title here: ok, or why not (in words). */
38
+ export type KitReferenceCreateCapability = {
39
+ ok: true;
40
+ } | {
41
+ ok: false;
42
+ reason: string;
43
+ };
33
44
  export interface KitReferenceQuery {
34
45
  /** the field's `reference.to`: entry model ids or slugs, and "page" / "form" / "collection" */
35
46
  to: string[];
@@ -48,11 +59,21 @@ declare module "../context" {
48
59
  }>;
49
60
  /** The options for these ids, in any order; an id it cannot find is left out (the control shows it as Missing). */
50
61
  lookupReferences?: (ids: string[], to: string[]) => Promise<KitReferenceOption[]>;
51
- /** Create a draft in the one entry model `to` names and hand back its option. */
62
+ /** Create a draft in the one entry model `to` names and hand back its option; `created: false` when an existing
63
+ * entry answered (a replay, or the title already there), so the toast says it is used, not made. */
52
64
  createReference?: (req: {
53
65
  to: string;
54
66
  title: string;
55
- }) => Promise<KitReferenceOption>;
67
+ }) => Promise<KitReferenceOption & {
68
+ created?: boolean;
69
+ }>;
70
+ /** Why there is no "Create new" here, in words. With no `createReference`, the picker of one entry model shows it
71
+ * in its empty state, so a search that finds nothing says why nothing can be made from it either. */
72
+ createDisabledReason?: string;
73
+ /** Per target: whether `to` (one entry model; null for any other picker) takes a draft from a title. "Create new"
74
+ * shows only on ok; ok:false puts its reason in the empty state (over createDisabledReason); undefined (not known
75
+ * yet) shows neither. Absent: createReference alone decides, as before. A hook: the picker calls it every render. */
76
+ useReferenceCreate?: (to: string | null) => KitReferenceCreateCapability | undefined;
56
77
  }
57
78
  }
58
79
  export {};
@@ -1,7 +1,7 @@
1
1
  import type { KitReferenceOption } from "./reference-services";
2
2
  import type { ControlProps } from "../types";
3
- /** The noun the picker uses (D48: "CMS item" where V2 says "entry"). */
4
- export declare function referenceNoun(to: string[]): string;
3
+ /** The noun the picker uses: the field's own (`reference.noun`), else D48's ("CMS item" where V2 says "entry"). */
4
+ export declare function referenceNoun(to: string[], noun?: string): string;
5
5
  export declare function RefThumb({ o, size }: {
6
6
  o: Pick<KitReferenceOption, "kind" | "title" | "photo" | "avatar" | "cover"> | null;
7
7
  size?: number;