@bettercms-ai/kit 2.0.0-next.5 → 2.0.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/lossy.d.ts +3 -3
- package/dist/adapters/lossy.js +3 -3
- package/dist/adapters/lossy.js.map +1 -1
- package/dist/adapters/prod-types.d.ts +48 -4
- package/dist/adapters/prod-types.js +4 -3
- package/dist/adapters/prod-types.js.map +1 -1
- package/dist/adapters/schema.d.ts +39 -0
- package/dist/adapters/schema.js +177 -32
- package/dist/adapters/schema.js.map +1 -1
- package/dist/controls/icon.d.ts +1 -1
- package/dist/controls/icon.js +1 -1
- package/dist/controls/icon.js.map +1 -1
- package/dist/controls/reference.js +10 -3
- package/dist/controls/reference.js.map +1 -1
- package/dist/controls/rich-text/article-shell.js +4 -1
- package/dist/controls/rich-text/article-shell.js.map +1 -1
- package/dist/controls/rich-text/blocks.js +2 -1
- package/dist/controls/rich-text/blocks.js.map +1 -1
- package/dist/controls/rich-text/codec.d.ts +2 -0
- package/dist/controls/rich-text/codec.js.map +1 -1
- package/dist/controls/rich-text/related.d.ts +7 -2
- package/dist/controls/rich-text/related.js +14 -5
- package/dist/controls/rich-text/related.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/ledgers/exclusions.v1.js +103 -0
- package/dist/ledgers/exclusions.v1.js.map +1 -0
- package/dist/library/coverage.d.ts +13 -1
- package/dist/library/coverage.js +12 -1
- package/dist/library/coverage.js.map +1 -1
- package/dist/library/kit-catalog.json +149 -149
- package/dist/schema/types.d.ts +1 -0
- package/dist/schema/types.js.map +1 -1
- package/dist/testing/coverage-extras.d.ts +8 -0
- package/dist/testing/coverage-extras.js +44 -0
- package/dist/testing/coverage-extras.js.map +1 -0
- package/dist/testing/exclusions.d.ts +30 -0
- package/dist/testing/exclusions.js +13 -0
- package/dist/testing/exclusions.js.map +1 -0
- package/package.json +2 -2
package/dist/controls/icon.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ICON — the icon field (DESIGN 8.14), V2 controls/icon.tsx fitted to what prod stores.
|
|
3
3
|
*
|
|
4
4
|
* Values (backend reference-validation `icon`, the classic PropsPanel IconValueInput):
|
|
5
|
-
* "arrow-right" a name from the BetterCMS icon set (DOCK_ICON_NAMES,
|
|
5
|
+
* "arrow-right" a name from the BetterCMS icon set (DOCK_ICON_NAMES, 473 names)
|
|
6
6
|
* "https://…/logo.svg" an uploaded icon: an image URL (picked from the media library; a component prop
|
|
7
7
|
* stores the URL string, like the classic panel's codec="url")
|
|
8
8
|
* { url, … } an uploaded icon stored as an image value: shown and kept until replaced
|
package/dist/controls/icon.js
CHANGED
|
@@ -16,7 +16,7 @@ import { Tooltip } from "@base-ui/react/tooltip";
|
|
|
16
16
|
* ICON — the icon field (DESIGN 8.14), V2 controls/icon.tsx fitted to what prod stores.
|
|
17
17
|
*
|
|
18
18
|
* Values (backend reference-validation `icon`, the classic PropsPanel IconValueInput):
|
|
19
|
-
* "arrow-right" a name from the BetterCMS icon set (DOCK_ICON_NAMES,
|
|
19
|
+
* "arrow-right" a name from the BetterCMS icon set (DOCK_ICON_NAMES, 473 names)
|
|
20
20
|
* "https://…/logo.svg" an uploaded icon: an image URL (picked from the media library; a component prop
|
|
21
21
|
* stores the URL string, like the classic panel's codec="url")
|
|
22
22
|
* { url, … } an uploaded icon stored as an image value: shown and kept until replaced
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.js","names":[],"sources":["../../src/controls/icon.tsx"],"sourcesContent":["/**\n * ICON — the icon field (DESIGN 8.14), V2 controls/icon.tsx fitted to what prod stores.\n *\n * Values (backend reference-validation `icon`, the classic PropsPanel IconValueInput):\n * \"arrow-right\" a name from the BetterCMS icon set (DOCK_ICON_NAMES, 472 names)\n * \"https://…/logo.svg\" an uploaded icon: an image URL (picked from the media library; a component prop\n * stores the URL string, like the classic panel's codec=\"url\")\n * { url, … } an uploaded icon stored as an image value: shown and kept until replaced\n * null no icon (\"No icon\"; the backend skips an empty value)\n *\n * The grid offers the BetterCMS set, the one prod accepts. Search also matches a name's Tabler twin through the\n * Tabler ↔ dock adapter (adapters/icons.ts), so \"map\" finds earth-americas. A stored name outside the set (a stale\n * Tabler or Lucide name) is shown with its reason and kept until the author picks another.\n *\n * Glyphs: the host draws them (KitServices.IconGlyph: the dashboard's DockIcon, the set the site renders). With no\n * host renderer the kit draws the Tabler twin, loaded on first use; a name with no Tabler twin shows its name.\n */\nimport * as React from \"react\";\nimport type { Icon as TablerIcon } from \"@tabler/icons-react\";\nimport { IconAlertTriangle, IconChevronDown, IconPhoto, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { iconLabel } from \"../lib/icons\";\nimport { useKitServices } from \"../context\";\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET } from \"../adapters/prod-types\";\nimport { tablerIconOf } from \"../adapters/icons\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { TooltipLayer } from \"../ui/tooltip-root\";\n\n/* ── Glyphs ───────────────────────────────────────────────────────────── */\ndeclare module \"../context\" {\n interface KitServices {\n /**\n * Draws one icon of the BetterCMS set by name, aria-hidden (the name beside it is the accessible text): the glyphs\n * the site renders. The dashboard passes `DockIcon` (src/components/dock/DockIcon). Absent → the Tabler twin.\n */\n IconGlyph?: React.ComponentType<{ name: string; className?: string }>;\n }\n}\n\nlet tablerSet: Record<string, unknown> | null = null;\nlet tablerLoad: Promise<void> | null = null;\nconst pascal = (kebab: string) => `Icon${kebab.split(\"-\").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(\"\")}`;\n\n/** The full Tabler set, loaded once and only when no host renderer is provided. */\nfunction useTablerSet(need: boolean): Record<string, unknown> | null {\n const [, landed] = React.useReducer((n: number) => n + 1, 0);\n React.useEffect(() => {\n if (!need || tablerSet) return;\n let live = true;\n tablerLoad ??= import(\"@tabler/icons-react\").then((m) => {\n tablerSet = m as unknown as Record<string, unknown>;\n });\n tablerLoad.then(() => live && landed(), () => {});\n return () => {\n live = false;\n };\n }, [need]);\n return tablerSet;\n}\n\nfunction Glyph({ name, className }: { name: string; className?: string }) {\n const Host = useKitServices().IconGlyph;\n const set = useTablerSet(!Host);\n if (Host) return <Host name={name} className={className} />;\n const T = set?.[pascal(tablerIconOf(name))] as TablerIcon | undefined;\n if (T) return <T className={className} stroke={1.5} aria-hidden />;\n // no Tabler twin (or the set is still loading): the name itself, never a stand-in shape\n return (\n <span aria-hidden className=\"max-w-full truncate px-0.5 text-[9px] leading-3 text-kit-fg-3\">\n {name}\n </span>\n );\n}\n\n/* ── Values ───────────────────────────────────────────────────────────── */\ntype Read =\n | { kind: \"empty\" }\n | { kind: \"name\"; name: string }\n | { kind: \"unknown\"; name: string }\n | { kind: \"upload\"; url: string }\n | { kind: \"unreadable\" };\nconst isUrlish = (s: string) => /[/.]/.test(s);\nfunction readIcon(v: unknown): Read {\n if (v == null || v === \"\") return { kind: \"empty\" };\n if (typeof v === \"string\") return DOCK_ICON_NAME_SET.has(v) ? { kind: \"name\", name: v } : isUrlish(v) ? { kind: \"upload\", url: v } : { kind: \"unknown\", name: v };\n if (isObj(v) && typeof v.url === \"string\" && v.url) return { kind: \"upload\", url: v.url };\n return { kind: \"unreadable\" };\n}\nconst fileName = (url: string) => decodeURIComponent(url.split(/[?#]/)[0].split(\"/\").pop() || url);\n\n/** Names picked this session, newest first (shown as \"Recent\"). */\nconst recents: string[] = [];\nconst pushRecent = (name: string) => {\n const i = recents.indexOf(name);\n if (i !== -1) recents.splice(i, 1);\n recents.unshift(name);\n recents.length = Math.min(recents.length, COLS);\n};\n\n/* ── The grid: one tab stop, arrow keys, Home / End ───────────────────── */\nconst COLS = 8;\nconst norm = (q: string) => q.toLowerCase().trim().replace(/\\s+/g, \"-\");\ninterface GridItem {\n key: string;\n label: string;\n node: React.ReactNode;\n}\n\ntype TipHandle = ReturnType<typeof TooltipPrimitive.createHandle<string>>;\n\n/** Up / down within a grid keep the column; past its edge they land in the same column of the next / previous grid. */\nfunction verticalTarget(grids: HTMLButtonElement[][], g: number, j: number, down: boolean): HTMLButtonElement | \"search\" | undefined {\n const col = j % COLS;\n const cur = grids[g];\n const within = down ? j + COLS : j - COLS;\n if (within >= 0 && within < cur.length) return cur[within];\n if (down && Math.floor(j / COLS) < Math.floor((cur.length - 1) / COLS)) return cur[cur.length - 1]; // a short last row\n const next = grids[down ? g + 1 : g - 1];\n if (!next) return down ? undefined : \"search\";\n if (down) return next[Math.min(col, next.length - 1)];\n const lastRow = Math.floor((next.length - 1) / COLS) * COLS;\n return next[Math.min(lastRow + col, next.length - 1)];\n}\n\nfunction IconGrid({ items, selected, onPick, label, tip }: { items: GridItem[]; selected?: string; onPick: (key: string) => void; label: string; tip: TipHandle }) {\n const ref = React.useRef<HTMLDivElement>(null);\n const stop = items.some((i) => i.key === selected) ? selected : items[0]?.key;\n const move = (e: React.KeyboardEvent) => {\n // one keyboard space across every group in the picker (Recent, the set, search results)\n const scope = ref.current?.closest(\"[data-icon-picker]\") ?? ref.current;\n const grids = Array.from(scope?.querySelectorAll<HTMLElement>(\"[data-icon-grid]\") ?? []).map((g) => Array.from(g.querySelectorAll<HTMLButtonElement>(\"[data-grid-item]\")));\n const btns = grids.flat();\n const i = btns.indexOf(document.activeElement as HTMLButtonElement);\n if (i === -1) return;\n const g = grids.findIndex((list) => list.includes(btns[i]));\n const j = grids[g].indexOf(btns[i]);\n let to: HTMLButtonElement | \"search\" | undefined;\n if (e.key === \"ArrowRight\") to = btns[Math.min(i + 1, btns.length - 1)];\n else if (e.key === \"ArrowLeft\") to = btns[Math.max(i - 1, 0)];\n else if (e.key === \"Home\") to = btns[0];\n else if (e.key === \"End\") to = btns[btns.length - 1];\n else if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") to = verticalTarget(grids, g, j, e.key === \"ArrowDown\") ?? btns[i];\n else return;\n e.preventDefault();\n if (to === \"search\") scope?.querySelector<HTMLInputElement>(\"input[data-icon-search]\")?.focus();\n else to?.focus();\n };\n return (\n <div ref={ref} data-icon-grid className=\"grid gap-0.5\" style={{ gridTemplateColumns: `repeat(${COLS}, minmax(0, 1fr))` }} role=\"listbox\" aria-label={label} onKeyDown={move}>\n {items.map((it) => (\n // one shared tooltip for the whole picker (hundreds of icons): each trigger hands it its label\n <TooltipPrimitive.Trigger\n key={it.key}\n handle={tip}\n payload={it.label}\n delay={500}\n render={\n <button\n type=\"button\"\n role=\"option\"\n data-grid-item\n data-icon={it.key}\n aria-selected={it.key === selected}\n aria-label={it.label}\n tabIndex={it.key === stop ? 0 : -1}\n onClick={() => onPick(it.key)}\n className={cn(\n \"flex aspect-square items-center justify-center rounded-kit-md text-kit-fg-2 transition-colors hover:bg-kit-hover hover:text-kit-fg\",\n it.key === selected && \"bg-kit-selected text-kit-fg ring-1 ring-inset ring-kit-line-strong\",\n )}\n >\n {it.node}\n </button>\n }\n />\n ))}\n </div>\n );\n}\n\nconst NONE = \"__none\";\n\n/** The picker: search, Recent, then the whole set (\"No icon\" first). Search spans the name and its Tabler twin.\n * `field`: the icon field's popover (V2 IconFieldPicker, a 22rem list); otherwise the app-UI grid (V2 IconPickerGrid, max-h-56). */\nexport function IconPicker({ value, onPick, onChooseMedia, field }: { value?: string; onPick: (name: string | null) => void; onChooseMedia?: () => void; field?: boolean }) {\n const [q, setQ] = React.useState(\"\");\n const root = React.useRef<HTMLDivElement>(null);\n const tip = React.useMemo(() => TooltipPrimitive.createHandle<string>(), []);\n const needle = norm(q);\n const item = (name: string): GridItem => ({ key: name, label: iconLabel(name), node: <Glyph name={name} className=\"size-[18px]\" /> });\n const pick = (key: string) => onPick(key === NONE ? null : key);\n const hits = needle ? DOCK_ICON_NAMES.filter((n) => n.includes(needle) || tablerIconOf(n).includes(needle)) : [];\n const recent = recents.filter((n) => DOCK_ICON_NAME_SET.has(n));\n return (\n <div ref={root} data-icon-picker className=\"flex flex-col gap-2\">\n <TooltipPrimitive.Root handle={tip}>{({ payload }) => (payload ? <TooltipLayer>{payload}</TooltipLayer> : null)}</TooltipPrimitive.Root>\n <label className=\"flex h-8 items-center gap-2 rounded-kit-md bg-kit-muted px-2.5 text-kit-fg-3 focus-within:bg-kit-field-bg focus-within:ring-1 focus-within:ring-kit-line-strong\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n data-icon-search\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n root.current?.querySelector<HTMLButtonElement>(\"[data-grid-item]\")?.focus();\n }\n }}\n placeholder=\"Search icons\"\n aria-label=\"Search icons\"\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div className={field ? \"max-h-[22rem] overflow-y-auto pr-0.5\" : \"max-h-56 overflow-y-auto pr-0.5\"}>\n {needle ? (\n <div className=\"flex flex-col gap-2\">\n {hits.length ? (\n <Group>\n <IconGrid label=\"Icons\" selected={value} onPick={pick} tip={tip} items={hits.map(item)} />\n </Group>\n ) : (\n <p className=\"py-6 text-center text-kit-sm text-kit-fg-3\">No icons match “{q.trim()}”</p>\n )}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {recent.length ? (\n <Group title=\"Recent\">\n <IconGrid label=\"Recent icons\" selected={value} onPick={pick} tip={tip} items={recent.map(item)} />\n </Group>\n ) : null}\n <Group title={recent.length ? \"All icons\" : undefined}>\n <IconGrid\n label=\"Icons\"\n selected={value ?? NONE}\n onPick={pick}\n tip={tip}\n items={[{ key: NONE, label: \"No icon\", node: <IconX className=\"size-4\" stroke={1.5} aria-hidden /> }, ...DOCK_ICON_NAMES.map(item)]}\n />\n </Group>\n </div>\n )}\n </div>\n {onChooseMedia ? (\n <div className=\"flex items-center justify-between gap-2 border-t border-kit-line pt-2\">\n <span className=\"whitespace-nowrap text-kit-xs text-kit-fg-3\">Images keep their colours.</span>\n <Button size=\"xs\" variant=\"ghost\" leftIcon={<IconPhoto stroke={1.5} />} onClick={onChooseMedia}>\n Choose from media\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction Group({ title, children }: { title?: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1\">\n {title ? <div className=\"px-0.5 text-kit-2xs font-medium text-kit-fg-3\">{title}</div> : null}\n {children}\n </div>\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\nexport function IconControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { MediaPicker, mediaSrc } = useKitServices();\n const [open, setOpen] = React.useState(false);\n const [mediaOpen, setMediaOpen] = React.useState(false);\n const read = readIcon(value);\n\n const commit = (v: string | null) => {\n onChange(v);\n if (v && DOCK_ICON_NAME_SET.has(v)) pushRecent(v);\n setOpen(false);\n };\n\n const tile =\n read.kind === \"name\" ? (\n <Glyph name={read.name} className=\"size-4\" />\n ) : read.kind === \"upload\" ? (\n <img src={mediaSrc ? mediaSrc(read.url) : read.url} alt=\"\" className=\"size-4 object-contain\" />\n ) : read.kind === \"empty\" ? (\n <span className=\"size-3 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />\n ) : (\n <IconAlertTriangle className=\"size-3.5 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n );\n const text =\n read.kind === \"name\"\n ? iconLabel(read.name)\n : read.kind === \"upload\"\n ? fileName(read.url)\n : read.kind === \"unknown\"\n ? `“${read.name}” isn't in the icon set`\n : read.kind === \"unreadable\"\n ? \"This value isn't an icon this picker can read\"\n : \"Choose an icon\";\n const warn = read.kind === \"unknown\" || read.kind === \"unreadable\";\n\n return (\n <>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n aria-invalid={invalid || undefined}\n className={cn(\n \"flex h-8 w-full items-center gap-2.5 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-1 pr-2.5 text-left text-kit-sm transition-colors hover:border-kit-line-strong data-[popup-open]:border-kit-line-strong data-[popup-open]:bg-kit-field-bg\",\n invalid && \"border-[var(--kit-field-invalid)]\",\n )}\n />\n }\n >\n <span className=\"flex size-6 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg\">{tile}</span>\n <span className={cn(\"min-w-0 flex-1 truncate\", warn ? \"text-kit-warning-fg\" : read.kind === \"empty\" ? \"text-kit-fg-3\" : \"text-kit-fg\")}>{text}</span>\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n <PopoverContent className=\"w-[320px] p-2\" align=\"start\" aria-label={`${field.title}: choose an icon`}>\n <IconPicker\n field\n value={read.kind === \"name\" ? read.name : read.kind === \"empty\" ? undefined : \"\"}\n onPick={commit}\n onChooseMedia={\n MediaPicker\n ? () => {\n setOpen(false);\n setMediaOpen(true);\n }\n : undefined\n }\n />\n </PopoverContent>\n </Popover>\n {MediaPicker && mediaOpen ? (\n <MediaPicker open={mediaOpen} onOpenChange={setMediaOpen} accept={[\"svg\", \"image\"]} onPick={(assets) => assets[0]?.url && commit(assets[0].url)} />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"icon.js","names":[],"sources":["../../src/controls/icon.tsx"],"sourcesContent":["/**\n * ICON — the icon field (DESIGN 8.14), V2 controls/icon.tsx fitted to what prod stores.\n *\n * Values (backend reference-validation `icon`, the classic PropsPanel IconValueInput):\n * \"arrow-right\" a name from the BetterCMS icon set (DOCK_ICON_NAMES, 473 names)\n * \"https://…/logo.svg\" an uploaded icon: an image URL (picked from the media library; a component prop\n * stores the URL string, like the classic panel's codec=\"url\")\n * { url, … } an uploaded icon stored as an image value: shown and kept until replaced\n * null no icon (\"No icon\"; the backend skips an empty value)\n *\n * The grid offers the BetterCMS set, the one prod accepts. Search also matches a name's Tabler twin through the\n * Tabler ↔ dock adapter (adapters/icons.ts), so \"map\" finds earth-americas. A stored name outside the set (a stale\n * Tabler or Lucide name) is shown with its reason and kept until the author picks another.\n *\n * Glyphs: the host draws them (KitServices.IconGlyph: the dashboard's DockIcon, the set the site renders). With no\n * host renderer the kit draws the Tabler twin, loaded on first use; a name with no Tabler twin shows its name.\n */\nimport * as React from \"react\";\nimport type { Icon as TablerIcon } from \"@tabler/icons-react\";\nimport { IconAlertTriangle, IconChevronDown, IconPhoto, IconSearch, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../lib/cn\";\nimport { isObj } from \"../lib/path\";\nimport { iconLabel } from \"../lib/icons\";\nimport { useKitServices } from \"../context\";\nimport { DOCK_ICON_NAMES, DOCK_ICON_NAME_SET } from \"../adapters/prod-types\";\nimport { tablerIconOf } from \"../adapters/icons\";\nimport type { ControlProps } from \"../types\";\nimport { Button } from \"../ui/button\";\nimport { Tooltip as TooltipPrimitive } from \"@base-ui/react/tooltip\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { TooltipLayer } from \"../ui/tooltip-root\";\n\n/* ── Glyphs ───────────────────────────────────────────────────────────── */\ndeclare module \"../context\" {\n interface KitServices {\n /**\n * Draws one icon of the BetterCMS set by name, aria-hidden (the name beside it is the accessible text): the glyphs\n * the site renders. The dashboard passes `DockIcon` (src/components/dock/DockIcon). Absent → the Tabler twin.\n */\n IconGlyph?: React.ComponentType<{ name: string; className?: string }>;\n }\n}\n\nlet tablerSet: Record<string, unknown> | null = null;\nlet tablerLoad: Promise<void> | null = null;\nconst pascal = (kebab: string) => `Icon${kebab.split(\"-\").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(\"\")}`;\n\n/** The full Tabler set, loaded once and only when no host renderer is provided. */\nfunction useTablerSet(need: boolean): Record<string, unknown> | null {\n const [, landed] = React.useReducer((n: number) => n + 1, 0);\n React.useEffect(() => {\n if (!need || tablerSet) return;\n let live = true;\n tablerLoad ??= import(\"@tabler/icons-react\").then((m) => {\n tablerSet = m as unknown as Record<string, unknown>;\n });\n tablerLoad.then(() => live && landed(), () => {});\n return () => {\n live = false;\n };\n }, [need]);\n return tablerSet;\n}\n\nfunction Glyph({ name, className }: { name: string; className?: string }) {\n const Host = useKitServices().IconGlyph;\n const set = useTablerSet(!Host);\n if (Host) return <Host name={name} className={className} />;\n const T = set?.[pascal(tablerIconOf(name))] as TablerIcon | undefined;\n if (T) return <T className={className} stroke={1.5} aria-hidden />;\n // no Tabler twin (or the set is still loading): the name itself, never a stand-in shape\n return (\n <span aria-hidden className=\"max-w-full truncate px-0.5 text-[9px] leading-3 text-kit-fg-3\">\n {name}\n </span>\n );\n}\n\n/* ── Values ───────────────────────────────────────────────────────────── */\ntype Read =\n | { kind: \"empty\" }\n | { kind: \"name\"; name: string }\n | { kind: \"unknown\"; name: string }\n | { kind: \"upload\"; url: string }\n | { kind: \"unreadable\" };\nconst isUrlish = (s: string) => /[/.]/.test(s);\nfunction readIcon(v: unknown): Read {\n if (v == null || v === \"\") return { kind: \"empty\" };\n if (typeof v === \"string\") return DOCK_ICON_NAME_SET.has(v) ? { kind: \"name\", name: v } : isUrlish(v) ? { kind: \"upload\", url: v } : { kind: \"unknown\", name: v };\n if (isObj(v) && typeof v.url === \"string\" && v.url) return { kind: \"upload\", url: v.url };\n return { kind: \"unreadable\" };\n}\nconst fileName = (url: string) => decodeURIComponent(url.split(/[?#]/)[0].split(\"/\").pop() || url);\n\n/** Names picked this session, newest first (shown as \"Recent\"). */\nconst recents: string[] = [];\nconst pushRecent = (name: string) => {\n const i = recents.indexOf(name);\n if (i !== -1) recents.splice(i, 1);\n recents.unshift(name);\n recents.length = Math.min(recents.length, COLS);\n};\n\n/* ── The grid: one tab stop, arrow keys, Home / End ───────────────────── */\nconst COLS = 8;\nconst norm = (q: string) => q.toLowerCase().trim().replace(/\\s+/g, \"-\");\ninterface GridItem {\n key: string;\n label: string;\n node: React.ReactNode;\n}\n\ntype TipHandle = ReturnType<typeof TooltipPrimitive.createHandle<string>>;\n\n/** Up / down within a grid keep the column; past its edge they land in the same column of the next / previous grid. */\nfunction verticalTarget(grids: HTMLButtonElement[][], g: number, j: number, down: boolean): HTMLButtonElement | \"search\" | undefined {\n const col = j % COLS;\n const cur = grids[g];\n const within = down ? j + COLS : j - COLS;\n if (within >= 0 && within < cur.length) return cur[within];\n if (down && Math.floor(j / COLS) < Math.floor((cur.length - 1) / COLS)) return cur[cur.length - 1]; // a short last row\n const next = grids[down ? g + 1 : g - 1];\n if (!next) return down ? undefined : \"search\";\n if (down) return next[Math.min(col, next.length - 1)];\n const lastRow = Math.floor((next.length - 1) / COLS) * COLS;\n return next[Math.min(lastRow + col, next.length - 1)];\n}\n\nfunction IconGrid({ items, selected, onPick, label, tip }: { items: GridItem[]; selected?: string; onPick: (key: string) => void; label: string; tip: TipHandle }) {\n const ref = React.useRef<HTMLDivElement>(null);\n const stop = items.some((i) => i.key === selected) ? selected : items[0]?.key;\n const move = (e: React.KeyboardEvent) => {\n // one keyboard space across every group in the picker (Recent, the set, search results)\n const scope = ref.current?.closest(\"[data-icon-picker]\") ?? ref.current;\n const grids = Array.from(scope?.querySelectorAll<HTMLElement>(\"[data-icon-grid]\") ?? []).map((g) => Array.from(g.querySelectorAll<HTMLButtonElement>(\"[data-grid-item]\")));\n const btns = grids.flat();\n const i = btns.indexOf(document.activeElement as HTMLButtonElement);\n if (i === -1) return;\n const g = grids.findIndex((list) => list.includes(btns[i]));\n const j = grids[g].indexOf(btns[i]);\n let to: HTMLButtonElement | \"search\" | undefined;\n if (e.key === \"ArrowRight\") to = btns[Math.min(i + 1, btns.length - 1)];\n else if (e.key === \"ArrowLeft\") to = btns[Math.max(i - 1, 0)];\n else if (e.key === \"Home\") to = btns[0];\n else if (e.key === \"End\") to = btns[btns.length - 1];\n else if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") to = verticalTarget(grids, g, j, e.key === \"ArrowDown\") ?? btns[i];\n else return;\n e.preventDefault();\n if (to === \"search\") scope?.querySelector<HTMLInputElement>(\"input[data-icon-search]\")?.focus();\n else to?.focus();\n };\n return (\n <div ref={ref} data-icon-grid className=\"grid gap-0.5\" style={{ gridTemplateColumns: `repeat(${COLS}, minmax(0, 1fr))` }} role=\"listbox\" aria-label={label} onKeyDown={move}>\n {items.map((it) => (\n // one shared tooltip for the whole picker (hundreds of icons): each trigger hands it its label\n <TooltipPrimitive.Trigger\n key={it.key}\n handle={tip}\n payload={it.label}\n delay={500}\n render={\n <button\n type=\"button\"\n role=\"option\"\n data-grid-item\n data-icon={it.key}\n aria-selected={it.key === selected}\n aria-label={it.label}\n tabIndex={it.key === stop ? 0 : -1}\n onClick={() => onPick(it.key)}\n className={cn(\n \"flex aspect-square items-center justify-center rounded-kit-md text-kit-fg-2 transition-colors hover:bg-kit-hover hover:text-kit-fg\",\n it.key === selected && \"bg-kit-selected text-kit-fg ring-1 ring-inset ring-kit-line-strong\",\n )}\n >\n {it.node}\n </button>\n }\n />\n ))}\n </div>\n );\n}\n\nconst NONE = \"__none\";\n\n/** The picker: search, Recent, then the whole set (\"No icon\" first). Search spans the name and its Tabler twin.\n * `field`: the icon field's popover (V2 IconFieldPicker, a 22rem list); otherwise the app-UI grid (V2 IconPickerGrid, max-h-56). */\nexport function IconPicker({ value, onPick, onChooseMedia, field }: { value?: string; onPick: (name: string | null) => void; onChooseMedia?: () => void; field?: boolean }) {\n const [q, setQ] = React.useState(\"\");\n const root = React.useRef<HTMLDivElement>(null);\n const tip = React.useMemo(() => TooltipPrimitive.createHandle<string>(), []);\n const needle = norm(q);\n const item = (name: string): GridItem => ({ key: name, label: iconLabel(name), node: <Glyph name={name} className=\"size-[18px]\" /> });\n const pick = (key: string) => onPick(key === NONE ? null : key);\n const hits = needle ? DOCK_ICON_NAMES.filter((n) => n.includes(needle) || tablerIconOf(n).includes(needle)) : [];\n const recent = recents.filter((n) => DOCK_ICON_NAME_SET.has(n));\n return (\n <div ref={root} data-icon-picker className=\"flex flex-col gap-2\">\n <TooltipPrimitive.Root handle={tip}>{({ payload }) => (payload ? <TooltipLayer>{payload}</TooltipLayer> : null)}</TooltipPrimitive.Root>\n <label className=\"flex h-8 items-center gap-2 rounded-kit-md bg-kit-muted px-2.5 text-kit-fg-3 focus-within:bg-kit-field-bg focus-within:ring-1 focus-within:ring-kit-line-strong\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n data-icon-search\n value={q}\n onChange={(e) => setQ(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n root.current?.querySelector<HTMLButtonElement>(\"[data-grid-item]\")?.focus();\n }\n }}\n placeholder=\"Search icons\"\n aria-label=\"Search icons\"\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div className={field ? \"max-h-[22rem] overflow-y-auto pr-0.5\" : \"max-h-56 overflow-y-auto pr-0.5\"}>\n {needle ? (\n <div className=\"flex flex-col gap-2\">\n {hits.length ? (\n <Group>\n <IconGrid label=\"Icons\" selected={value} onPick={pick} tip={tip} items={hits.map(item)} />\n </Group>\n ) : (\n <p className=\"py-6 text-center text-kit-sm text-kit-fg-3\">No icons match “{q.trim()}”</p>\n )}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {recent.length ? (\n <Group title=\"Recent\">\n <IconGrid label=\"Recent icons\" selected={value} onPick={pick} tip={tip} items={recent.map(item)} />\n </Group>\n ) : null}\n <Group title={recent.length ? \"All icons\" : undefined}>\n <IconGrid\n label=\"Icons\"\n selected={value ?? NONE}\n onPick={pick}\n tip={tip}\n items={[{ key: NONE, label: \"No icon\", node: <IconX className=\"size-4\" stroke={1.5} aria-hidden /> }, ...DOCK_ICON_NAMES.map(item)]}\n />\n </Group>\n </div>\n )}\n </div>\n {onChooseMedia ? (\n <div className=\"flex items-center justify-between gap-2 border-t border-kit-line pt-2\">\n <span className=\"whitespace-nowrap text-kit-xs text-kit-fg-3\">Images keep their colours.</span>\n <Button size=\"xs\" variant=\"ghost\" leftIcon={<IconPhoto stroke={1.5} />} onClick={onChooseMedia}>\n Choose from media\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction Group({ title, children }: { title?: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1\">\n {title ? <div className=\"px-0.5 text-kit-2xs font-medium text-kit-fg-3\">{title}</div> : null}\n {children}\n </div>\n );\n}\n\n/* ── The control ──────────────────────────────────────────────────────── */\nexport function IconControl({ field, value, onChange, readOnly, id, invalid }: ControlProps) {\n const { MediaPicker, mediaSrc } = useKitServices();\n const [open, setOpen] = React.useState(false);\n const [mediaOpen, setMediaOpen] = React.useState(false);\n const read = readIcon(value);\n\n const commit = (v: string | null) => {\n onChange(v);\n if (v && DOCK_ICON_NAME_SET.has(v)) pushRecent(v);\n setOpen(false);\n };\n\n const tile =\n read.kind === \"name\" ? (\n <Glyph name={read.name} className=\"size-4\" />\n ) : read.kind === \"upload\" ? (\n <img src={mediaSrc ? mediaSrc(read.url) : read.url} alt=\"\" className=\"size-4 object-contain\" />\n ) : read.kind === \"empty\" ? (\n <span className=\"size-3 rounded-kit-md border border-dashed border-[var(--kit-emphasis-line)]\" />\n ) : (\n <IconAlertTriangle className=\"size-3.5 text-kit-warning-fg\" stroke={1.5} aria-hidden />\n );\n const text =\n read.kind === \"name\"\n ? iconLabel(read.name)\n : read.kind === \"upload\"\n ? fileName(read.url)\n : read.kind === \"unknown\"\n ? `“${read.name}” isn't in the icon set`\n : read.kind === \"unreadable\"\n ? \"This value isn't an icon this picker can read\"\n : \"Choose an icon\";\n const warn = read.kind === \"unknown\" || read.kind === \"unreadable\";\n\n return (\n <>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <button\n id={id}\n type=\"button\"\n disabled={readOnly}\n aria-invalid={invalid || undefined}\n className={cn(\n \"flex h-8 w-full items-center gap-2.5 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-1 pr-2.5 text-left text-kit-sm transition-colors hover:border-kit-line-strong data-[popup-open]:border-kit-line-strong data-[popup-open]:bg-kit-field-bg\",\n invalid && \"border-[var(--kit-field-invalid)]\",\n )}\n />\n }\n >\n <span className=\"flex size-6 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg\">{tile}</span>\n <span className={cn(\"min-w-0 flex-1 truncate\", warn ? \"text-kit-warning-fg\" : read.kind === \"empty\" ? \"text-kit-fg-3\" : \"text-kit-fg\")}>{text}</span>\n <IconChevronDown className=\"size-3.5 text-kit-fg-3\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n <PopoverContent className=\"w-[320px] p-2\" align=\"start\" aria-label={`${field.title}: choose an icon`}>\n <IconPicker\n field\n value={read.kind === \"name\" ? read.name : read.kind === \"empty\" ? undefined : \"\"}\n onPick={commit}\n onChooseMedia={\n MediaPicker\n ? () => {\n setOpen(false);\n setMediaOpen(true);\n }\n : undefined\n }\n />\n </PopoverContent>\n </Popover>\n {MediaPicker && mediaOpen ? (\n <MediaPicker open={mediaOpen} onOpenChange={setMediaOpen} accept={[\"svg\", \"image\"]} onPick={(assets) => assets[0]?.url && commit(assets[0].url)} />\n ) : null}\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -148,7 +148,7 @@ function useReferenceRecords(ids, to) {
|
|
|
148
148
|
canLookup: !!lookupReferences
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
|
-
function PickerBody({ to, filter, selected, multi, max, noun, onPick, onNone, canCreate, noCreateWhy, onCreated }) {
|
|
151
|
+
function PickerBody({ to, filter, selected, multi, max, noun, onPick, onNone, canCreate, noCreateWhy, onCreated, excludeId }) {
|
|
152
152
|
const { searchReferences, createReference, toast } = useKitServices();
|
|
153
153
|
const env = useKitEnv();
|
|
154
154
|
const [q, setQ] = React.useState("");
|
|
@@ -176,11 +176,11 @@ function PickerBody({ to, filter, selected, multi, max, noun, onPick, onNone, ca
|
|
|
176
176
|
filter,
|
|
177
177
|
q: query,
|
|
178
178
|
limit: PAGE,
|
|
179
|
-
excludeId: env.docId,
|
|
179
|
+
excludeId: excludeId ?? env.docId,
|
|
180
180
|
signal: ctrl.signal
|
|
181
181
|
}).then((r) => {
|
|
182
182
|
if (ctrl.signal.aborted) return;
|
|
183
|
-
setRows(r.options.filter((o) => o.id !== env.docId));
|
|
183
|
+
setRows(r.options.filter((o) => o.id !== env.docId && o.id !== excludeId));
|
|
184
184
|
setTruncated(r.truncated);
|
|
185
185
|
setError(null);
|
|
186
186
|
setActive(0);
|
|
@@ -191,6 +191,7 @@ function PickerBody({ to, filter, selected, multi, max, noun, onPick, onNone, ca
|
|
|
191
191
|
toKey,
|
|
192
192
|
filter,
|
|
193
193
|
env.docId,
|
|
194
|
+
excludeId,
|
|
194
195
|
searchReferences
|
|
195
196
|
]);
|
|
196
197
|
const none = onNone && !q;
|
|
@@ -505,6 +506,7 @@ function ReferenceControl({ field, value, onChange, readOnly, id }) {
|
|
|
505
506
|
children: /* @__PURE__ */ jsx(PickerBody, {
|
|
506
507
|
to,
|
|
507
508
|
filter: field.reference?.filter,
|
|
509
|
+
excludeId: field.reference?.excludeId,
|
|
508
510
|
selected: current ? [current] : [],
|
|
509
511
|
noun,
|
|
510
512
|
onPick: pick,
|
|
@@ -665,6 +667,10 @@ function RefChip({ id, o, canLookup, readOnly, sort, onRemove }) {
|
|
|
665
667
|
className: "truncate",
|
|
666
668
|
children: title
|
|
667
669
|
}),
|
|
670
|
+
o?.missingRequired ? /* @__PURE__ */ jsx(DraftChip, {
|
|
671
|
+
status: o.status,
|
|
672
|
+
missingRequired: o.missingRequired
|
|
673
|
+
}) : null,
|
|
668
674
|
readOnly ? null : /* @__PURE__ */ jsx("button", {
|
|
669
675
|
type: "button",
|
|
670
676
|
"aria-label": `Remove ${title}`,
|
|
@@ -747,6 +753,7 @@ function ReferencesControl({ field, value, onChange, readOnly, id }) {
|
|
|
747
753
|
}) : /* @__PURE__ */ jsx(PickerBody, {
|
|
748
754
|
to,
|
|
749
755
|
filter,
|
|
756
|
+
excludeId: item?.reference?.excludeId ?? field.reference?.excludeId,
|
|
750
757
|
selected: ids,
|
|
751
758
|
multi: true,
|
|
752
759
|
max,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.js","names":[],"sources":["../../src/controls/reference.tsx"],"sourcesContent":["/**\n * REFERENCE — single: a select-like trigger (\"Select a CMS item\") → a 300px search popover with \"None\", result rows,\n * drafts labelled, and \"Create new\" inline when the host can create. Never lists the document being edited. No one-click\n * clear (⋯ → Remove). MULTI-REFERENCE — reorderable chips + \"+ Add\", \"n / max\"; at the limit the picker swaps in place.\n * (V2 HEAD 9829bf1 kit/controls/reference.tsx, DESIGN.md 6.8, 8.16, 9.6.)\n *\n * The rows come from the host (reference-services.ts): `searchReferences` is POST /content/reference-options, which\n * already applies the field's `reference.filter` and scope; `truncated` says its filter scan stopped early, and the\n * picker says so. The stored value is the target id (\"en_12\"; a list for many), exactly V2's shape.\n *\n * Kit deviations from V2: no seed rows (every row is a real record from the service); matching is the server's title /\n * slug search, so rows keep the server's order; a stored id the lookup cannot find shows as a \"Missing\" card, or in a\n * multi list one compact \"n missing\" chip with Remove (DESIGN 9.6's production rule), instead of disappearing; chips sort with the engine's `useDragReorder`\n * (@dnd-kit is not on the kit allow-list).\n */\nimport * as React from \"react\";\nimport { IconArrowUpRight, IconCheck, IconChevronDown, IconDatabase, IconDots, IconFileDatabase, IconFileText, IconForms, IconPlus, IconReplace, IconSearch, IconShoppingBag, IconTrash, IconX } from \"@tabler/icons-react\";\nimport type { KitReferenceCreateCapability, KitReferenceKind, KitReferenceOption } from \"./reference-services\";\nimport { Button } from \"../ui/button\";\nimport { Avatar } from \"../ui/display\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { cn } from \"../lib/cn\";\nimport { useDragReorder } from \"../engine/item-list\";\nimport { useKitEnv, useKitServices } from \"../context\";\nimport type { ControlProps } from \"../types\";\n\nconst NON_ENTRY = new Set([\"page\", \"form\", \"collection\", \"shopify\"]);\nconst isEntryTarget = (t: string) => !NON_ENTRY.has(t);\nconst targetsOf = (field: ControlProps[\"field\"]) => field.reference?.to ?? [];\n\n/** The noun the picker uses: the field's own (`reference.noun`), else D48's (\"CMS item\" where V2 says \"entry\"). */\nexport function referenceNoun(to: string[], noun?: string): string {\n if (noun) return noun;\n if (to.length === 1) return to[0] === \"page\" ? \"page\" : to[0] === \"form\" ? \"form\" : to[0] === \"collection\" ? \"collection\" : to[0] === \"shopify\" ? \"product\" : \"CMS item\";\n return to.length && to.every(isEntryTarget) ? \"CMS item\" : \"item\";\n}\nconst plural = (noun: string) => (noun === \"CMS item\" ? \"CMS items\" : `${noun}s`);\nconst withArticle = (noun: string) => `${/^[aeiou]/i.test(noun) ? \"an\" : \"a\"} ${noun}`;\nconst reasonOf = (e: unknown) => (e instanceof Error ? e.message : String(e));\nconst PAGE = 25;\n/** V2 (Radix) slides a picker that would overflow along the edge, keeping it over the panel; Base UI would flip it to\n * end-aligned, which hangs it left over the preview */\nconst SHIFT = { align: \"shift\" } as const;\n\nconst KIND_ICON: Record<KitReferenceKind, React.ComponentType<{ className?: string; stroke?: number }>> = {\n entry: IconFileDatabase,\n page: IconFileText,\n form: IconForms,\n collection: IconDatabase,\n shopify: IconShoppingBag,\n};\n\nexport function RefThumb({ o, size = 28 }: { o: Pick<KitReferenceOption, \"kind\" | \"title\" | \"photo\" | \"avatar\" | \"cover\"> | null; size?: number }) {\n // V2 reference.tsx:152-156: a person is their round avatar (initials without a photo), a record with a cover its image\n if (o?.avatar || o?.photo) return <Avatar name={o.title} src={o.photo ?? undefined} size={size} decorative />;\n if (o?.cover) return <img src={o.cover} alt=\"\" style={{ width: size, height: size }} className=\"shrink-0 rounded-kit-md border border-kit-line object-cover\" />;\n const Icon = o ? KIND_ICON[o.kind] : IconFileDatabase;\n return (\n <span aria-hidden style={{ width: size, height: size }} className=\"flex shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle text-kit-fg-3\">\n <Icon className={size > 24 ? \"size-4\" : \"size-3.5\"} stroke={1.5} />\n </span>\n );\n}\n\nfunction DraftChip({ status, missingRequired }: { status?: string | null; missingRequired?: number }) {\n if (status !== \"draft\") return null;\n const n = missingRequired ?? 0;\n return (\n <span className=\"shrink-0 rounded-kit-md bg-kit-muted px-1 text-kit-2xs text-kit-fg-3\">\n Draft{n > 0 ? ` · ${n} required field${n === 1 ? \"\" : \"s\"} empty` : \"\"}\n </span>\n );\n}\n\n/* ── Lookup: stored ids → their records ────────────────────────────── */\n/**\n * The records behind `ids`, read once per id through `lookupReferences`. An id the service does not hand back is\n * `missing`; a failed read is `error` (in words). A row picked in the picker is `remember`ed, so it shows at once.\n */\nexport function useReferenceRecords(ids: string[], to: string[]) {\n const { lookupReferences } = useKitServices();\n const [known, setKnown] = React.useState<Record<string, KitReferenceOption>>({});\n const [missing, setMissing] = React.useState<ReadonlySet<string>>(new Set());\n const [error, setError] = React.useState<string | null>(null);\n const inflight = React.useRef(new Set<string>());\n const alive = React.useRef(true);\n // set on every mount: StrictMode mounts, unmounts and mounts again, and a flag only cleared would drop every read\n React.useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n const idsKey = ids.join(\"|\");\n const toKey = to.join(\"|\");\n React.useEffect(() => {\n if (!lookupReferences) return;\n const asked = ids.filter((x) => !known[x] && !missing.has(x) && !inflight.current.has(x));\n if (!asked.length) return;\n for (const x of asked) inflight.current.add(x);\n lookupReferences(asked, to)\n .then((rows) => {\n if (!alive.current) return;\n const found = new Set(rows.map((r) => r.id));\n setKnown((k) => ({ ...k, ...Object.fromEntries(rows.map((r) => [r.id, r])) }));\n setMissing((m) => new Set([...m, ...asked.filter((x) => !found.has(x))]));\n setError(null);\n })\n .catch((e: unknown) => alive.current && setError(`The saved ${plural(referenceNoun(to))} could not be read: ${reasonOf(e)}`))\n .finally(() => {\n for (const x of asked) inflight.current.delete(x);\n });\n }, [idsKey, toKey, lookupReferences, known, missing]); // eslint-disable-line react-hooks/exhaustive-deps\n const remember = React.useCallback((o: KitReferenceOption) => {\n setKnown((k) => ({ ...k, [o.id]: o }));\n setMissing((m) => (m.has(o.id) ? new Set([...m].filter((x) => x !== o.id)) : m));\n }, []);\n return { known, missing, loading: !!lookupReferences && ids.some((x) => !known[x] && !missing.has(x)) && !error, error, remember, canLookup: !!lookupReferences };\n}\n\n/* ── The search popover body, shared by single and multi ───────────── */\nfunction PickerBody({\n to,\n filter,\n selected,\n multi,\n max,\n noun,\n onPick,\n onNone,\n canCreate,\n noCreateWhy,\n onCreated,\n}: {\n to: string[];\n filter?: string;\n selected: string[];\n multi?: boolean;\n max?: number;\n noun: string;\n onPick: (o: KitReferenceOption) => void;\n onNone?: () => void;\n canCreate: boolean;\n /** why \"Create new\" isn't offered here, for the empty state (useCreate) */\n noCreateWhy?: string;\n onCreated: (o: KitReferenceOption) => void;\n}) {\n const { searchReferences, createReference, toast } = useKitServices();\n const env = useKitEnv();\n const [q, setQ] = React.useState(\"\");\n const [query, setQuery] = React.useState(\"\");\n const [rows, setRows] = React.useState<KitReferenceOption[]>([]);\n const [truncated, setTruncated] = React.useState(false);\n const [loading, setLoading] = React.useState(true);\n const [error, setError] = React.useState<string | null>(null);\n const [active, setActive] = React.useState(0);\n const [creating, setCreating] = React.useState(false);\n const [createBusy, setCreateBusy] = React.useState(false);\n const [createError, setCreateError] = React.useState<string | null>(null);\n const listId = React.useId();\n\n React.useEffect(() => {\n const t = window.setTimeout(() => setQuery(q.trim()), q.trim() ? 180 : 0);\n return () => window.clearTimeout(t);\n }, [q]);\n const toKey = to.join(\"|\");\n React.useEffect(() => {\n if (!searchReferences) return;\n const ctrl = new AbortController();\n setLoading(true);\n searchReferences({ to, filter, q: query, limit: PAGE, excludeId: env.docId, signal: ctrl.signal })\n .then((r) => {\n if (ctrl.signal.aborted) return;\n setRows(r.options.filter((o) => o.id !== env.docId));\n setTruncated(r.truncated);\n setError(null);\n setActive(0);\n })\n .catch((e: unknown) => !ctrl.signal.aborted && setError(reasonOf(e)))\n .finally(() => !ctrl.signal.aborted && setLoading(false));\n return () => ctrl.abort();\n }, [query, toKey, filter, env.docId, searchReferences]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const none = onNone && !q;\n const total = rows.length + (none ? 1 : 0);\n const at = (i: number) => (none ? (i === 0 ? null : rows[i - 1]) : rows[i]);\n const full = multi && max != null && selected.length >= max;\n const choose = (i: number) => {\n const o = at(i);\n if (o) onPick(o);\n else if (none) onNone!();\n };\n const optionId = (i: number) => `${listId}-${i}`;\n // one create at a time: a second Enter or click while the first is out is the same request, not another draft\n const createOut = React.useRef(false);\n const create = async (title: string) => {\n if (!createReference || createOut.current) return;\n createOut.current = true;\n setCreateBusy(true);\n setCreateError(null);\n try {\n const o = await createReference({ to: to[0], title });\n setCreating(false);\n onCreated(o);\n const open =\n o.kind === \"entry\" && o.modelSlug && env.onOpenReference\n ? { label: \"Open\", onClick: () => env.onOpenReference!({ collectionId: o.modelSlug!, entryId: o.id, title: o.title }) }\n : undefined;\n toast?.success(o.created === false ? `Using existing ‘${o.title}’` : `Created ‘${o.title}’ as a draft`, open ? { action: open } : undefined);\n } catch (e) {\n setCreateError(`Not created: ${reasonOf(e)}`);\n } finally {\n createOut.current = false;\n setCreateBusy(false);\n }\n };\n // V2's search copy: \"pages\" for a page picker, \"entries\" for every other one\n const searchLabel = `Search ${noun === \"page\" ? \"pages\" : \"entries\"}`;\n return (\n <div className=\"flex flex-col\">\n <label className=\"flex h-10 items-center gap-2 border-b border-kit-line px-3 text-kit-fg-3\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n value={q}\n onChange={(e) => {\n setQ(e.target.value);\n setActive(0);\n }}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((a) => Math.min(total - 1, a + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(0, a - 1));\n } else if (e.key === \"Home\") {\n e.preventDefault();\n setActive(0);\n } else if (e.key === \"End\") {\n e.preventDefault();\n setActive(Math.max(0, total - 1));\n } else if (e.key === \"Enter\" && total) {\n e.preventDefault();\n choose(Math.min(active, total - 1));\n }\n }}\n placeholder={`${searchLabel}…`}\n role=\"combobox\"\n aria-expanded\n aria-autocomplete=\"list\"\n aria-controls={listId}\n aria-activedescendant={total ? optionId(Math.min(active, total - 1)) : undefined}\n aria-label={searchLabel}\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div id={listId} className=\"max-h-72 overflow-y-auto p-1\" role=\"listbox\" aria-label={`${noun} results`} aria-multiselectable={multi || undefined} aria-busy={loading || undefined}>\n {none ? (\n <button\n type=\"button\"\n id={optionId(0)}\n role=\"option\"\n aria-selected={false}\n tabIndex={-1}\n onMouseEnter={() => setActive(0)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onNone}\n className={cn(\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm text-kit-fg-3 hover:bg-kit-hover\", active === 0 && \"bg-kit-hover\")}\n >\n None\n </button>\n ) : null}\n {rows.map((o, j) => {\n const i = j + (none ? 1 : 0);\n const on = selected.includes(o.id);\n return (\n <button\n type=\"button\"\n key={`${o.kind}:${o.id}`}\n id={optionId(i)}\n role=\"option\"\n aria-selected={on}\n tabIndex={-1}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(o)}\n className={cn(\"flex w-full items-center gap-2.5 rounded-kit-md p-1.5 text-left\", i === active && \"bg-kit-hover\")}\n >\n {multi ? (\n <span aria-hidden className={cn(\"flex size-4 shrink-0 items-center justify-center rounded-kit-md border\", on ? \"border-kit-accent bg-kit-accent text-kit-accent-on\" : \"border-kit-line-strong\", !on && full && \"opacity-40\")}>\n {on ? <IconCheck className=\"size-3\" stroke={3} /> : null}\n </span>\n ) : null}\n <RefThumb o={o} size={28} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-kit-sm text-kit-fg\">{o.title}</span>\n {o.subtitle ? <span className=\"block truncate text-kit-xs text-kit-fg-3\">{o.subtitle}</span> : null}\n </span>\n <DraftChip status={o.status} missingRequired={o.missingRequired} />\n {!multi && on ? <IconCheck className=\"size-4 shrink-0 text-kit-fg\" stroke={2} aria-hidden /> : null}\n </button>\n );\n })}\n {!loading && !error && rows.length === 0 ? (\n <div className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">\n No matches\n {noCreateWhy ? (\n <p role=\"note\" className=\"mt-1 text-kit-xs\">\n {noCreateWhy}\n </p>\n ) : null}\n </div>\n ) : null}\n {loading && rows.length === 0 ? (\n <div role=\"status\" className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">\n Searching…\n </div>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"px-3 py-3 text-kit-xs text-kit-danger-fg\">\n {plural(noun).replace(/^./, (c) => c.toUpperCase())} could not be listed: {error}\n </p>\n ) : null}\n </div>\n {truncated && !error ? (\n <p role=\"note\" className=\"border-t border-kit-line px-3 py-2 text-kit-xs text-kit-warning-fg\">\n Some {plural(noun)} were not checked against this field's filter, so the list may be incomplete. Search by name to narrow it.\n </p>\n ) : null}\n {multi ? (\n <div className={cn(\"border-t border-kit-line px-3 py-2 text-kit-xs\", full ? \"text-kit-warning-fg\" : \"text-kit-fg-3\")}>\n {selected.length}\n {max != null ? ` of ${max}` : \"\"} selected{full ? ` · Limit is ${max}. Picking another swaps out the last one.` : \"\"}\n </div>\n ) : null}\n {canCreate ? (\n <div className=\"border-t border-kit-line p-1.5\">\n {creating ? (\n <>\n <form\n className=\"flex items-center gap-1.5\"\n onSubmit={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const t = String(new FormData(e.currentTarget).get(\"t\") ?? \"\").trim();\n if (t) void create(t);\n }}\n >\n <input\n name=\"t\"\n autoFocus\n defaultValue={q}\n aria-label={`New ${noun} name`}\n placeholder={`New ${noun} name`}\n className=\"h-8 min-w-0 flex-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-2 text-kit-sm text-kit-fg outline-none focus:bg-kit-field-bg focus:ring-1 focus:ring-kit-line-strong\"\n />\n <Button size=\"sm\" type=\"submit\" variant=\"primary\" loading={createBusy} disabled={createBusy}>\n Create\n </Button>\n </form>\n {createError ? (\n <p role=\"alert\" className=\"mt-1.5 px-1 text-kit-xs text-kit-danger-fg\">\n {createError}\n </p>\n ) : null}\n </>\n ) : (\n <button\n type=\"button\"\n onClick={() => setCreating(true)}\n className=\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\"\n >\n <IconPlus className=\"size-4\" stroke={1.5} aria-hidden />\n Create new {noun}\n {q ? <span className=\"truncate text-kit-fg-3\">“{q}”</span> : null}\n </button>\n )}\n </div>\n ) : null}\n </div>\n );\n}\n\nconst noCapability = (_to: string | null): KitReferenceCreateCapability | undefined => undefined;\n\n/**\n * \"Create new\" only where the host can create a draft in the ONE entry model the field targets, and, when the host\n * answers per target (useReferenceCreate), only where that model takes one. Otherwise `why`, for the empty state:\n * the target's own refusal, else the host's createDisabledReason. A capability not known yet shows neither.\n */\nfunction useCreate(to: string[]): { can: boolean; why?: string } {\n const { createReference, createDisabledReason, useReferenceCreate } = useKitServices();\n const one = to.length === 1 && isEntryTarget(to[0]) ? to[0] : null;\n const useCapability = useReferenceCreate ?? noCapability;\n const cap = useCapability(one);\n if (!one) return { can: false };\n if (useReferenceCreate) {\n if (!cap) return { can: false };\n if (!cap.ok) return { can: false, why: cap.reason };\n }\n return createReference ? { can: true } : { can: false, why: createDisabledReason };\n}\n\n/** Why the field cannot change its value here (no search service), in words. */\nfunction NoSearch({ title }: { title: string }) {\n return (\n <p role=\"note\" className=\"text-kit-xs text-kit-fg-3\">\n No reference search is connected to this editor, so {title} can't be changed here.\n </p>\n );\n}\n\n/* ── Single reference ──────────────────────────────────────────────── */\nexport function ReferenceControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const env = useKitEnv();\n const { searchReferences } = useKitServices();\n const to = targetsOf(field);\n const noun = referenceNoun(to, field.reference?.noun);\n const current = typeof value === \"string\" && value ? value : null;\n const ids = React.useMemo(() => (current ? [current] : []), [current]);\n const rec = useReferenceRecords(ids, to);\n const createState = useCreate(to);\n const canCreate = createState.can && !readOnly;\n const [open, setOpen] = React.useState(false);\n const pick = (o: KitReferenceOption) => {\n rec.remember(o);\n onChange(o.id);\n setOpen(false);\n };\n /* the trigger opens like V2's even with no search service; the popover then says why nothing can be picked */\n const editable = !readOnly;\n const body = !editable ? null : !searchReferences ? (\n <PopoverContent className=\"w-[300px] p-3\" align=\"start\" collisionAvoidance={SHIFT}>\n <NoSearch title={field.title} />\n </PopoverContent>\n ) : (\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\" collisionAvoidance={SHIFT}>\n <PickerBody\n to={to}\n filter={field.reference?.filter}\n selected={current ? [current] : []}\n noun={noun}\n onPick={pick}\n onNone={\n current\n ? () => {\n onChange(null);\n setOpen(false);\n }\n : undefined\n }\n canCreate={canCreate}\n noCreateWhy={createState.why}\n onCreated={pick}\n />\n </PopoverContent>\n );\n\n const missing = !!current && rec.missing.has(current);\n if (current && !missing) {\n const o = rec.known[current];\n const title = o?.title ?? (rec.loading ? \"Loading…\" : current);\n const subtitle = o ? o.subtitle : rec.error ?? (!rec.canLookup ? `Saved ${noun} id` : null);\n const openable = !!o && o.kind === \"entry\" && !!o.modelSlug && !!env.onOpenReference;\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <div data-slot=\"kit-reference-card\" className=\"group/ref flex items-center gap-2.5 rounded-kit-lg border border-kit-line bg-kit-control-bg p-1.5 pr-1 transition-colors hover:border-kit-line-strong\">\n <PopoverTrigger\n id={id}\n disabled={!editable}\n aria-label={`${field.title}: ${title}.${editable ? \" Change\" : \"\"}`}\n className=\"flex min-w-0 flex-1 items-center gap-2.5 text-left\"\n >\n <RefThumb o={o ?? null} size={32} />\n <span className=\"min-w-0 flex-1\">\n <span className={cn(\"block truncate text-kit-sm font-medium text-kit-fg\", !o && !rec.canLookup && \"font-kit-mono text-kit-xs\")}>{title}</span>\n {subtitle ? <span className={cn(\"block truncate text-kit-xs\", rec.error && !o ? \"text-kit-danger-fg\" : \"text-kit-fg-3\")}>{subtitle}</span> : null}\n </span>\n <DraftChip status={o?.status} missingRequired={o?.missingRequired} />\n </PopoverTrigger>\n {readOnly ? null : (\n <Menu>\n <MenuTrigger\n aria-label={`${o?.title ?? field.title} actions`}\n className=\"flex size-7 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-48\">\n {openable ? (\n <MenuItem icon={<IconArrowUpRight stroke={1.5} />} onClick={() => env.onOpenReference!({ collectionId: o!.modelSlug!, entryId: o!.id, title: o!.title })}>\n Open {o!.title.length > 18 ? `${o!.title.slice(0, 16)}…` : o!.title}\n </MenuItem>\n ) : null}\n {editable ? (\n <MenuItem icon={<IconReplace stroke={1.5} />} onClick={() => window.setTimeout(() => setOpen(true), 0)}>\n Replace\n </MenuItem>\n ) : null}\n {openable || editable ? <MenuSeparator /> : null}\n <MenuItem danger icon={<IconTrash stroke={1.5} />} onClick={() => onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n )}\n </div>\n {body}\n </Popover>\n );\n }\n /* empty, or a saved id the lookup cannot find: V2's select trigger (V2 draws an unresolved id as no selection). Ours\n says \"Missing\" on it instead of hiding the saved id (DESIGN 9.6); the picker's None clears it, a row replaces it. */\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n id={id}\n disabled={!editable}\n data-slot={missing ? \"kit-reference-card\" : undefined}\n data-missing={missing || undefined}\n aria-label={missing ? `${field.title}: Missing ${noun}.${editable ? \" Change\" : \"\"}` : `${field.title}: select ${withArticle(noun)}`}\n className={cn(\n \"flex h-8 w-full items-center gap-2 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-2.5 text-left text-kit-sm text-kit-fg-3 transition-colors hover:border-kit-line-strong data-[popup-open]:border-kit-line-strong data-[popup-open]:bg-kit-field-bg\",\n missing && \"border-kit-warning-line text-kit-warning-fg hover:border-kit-warning-line data-[popup-open]:border-kit-warning-line\",\n )}\n >\n <IconFileDatabase className=\"size-4\" stroke={1.5} aria-hidden />\n {missing ? (\n <span className=\"flex-1 truncate\">\n Missing {noun}\n <span className=\"sr-only\">. Deleted, or not visible to you. The saved id stays until you replace or remove it.</span>\n </span>\n ) : (\n <span className=\"flex-1 truncate\">Select {withArticle(noun)}</span>\n )}\n <IconChevronDown className=\"size-3.5\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n {body}\n </Popover>\n );\n}\n\n/* ── Multi-reference: an array of ids ─────────────────────────────── */\nfunction RefChip({\n id,\n o,\n canLookup,\n readOnly,\n sort,\n onRemove,\n}: {\n id: string;\n o?: KitReferenceOption;\n /** false: no lookup service, so the saved id is all there is to show (never a \"Loading…\" that never ends) */\n canLookup: boolean;\n readOnly?: boolean;\n sort: ReturnType<typeof useDragReorder>;\n onRemove: () => void;\n}) {\n const handle = sort.handle(id);\n const register = sort.register(id);\n const title = o?.title ?? (canLookup ? \"Loading…\" : id);\n /* V2: the chip itself is the sortable item (thumb, title and remove button inside it) */\n return (\n <span\n {...(readOnly ? {} : handle)}\n ref={(el: HTMLElement | null) => {\n register(el);\n if (!readOnly) handle.ref(el);\n }}\n style={sort.style(id)}\n tabIndex={0}\n role=\"group\"\n aria-roledescription=\"sortable item\"\n aria-label={readOnly ? title : `${title}, drag to reorder`}\n onKeyDown={(e) => {\n // keys on the remove button are the button's own\n if (readOnly || e.target !== e.currentTarget) return;\n if (e.key === \"Delete\" || e.key === \"Backspace\") {\n e.preventDefault();\n onRemove();\n return;\n }\n handle.onKeyDown(e);\n }}\n className={cn(\n \"inline-flex h-6 max-w-full cursor-grab touch-none items-center gap-1.5 rounded-kit-md border border-kit-line bg-kit-control-bg pl-0.5 pr-1 text-kit-sm text-kit-fg shadow-kit-xs active:cursor-grabbing\",\n sort.active === id && \"z-10 shadow-kit-md\",\n )}\n >\n <RefThumb o={o ?? null} size={20} />\n <span className=\"truncate\">{title}</span>\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${title}`} onPointerDown={(e) => e.stopPropagation()} onClick={onRemove} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} aria-hidden />\n </button>\n )}\n </span>\n );\n}\n\n/** Multi-reference: an array of reference ids. `field` is the ARRAY field; the engine hands it the item's `reference`. */\nexport function ReferencesControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const { searchReferences } = useKitServices();\n const item = Array.isArray(field.of) ? field.of[0] : undefined;\n const to = item?.reference?.to ?? field.reference?.to ?? [];\n const filter = item?.reference?.filter ?? field.reference?.filter;\n const noun = referenceNoun(to, item?.reference?.noun ?? field.reference?.noun);\n const ids = React.useMemo(() => (Array.isArray(value) ? value : []).filter((x): x is string => typeof x === \"string\" && x !== \"\"), [value]);\n const rec = useReferenceRecords(ids, to);\n const createState = useCreate(to);\n const canCreate = createState.can && !readOnly;\n const max = field.validation?.max;\n /* ids the lookup cannot find are drawn as ONE compact \"n missing\" chip after Add (V2 hides them; one row keeps V2's height),\n so the chips that sort are the rest; a reorder puts them back around the missing ids, which keep their places */\n const missingIds = ids.filter((x) => rec.missing.has(x));\n const shown = missingIds.length ? ids.filter((x) => !rec.missing.has(x)) : ids;\n const sort = useDragReorder(\n shown,\n (from, to2) => {\n const next = [...shown];\n const [moved] = next.splice(from, 1);\n next.splice(to2, 0, moved);\n let i = 0;\n onChange(ids.map((x) => (rec.missing.has(x) ? x : next[i++])));\n },\n { axis: \"grid\", disabled: readOnly },\n );\n const missingNoun = missingIds.length === 1 ? noun : plural(noun);\n const toggle = (o: KitReferenceOption) => {\n rec.remember(o);\n if (ids.includes(o.id)) return onChange(ids.filter((x) => x !== o.id));\n if (max != null && ids.length >= max) return onChange([...ids.slice(0, -1), o.id]); // swap in place at the limit\n onChange([...ids, o.id]);\n };\n return (\n <div className=\"flex flex-col gap-1\">\n {/* the field label points at the Add trigger; read-only there is none, so the box carries the id. The chips sit\n straight in the wrapping box, as V2's do (a wrapper would take them out of the box's flow). V2's box has no\n role or name while editing; read-only (no Add to label) it is named as a group. */}\n <div\n id={readOnly ? id : undefined}\n role={readOnly ? \"group\" : undefined}\n aria-label={readOnly ? field.title : undefined}\n className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors hover:border-kit-line-strong\"\n >\n {shown.map((x) => (\n <RefChip key={x} id={x} o={rec.known[x]} canLookup={rec.canLookup} readOnly={readOnly} sort={sort} onRemove={() => onChange(ids.filter((y) => y !== x))} />\n ))}\n {sort.a11y}\n {!readOnly ? (\n <Popover>\n <PopoverTrigger id={id} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconPlus className=\"size-3.5\" stroke={1.5} aria-hidden />\n Add\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\" collisionAvoidance={SHIFT}>\n {/* no search service: the picker says why instead of listing anything */}\n {!searchReferences ? (\n <div className=\"p-3\">\n <NoSearch title={field.title} />\n </div>\n ) : (\n <PickerBody\n to={to}\n filter={filter}\n selected={ids}\n multi\n max={max}\n noun={noun}\n onPick={toggle}\n canCreate={canCreate}\n noCreateWhy={createState.why}\n onCreated={(o) => {\n rec.remember(o);\n onChange(max != null && ids.length >= max ? [...ids.slice(0, -1), o.id] : [...ids, o.id]);\n }}\n />\n )}\n </PopoverContent>\n </Popover>\n ) : ids.length === 0 ? (\n <span className=\"px-1.5 text-kit-sm text-kit-fg-3\">None</span>\n ) : null}\n {/* after Add, so Add keeps V2's place (V2 draws nothing for these ids) */}\n {missingIds.length ? (\n <span\n data-missing\n data-slot=\"kit-reference-missing\"\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-kit-md border border-kit-warning-line bg-kit-control-bg pl-1.5 pr-1 text-kit-sm text-kit-warning-fg shadow-kit-xs\"\n >\n <span className=\"truncate tabular-nums\">\n {missingIds.length} missing\n <span className=\"sr-only\">\n {\" \"}\n {missingNoun}. Deleted, or not visible to you. The saved {missingIds.length === 1 ? \"id stays\" : \"ids stay\"} until you remove {missingIds.length === 1 ? \"it\" : \"them\"}.\n </span>\n </span>\n {readOnly ? null : (\n <button\n type=\"button\"\n aria-label={`Remove ${missingIds.length} missing ${missingNoun}`}\n onClick={() => onChange(ids.filter((y) => !rec.missing.has(y)))}\n className=\"flex rounded-kit-sm p-0.5 hover:bg-kit-hover hover:text-kit-fg\"\n >\n <IconX className=\"size-3\" stroke={1.5} aria-hidden />\n </button>\n )}\n </span>\n ) : null}\n </div>\n {rec.error ? (\n <p role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {rec.error}\n </p>\n ) : null}\n {max != null ? (\n <span className=\"tabular-nums self-end text-kit-xs text-kit-fg-3\">\n {ids.length} / {max}\n </span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"reference.js","names":[],"sources":["../../src/controls/reference.tsx"],"sourcesContent":["/**\n * REFERENCE — single: a select-like trigger (\"Select a CMS item\") → a 300px search popover with \"None\", result rows,\n * drafts labelled, and \"Create new\" inline when the host can create. Never lists the document being edited. No one-click\n * clear (⋯ → Remove). MULTI-REFERENCE — reorderable chips + \"+ Add\", \"n / max\"; at the limit the picker swaps in place.\n * (V2 HEAD 9829bf1 kit/controls/reference.tsx, DESIGN.md 6.8, 8.16, 9.6.)\n *\n * The rows come from the host (reference-services.ts): `searchReferences` is POST /content/reference-options, which\n * already applies the field's `reference.filter` and scope; `truncated` says its filter scan stopped early, and the\n * picker says so. The stored value is the target id (\"en_12\"; a list for many), exactly V2's shape.\n *\n * Kit deviations from V2: no seed rows (every row is a real record from the service); matching is the server's title /\n * slug search, so rows keep the server's order; a stored id the lookup cannot find shows as a \"Missing\" card, or in a\n * multi list one compact \"n missing\" chip with Remove (DESIGN 9.6's production rule), instead of disappearing; chips sort with the engine's `useDragReorder`\n * (@dnd-kit is not on the kit allow-list).\n */\nimport * as React from \"react\";\nimport { IconArrowUpRight, IconCheck, IconChevronDown, IconDatabase, IconDots, IconFileDatabase, IconFileText, IconForms, IconPlus, IconReplace, IconSearch, IconShoppingBag, IconTrash, IconX } from \"@tabler/icons-react\";\nimport type { KitReferenceCreateCapability, KitReferenceKind, KitReferenceOption } from \"./reference-services\";\nimport { Button } from \"../ui/button\";\nimport { Avatar } from \"../ui/display\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverContent, PopoverTrigger } from \"../ui/overlay\";\nimport { cn } from \"../lib/cn\";\nimport { useDragReorder } from \"../engine/item-list\";\nimport { useKitEnv, useKitServices } from \"../context\";\nimport type { ControlProps } from \"../types\";\n\nconst NON_ENTRY = new Set([\"page\", \"form\", \"collection\", \"shopify\"]);\nconst isEntryTarget = (t: string) => !NON_ENTRY.has(t);\nconst targetsOf = (field: ControlProps[\"field\"]) => field.reference?.to ?? [];\n\n/** The noun the picker uses: the field's own (`reference.noun`), else D48's (\"CMS item\" where V2 says \"entry\"). */\nexport function referenceNoun(to: string[], noun?: string): string {\n if (noun) return noun;\n if (to.length === 1) return to[0] === \"page\" ? \"page\" : to[0] === \"form\" ? \"form\" : to[0] === \"collection\" ? \"collection\" : to[0] === \"shopify\" ? \"product\" : \"CMS item\";\n return to.length && to.every(isEntryTarget) ? \"CMS item\" : \"item\";\n}\nconst plural = (noun: string) => (noun === \"CMS item\" ? \"CMS items\" : `${noun}s`);\nconst withArticle = (noun: string) => `${/^[aeiou]/i.test(noun) ? \"an\" : \"a\"} ${noun}`;\nconst reasonOf = (e: unknown) => (e instanceof Error ? e.message : String(e));\nconst PAGE = 25;\n/** V2 (Radix) slides a picker that would overflow along the edge, keeping it over the panel; Base UI would flip it to\n * end-aligned, which hangs it left over the preview */\nconst SHIFT = { align: \"shift\" } as const;\n\nconst KIND_ICON: Record<KitReferenceKind, React.ComponentType<{ className?: string; stroke?: number }>> = {\n entry: IconFileDatabase,\n page: IconFileText,\n form: IconForms,\n collection: IconDatabase,\n shopify: IconShoppingBag,\n};\n\nexport function RefThumb({ o, size = 28 }: { o: Pick<KitReferenceOption, \"kind\" | \"title\" | \"photo\" | \"avatar\" | \"cover\"> | null; size?: number }) {\n // V2 reference.tsx:152-156: a person is their round avatar (initials without a photo), a record with a cover its image\n if (o?.avatar || o?.photo) return <Avatar name={o.title} src={o.photo ?? undefined} size={size} decorative />;\n if (o?.cover) return <img src={o.cover} alt=\"\" style={{ width: size, height: size }} className=\"shrink-0 rounded-kit-md border border-kit-line object-cover\" />;\n const Icon = o ? KIND_ICON[o.kind] : IconFileDatabase;\n return (\n <span aria-hidden style={{ width: size, height: size }} className=\"flex shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-subtle text-kit-fg-3\">\n <Icon className={size > 24 ? \"size-4\" : \"size-3.5\"} stroke={1.5} />\n </span>\n );\n}\n\nfunction DraftChip({ status, missingRequired }: { status?: string | null; missingRequired?: number }) {\n if (status !== \"draft\") return null;\n const n = missingRequired ?? 0;\n return (\n <span className=\"shrink-0 rounded-kit-md bg-kit-muted px-1 text-kit-2xs text-kit-fg-3\">\n Draft{n > 0 ? ` · ${n} required field${n === 1 ? \"\" : \"s\"} empty` : \"\"}\n </span>\n );\n}\n\n/* ── Lookup: stored ids → their records ────────────────────────────── */\n/**\n * The records behind `ids`, read once per id through `lookupReferences`. An id the service does not hand back is\n * `missing`; a failed read is `error` (in words). A row picked in the picker is `remember`ed, so it shows at once.\n */\nexport function useReferenceRecords(ids: string[], to: string[]) {\n const { lookupReferences } = useKitServices();\n const [known, setKnown] = React.useState<Record<string, KitReferenceOption>>({});\n const [missing, setMissing] = React.useState<ReadonlySet<string>>(new Set());\n const [error, setError] = React.useState<string | null>(null);\n const inflight = React.useRef(new Set<string>());\n const alive = React.useRef(true);\n // set on every mount: StrictMode mounts, unmounts and mounts again, and a flag only cleared would drop every read\n React.useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n const idsKey = ids.join(\"|\");\n const toKey = to.join(\"|\");\n React.useEffect(() => {\n if (!lookupReferences) return;\n const asked = ids.filter((x) => !known[x] && !missing.has(x) && !inflight.current.has(x));\n if (!asked.length) return;\n for (const x of asked) inflight.current.add(x);\n lookupReferences(asked, to)\n .then((rows) => {\n if (!alive.current) return;\n const found = new Set(rows.map((r) => r.id));\n setKnown((k) => ({ ...k, ...Object.fromEntries(rows.map((r) => [r.id, r])) }));\n setMissing((m) => new Set([...m, ...asked.filter((x) => !found.has(x))]));\n setError(null);\n })\n .catch((e: unknown) => alive.current && setError(`The saved ${plural(referenceNoun(to))} could not be read: ${reasonOf(e)}`))\n .finally(() => {\n for (const x of asked) inflight.current.delete(x);\n });\n }, [idsKey, toKey, lookupReferences, known, missing]); // eslint-disable-line react-hooks/exhaustive-deps\n const remember = React.useCallback((o: KitReferenceOption) => {\n setKnown((k) => ({ ...k, [o.id]: o }));\n setMissing((m) => (m.has(o.id) ? new Set([...m].filter((x) => x !== o.id)) : m));\n }, []);\n return { known, missing, loading: !!lookupReferences && ids.some((x) => !known[x] && !missing.has(x)) && !error, error, remember, canLookup: !!lookupReferences };\n}\n\n/* ── The search popover body, shared by single and multi ───────────── */\nfunction PickerBody({\n to,\n filter,\n selected,\n multi,\n max,\n noun,\n onPick,\n onNone,\n canCreate,\n noCreateWhy,\n onCreated,\n excludeId,\n}: {\n to: string[];\n filter?: string;\n /** a record never listed besides the document being edited (the field's `reference.excludeId`) */\n excludeId?: string;\n selected: string[];\n multi?: boolean;\n max?: number;\n noun: string;\n onPick: (o: KitReferenceOption) => void;\n onNone?: () => void;\n canCreate: boolean;\n /** why \"Create new\" isn't offered here, for the empty state (useCreate) */\n noCreateWhy?: string;\n onCreated: (o: KitReferenceOption) => void;\n}) {\n const { searchReferences, createReference, toast } = useKitServices();\n const env = useKitEnv();\n const [q, setQ] = React.useState(\"\");\n const [query, setQuery] = React.useState(\"\");\n const [rows, setRows] = React.useState<KitReferenceOption[]>([]);\n const [truncated, setTruncated] = React.useState(false);\n const [loading, setLoading] = React.useState(true);\n const [error, setError] = React.useState<string | null>(null);\n const [active, setActive] = React.useState(0);\n const [creating, setCreating] = React.useState(false);\n const [createBusy, setCreateBusy] = React.useState(false);\n const [createError, setCreateError] = React.useState<string | null>(null);\n const listId = React.useId();\n\n React.useEffect(() => {\n const t = window.setTimeout(() => setQuery(q.trim()), q.trim() ? 180 : 0);\n return () => window.clearTimeout(t);\n }, [q]);\n const toKey = to.join(\"|\");\n React.useEffect(() => {\n if (!searchReferences) return;\n const ctrl = new AbortController();\n setLoading(true);\n searchReferences({ to, filter, q: query, limit: PAGE, excludeId: excludeId ?? env.docId, signal: ctrl.signal })\n .then((r) => {\n if (ctrl.signal.aborted) return;\n setRows(r.options.filter((o) => o.id !== env.docId && o.id !== excludeId));\n setTruncated(r.truncated);\n setError(null);\n setActive(0);\n })\n .catch((e: unknown) => !ctrl.signal.aborted && setError(reasonOf(e)))\n .finally(() => !ctrl.signal.aborted && setLoading(false));\n return () => ctrl.abort();\n }, [query, toKey, filter, env.docId, excludeId, searchReferences]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const none = onNone && !q;\n const total = rows.length + (none ? 1 : 0);\n const at = (i: number) => (none ? (i === 0 ? null : rows[i - 1]) : rows[i]);\n const full = multi && max != null && selected.length >= max;\n const choose = (i: number) => {\n const o = at(i);\n if (o) onPick(o);\n else if (none) onNone!();\n };\n const optionId = (i: number) => `${listId}-${i}`;\n // one create at a time: a second Enter or click while the first is out is the same request, not another draft\n const createOut = React.useRef(false);\n const create = async (title: string) => {\n if (!createReference || createOut.current) return;\n createOut.current = true;\n setCreateBusy(true);\n setCreateError(null);\n try {\n const o = await createReference({ to: to[0], title });\n setCreating(false);\n onCreated(o);\n const open =\n o.kind === \"entry\" && o.modelSlug && env.onOpenReference\n ? { label: \"Open\", onClick: () => env.onOpenReference!({ collectionId: o.modelSlug!, entryId: o.id, title: o.title }) }\n : undefined;\n toast?.success(o.created === false ? `Using existing ‘${o.title}’` : `Created ‘${o.title}’ as a draft`, open ? { action: open } : undefined);\n } catch (e) {\n setCreateError(`Not created: ${reasonOf(e)}`);\n } finally {\n createOut.current = false;\n setCreateBusy(false);\n }\n };\n // V2's search copy: \"pages\" for a page picker, \"entries\" for every other one\n const searchLabel = `Search ${noun === \"page\" ? \"pages\" : \"entries\"}`;\n return (\n <div className=\"flex flex-col\">\n <label className=\"flex h-10 items-center gap-2 border-b border-kit-line px-3 text-kit-fg-3\">\n <IconSearch className=\"size-4 shrink-0\" stroke={1.5} aria-hidden />\n <input\n autoFocus\n value={q}\n onChange={(e) => {\n setQ(e.target.value);\n setActive(0);\n }}\n onKeyDown={(e) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive((a) => Math.min(total - 1, a + 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(0, a - 1));\n } else if (e.key === \"Home\") {\n e.preventDefault();\n setActive(0);\n } else if (e.key === \"End\") {\n e.preventDefault();\n setActive(Math.max(0, total - 1));\n } else if (e.key === \"Enter\" && total) {\n e.preventDefault();\n choose(Math.min(active, total - 1));\n }\n }}\n placeholder={`${searchLabel}…`}\n role=\"combobox\"\n aria-expanded\n aria-autocomplete=\"list\"\n aria-controls={listId}\n aria-activedescendant={total ? optionId(Math.min(active, total - 1)) : undefined}\n aria-label={searchLabel}\n className=\"h-full min-w-0 flex-1 bg-transparent text-kit-sm text-kit-fg outline-none placeholder:text-kit-fg-3\"\n />\n </label>\n <div id={listId} className=\"max-h-72 overflow-y-auto p-1\" role=\"listbox\" aria-label={`${noun} results`} aria-multiselectable={multi || undefined} aria-busy={loading || undefined}>\n {none ? (\n <button\n type=\"button\"\n id={optionId(0)}\n role=\"option\"\n aria-selected={false}\n tabIndex={-1}\n onMouseEnter={() => setActive(0)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onNone}\n className={cn(\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm text-kit-fg-3 hover:bg-kit-hover\", active === 0 && \"bg-kit-hover\")}\n >\n None\n </button>\n ) : null}\n {rows.map((o, j) => {\n const i = j + (none ? 1 : 0);\n const on = selected.includes(o.id);\n return (\n <button\n type=\"button\"\n key={`${o.kind}:${o.id}`}\n id={optionId(i)}\n role=\"option\"\n aria-selected={on}\n tabIndex={-1}\n onMouseEnter={() => setActive(i)}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(o)}\n className={cn(\"flex w-full items-center gap-2.5 rounded-kit-md p-1.5 text-left\", i === active && \"bg-kit-hover\")}\n >\n {multi ? (\n <span aria-hidden className={cn(\"flex size-4 shrink-0 items-center justify-center rounded-kit-md border\", on ? \"border-kit-accent bg-kit-accent text-kit-accent-on\" : \"border-kit-line-strong\", !on && full && \"opacity-40\")}>\n {on ? <IconCheck className=\"size-3\" stroke={3} /> : null}\n </span>\n ) : null}\n <RefThumb o={o} size={28} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-kit-sm text-kit-fg\">{o.title}</span>\n {o.subtitle ? <span className=\"block truncate text-kit-xs text-kit-fg-3\">{o.subtitle}</span> : null}\n </span>\n <DraftChip status={o.status} missingRequired={o.missingRequired} />\n {!multi && on ? <IconCheck className=\"size-4 shrink-0 text-kit-fg\" stroke={2} aria-hidden /> : null}\n </button>\n );\n })}\n {!loading && !error && rows.length === 0 ? (\n <div className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">\n No matches\n {noCreateWhy ? (\n <p role=\"note\" className=\"mt-1 text-kit-xs\">\n {noCreateWhy}\n </p>\n ) : null}\n </div>\n ) : null}\n {loading && rows.length === 0 ? (\n <div role=\"status\" className=\"px-3 py-6 text-center text-kit-sm text-kit-fg-3\">\n Searching…\n </div>\n ) : null}\n {error ? (\n <p role=\"alert\" className=\"px-3 py-3 text-kit-xs text-kit-danger-fg\">\n {plural(noun).replace(/^./, (c) => c.toUpperCase())} could not be listed: {error}\n </p>\n ) : null}\n </div>\n {truncated && !error ? (\n <p role=\"note\" className=\"border-t border-kit-line px-3 py-2 text-kit-xs text-kit-warning-fg\">\n Some {plural(noun)} were not checked against this field's filter, so the list may be incomplete. Search by name to narrow it.\n </p>\n ) : null}\n {multi ? (\n <div className={cn(\"border-t border-kit-line px-3 py-2 text-kit-xs\", full ? \"text-kit-warning-fg\" : \"text-kit-fg-3\")}>\n {selected.length}\n {max != null ? ` of ${max}` : \"\"} selected{full ? ` · Limit is ${max}. Picking another swaps out the last one.` : \"\"}\n </div>\n ) : null}\n {canCreate ? (\n <div className=\"border-t border-kit-line p-1.5\">\n {creating ? (\n <>\n <form\n className=\"flex items-center gap-1.5\"\n onSubmit={(e) => {\n e.preventDefault();\n e.stopPropagation();\n const t = String(new FormData(e.currentTarget).get(\"t\") ?? \"\").trim();\n if (t) void create(t);\n }}\n >\n <input\n name=\"t\"\n autoFocus\n defaultValue={q}\n aria-label={`New ${noun} name`}\n placeholder={`New ${noun} name`}\n className=\"h-8 min-w-0 flex-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-2 text-kit-sm text-kit-fg outline-none focus:bg-kit-field-bg focus:ring-1 focus:ring-kit-line-strong\"\n />\n <Button size=\"sm\" type=\"submit\" variant=\"primary\" loading={createBusy} disabled={createBusy}>\n Create\n </Button>\n </form>\n {createError ? (\n <p role=\"alert\" className=\"mt-1.5 px-1 text-kit-xs text-kit-danger-fg\">\n {createError}\n </p>\n ) : null}\n </>\n ) : (\n <button\n type=\"button\"\n onClick={() => setCreating(true)}\n className=\"flex h-8 w-full items-center gap-2 rounded-kit-md px-2 text-left text-kit-sm text-kit-fg-2 hover:bg-kit-hover hover:text-kit-fg\"\n >\n <IconPlus className=\"size-4\" stroke={1.5} aria-hidden />\n Create new {noun}\n {q ? <span className=\"truncate text-kit-fg-3\">“{q}”</span> : null}\n </button>\n )}\n </div>\n ) : null}\n </div>\n );\n}\n\nconst noCapability = (_to: string | null): KitReferenceCreateCapability | undefined => undefined;\n\n/**\n * \"Create new\" only where the host can create a draft in the ONE entry model the field targets, and, when the host\n * answers per target (useReferenceCreate), only where that model takes one. Otherwise `why`, for the empty state:\n * the target's own refusal, else the host's createDisabledReason. A capability not known yet shows neither.\n */\nfunction useCreate(to: string[]): { can: boolean; why?: string } {\n const { createReference, createDisabledReason, useReferenceCreate } = useKitServices();\n const one = to.length === 1 && isEntryTarget(to[0]) ? to[0] : null;\n const useCapability = useReferenceCreate ?? noCapability;\n const cap = useCapability(one);\n if (!one) return { can: false };\n if (useReferenceCreate) {\n if (!cap) return { can: false };\n if (!cap.ok) return { can: false, why: cap.reason };\n }\n return createReference ? { can: true } : { can: false, why: createDisabledReason };\n}\n\n/** Why the field cannot change its value here (no search service), in words. */\nfunction NoSearch({ title }: { title: string }) {\n return (\n <p role=\"note\" className=\"text-kit-xs text-kit-fg-3\">\n No reference search is connected to this editor, so {title} can't be changed here.\n </p>\n );\n}\n\n/* ── Single reference ──────────────────────────────────────────────── */\nexport function ReferenceControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const env = useKitEnv();\n const { searchReferences } = useKitServices();\n const to = targetsOf(field);\n const noun = referenceNoun(to, field.reference?.noun);\n const current = typeof value === \"string\" && value ? value : null;\n const ids = React.useMemo(() => (current ? [current] : []), [current]);\n const rec = useReferenceRecords(ids, to);\n const createState = useCreate(to);\n const canCreate = createState.can && !readOnly;\n const [open, setOpen] = React.useState(false);\n const pick = (o: KitReferenceOption) => {\n rec.remember(o);\n onChange(o.id);\n setOpen(false);\n };\n /* the trigger opens like V2's even with no search service; the popover then says why nothing can be picked */\n const editable = !readOnly;\n const body = !editable ? null : !searchReferences ? (\n <PopoverContent className=\"w-[300px] p-3\" align=\"start\" collisionAvoidance={SHIFT}>\n <NoSearch title={field.title} />\n </PopoverContent>\n ) : (\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\" collisionAvoidance={SHIFT}>\n <PickerBody\n to={to}\n filter={field.reference?.filter}\n excludeId={field.reference?.excludeId}\n selected={current ? [current] : []}\n noun={noun}\n onPick={pick}\n onNone={\n current\n ? () => {\n onChange(null);\n setOpen(false);\n }\n : undefined\n }\n canCreate={canCreate}\n noCreateWhy={createState.why}\n onCreated={pick}\n />\n </PopoverContent>\n );\n\n const missing = !!current && rec.missing.has(current);\n if (current && !missing) {\n const o = rec.known[current];\n const title = o?.title ?? (rec.loading ? \"Loading…\" : current);\n const subtitle = o ? o.subtitle : rec.error ?? (!rec.canLookup ? `Saved ${noun} id` : null);\n const openable = !!o && o.kind === \"entry\" && !!o.modelSlug && !!env.onOpenReference;\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <div data-slot=\"kit-reference-card\" className=\"group/ref flex items-center gap-2.5 rounded-kit-lg border border-kit-line bg-kit-control-bg p-1.5 pr-1 transition-colors hover:border-kit-line-strong\">\n <PopoverTrigger\n id={id}\n disabled={!editable}\n aria-label={`${field.title}: ${title}.${editable ? \" Change\" : \"\"}`}\n className=\"flex min-w-0 flex-1 items-center gap-2.5 text-left\"\n >\n <RefThumb o={o ?? null} size={32} />\n <span className=\"min-w-0 flex-1\">\n <span className={cn(\"block truncate text-kit-sm font-medium text-kit-fg\", !o && !rec.canLookup && \"font-kit-mono text-kit-xs\")}>{title}</span>\n {subtitle ? <span className={cn(\"block truncate text-kit-xs\", rec.error && !o ? \"text-kit-danger-fg\" : \"text-kit-fg-3\")}>{subtitle}</span> : null}\n </span>\n <DraftChip status={o?.status} missingRequired={o?.missingRequired} />\n </PopoverTrigger>\n {readOnly ? null : (\n <Menu>\n <MenuTrigger\n aria-label={`${o?.title ?? field.title} actions`}\n className=\"flex size-7 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-48\">\n {openable ? (\n <MenuItem icon={<IconArrowUpRight stroke={1.5} />} onClick={() => env.onOpenReference!({ collectionId: o!.modelSlug!, entryId: o!.id, title: o!.title })}>\n Open {o!.title.length > 18 ? `${o!.title.slice(0, 16)}…` : o!.title}\n </MenuItem>\n ) : null}\n {editable ? (\n <MenuItem icon={<IconReplace stroke={1.5} />} onClick={() => window.setTimeout(() => setOpen(true), 0)}>\n Replace\n </MenuItem>\n ) : null}\n {openable || editable ? <MenuSeparator /> : null}\n <MenuItem danger icon={<IconTrash stroke={1.5} />} onClick={() => onChange(null)}>\n Remove\n </MenuItem>\n </MenuContent>\n </Menu>\n )}\n </div>\n {body}\n </Popover>\n );\n }\n /* empty, or a saved id the lookup cannot find: V2's select trigger (V2 draws an unresolved id as no selection). Ours\n says \"Missing\" on it instead of hiding the saved id (DESIGN 9.6); the picker's None clears it, a row replaces it. */\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n id={id}\n disabled={!editable}\n data-slot={missing ? \"kit-reference-card\" : undefined}\n data-missing={missing || undefined}\n aria-label={missing ? `${field.title}: Missing ${noun}.${editable ? \" Change\" : \"\"}` : `${field.title}: select ${withArticle(noun)}`}\n className={cn(\n \"flex h-8 w-full items-center gap-2 rounded-kit-md border border-kit-line-strong bg-kit-field-bg px-2.5 text-left text-kit-sm text-kit-fg-3 transition-colors hover:border-kit-line-strong data-[popup-open]:border-kit-line-strong data-[popup-open]:bg-kit-field-bg\",\n missing && \"border-kit-warning-line text-kit-warning-fg hover:border-kit-warning-line data-[popup-open]:border-kit-warning-line\",\n )}\n >\n <IconFileDatabase className=\"size-4\" stroke={1.5} aria-hidden />\n {missing ? (\n <span className=\"flex-1 truncate\">\n Missing {noun}\n <span className=\"sr-only\">. Deleted, or not visible to you. The saved id stays until you replace or remove it.</span>\n </span>\n ) : (\n <span className=\"flex-1 truncate\">Select {withArticle(noun)}</span>\n )}\n <IconChevronDown className=\"size-3.5\" stroke={1.5} aria-hidden />\n </PopoverTrigger>\n {body}\n </Popover>\n );\n}\n\n/* ── Multi-reference: an array of ids ─────────────────────────────── */\nfunction RefChip({\n id,\n o,\n canLookup,\n readOnly,\n sort,\n onRemove,\n}: {\n id: string;\n o?: KitReferenceOption;\n /** false: no lookup service, so the saved id is all there is to show (never a \"Loading…\" that never ends) */\n canLookup: boolean;\n readOnly?: boolean;\n sort: ReturnType<typeof useDragReorder>;\n onRemove: () => void;\n}) {\n const handle = sort.handle(id);\n const register = sort.register(id);\n const title = o?.title ?? (canLookup ? \"Loading…\" : id);\n /* V2: the chip itself is the sortable item (thumb, title and remove button inside it) */\n return (\n <span\n {...(readOnly ? {} : handle)}\n ref={(el: HTMLElement | null) => {\n register(el);\n if (!readOnly) handle.ref(el);\n }}\n style={sort.style(id)}\n tabIndex={0}\n role=\"group\"\n aria-roledescription=\"sortable item\"\n aria-label={readOnly ? title : `${title}, drag to reorder`}\n onKeyDown={(e) => {\n // keys on the remove button are the button's own\n if (readOnly || e.target !== e.currentTarget) return;\n if (e.key === \"Delete\" || e.key === \"Backspace\") {\n e.preventDefault();\n onRemove();\n return;\n }\n handle.onKeyDown(e);\n }}\n className={cn(\n \"inline-flex h-6 max-w-full cursor-grab touch-none items-center gap-1.5 rounded-kit-md border border-kit-line bg-kit-control-bg pl-0.5 pr-1 text-kit-sm text-kit-fg shadow-kit-xs active:cursor-grabbing\",\n sort.active === id && \"z-10 shadow-kit-md\",\n )}\n >\n <RefThumb o={o ?? null} size={20} />\n <span className=\"truncate\">{title}</span>\n {/* a picker-made draft says what is left to fill, as the single card does; other chips stay V2's */}\n {o?.missingRequired ? <DraftChip status={o.status} missingRequired={o.missingRequired} /> : null}\n {readOnly ? null : (\n <button type=\"button\" aria-label={`Remove ${title}`} onPointerDown={(e) => e.stopPropagation()} onClick={onRemove} className=\"flex rounded-kit-md p-0.5 text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconX className=\"size-3\" stroke={1.5} aria-hidden />\n </button>\n )}\n </span>\n );\n}\n\n/** Multi-reference: an array of reference ids. `field` is the ARRAY field; the engine hands it the item's `reference`. */\nexport function ReferencesControl({ field, value, onChange, readOnly, id }: ControlProps) {\n const { searchReferences } = useKitServices();\n const item = Array.isArray(field.of) ? field.of[0] : undefined;\n const to = item?.reference?.to ?? field.reference?.to ?? [];\n const filter = item?.reference?.filter ?? field.reference?.filter;\n const noun = referenceNoun(to, item?.reference?.noun ?? field.reference?.noun);\n const ids = React.useMemo(() => (Array.isArray(value) ? value : []).filter((x): x is string => typeof x === \"string\" && x !== \"\"), [value]);\n const rec = useReferenceRecords(ids, to);\n const createState = useCreate(to);\n const canCreate = createState.can && !readOnly;\n const max = field.validation?.max;\n /* ids the lookup cannot find are drawn as ONE compact \"n missing\" chip after Add (V2 hides them; one row keeps V2's height),\n so the chips that sort are the rest; a reorder puts them back around the missing ids, which keep their places */\n const missingIds = ids.filter((x) => rec.missing.has(x));\n const shown = missingIds.length ? ids.filter((x) => !rec.missing.has(x)) : ids;\n const sort = useDragReorder(\n shown,\n (from, to2) => {\n const next = [...shown];\n const [moved] = next.splice(from, 1);\n next.splice(to2, 0, moved);\n let i = 0;\n onChange(ids.map((x) => (rec.missing.has(x) ? x : next[i++])));\n },\n { axis: \"grid\", disabled: readOnly },\n );\n const missingNoun = missingIds.length === 1 ? noun : plural(noun);\n const toggle = (o: KitReferenceOption) => {\n rec.remember(o);\n if (ids.includes(o.id)) return onChange(ids.filter((x) => x !== o.id));\n if (max != null && ids.length >= max) return onChange([...ids.slice(0, -1), o.id]); // swap in place at the limit\n onChange([...ids, o.id]);\n };\n return (\n <div className=\"flex flex-col gap-1\">\n {/* the field label points at the Add trigger; read-only there is none, so the box carries the id. The chips sit\n straight in the wrapping box, as V2's do (a wrapper would take them out of the box's flow). V2's box has no\n role or name while editing; read-only (no Add to label) it is named as a group. */}\n <div\n id={readOnly ? id : undefined}\n role={readOnly ? \"group\" : undefined}\n aria-label={readOnly ? field.title : undefined}\n className=\"flex min-h-8 flex-wrap items-center gap-1 rounded-kit-md border border-kit-line-strong bg-kit-field-bg p-1 transition-colors hover:border-kit-line-strong\"\n >\n {shown.map((x) => (\n <RefChip key={x} id={x} o={rec.known[x]} canLookup={rec.canLookup} readOnly={readOnly} sort={sort} onRemove={() => onChange(ids.filter((y) => y !== x))} />\n ))}\n {sort.a11y}\n {!readOnly ? (\n <Popover>\n <PopoverTrigger id={id} className=\"inline-flex h-6 items-center gap-1 rounded-kit-md px-1.5 text-kit-sm text-kit-fg-3 hover:bg-kit-hover hover:text-kit-fg\">\n <IconPlus className=\"size-3.5\" stroke={1.5} aria-hidden />\n Add\n </PopoverTrigger>\n <PopoverContent className=\"w-[300px] p-0\" align=\"start\" collisionAvoidance={SHIFT}>\n {/* no search service: the picker says why instead of listing anything */}\n {!searchReferences ? (\n <div className=\"p-3\">\n <NoSearch title={field.title} />\n </div>\n ) : (\n <PickerBody\n to={to}\n filter={filter}\n excludeId={item?.reference?.excludeId ?? field.reference?.excludeId}\n selected={ids}\n multi\n max={max}\n noun={noun}\n onPick={toggle}\n canCreate={canCreate}\n noCreateWhy={createState.why}\n onCreated={(o) => {\n rec.remember(o);\n onChange(max != null && ids.length >= max ? [...ids.slice(0, -1), o.id] : [...ids, o.id]);\n }}\n />\n )}\n </PopoverContent>\n </Popover>\n ) : ids.length === 0 ? (\n <span className=\"px-1.5 text-kit-sm text-kit-fg-3\">None</span>\n ) : null}\n {/* after Add, so Add keeps V2's place (V2 draws nothing for these ids) */}\n {missingIds.length ? (\n <span\n data-missing\n data-slot=\"kit-reference-missing\"\n className=\"inline-flex h-6 max-w-full items-center gap-1 rounded-kit-md border border-kit-warning-line bg-kit-control-bg pl-1.5 pr-1 text-kit-sm text-kit-warning-fg shadow-kit-xs\"\n >\n <span className=\"truncate tabular-nums\">\n {missingIds.length} missing\n <span className=\"sr-only\">\n {\" \"}\n {missingNoun}. Deleted, or not visible to you. The saved {missingIds.length === 1 ? \"id stays\" : \"ids stay\"} until you remove {missingIds.length === 1 ? \"it\" : \"them\"}.\n </span>\n </span>\n {readOnly ? null : (\n <button\n type=\"button\"\n aria-label={`Remove ${missingIds.length} missing ${missingNoun}`}\n onClick={() => onChange(ids.filter((y) => !rec.missing.has(y)))}\n className=\"flex rounded-kit-sm p-0.5 hover:bg-kit-hover hover:text-kit-fg\"\n >\n <IconX className=\"size-3\" stroke={1.5} aria-hidden />\n </button>\n )}\n </span>\n ) : null}\n </div>\n {rec.error ? (\n <p role=\"alert\" className=\"text-kit-xs text-kit-danger-fg\">\n {rec.error}\n </p>\n ) : null}\n {max != null ? (\n <span className=\"tabular-nums self-end text-kit-xs text-kit-fg-3\">\n {ids.length} / {max}\n </span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cn } from "../../lib/cn.js";
|
|
2
|
+
import { useKitEnv } from "../../context.js";
|
|
2
3
|
import { Button, IconButton } from "../../ui/button.js";
|
|
3
4
|
import { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from "../../ui/overlay.js";
|
|
4
5
|
import { SchemaForm } from "../../engine/schema-form.js";
|
|
@@ -178,6 +179,7 @@ var ArticleCard = React.forwardRef(function ArticleCard({ label, kind, ro, editi
|
|
|
178
179
|
});
|
|
179
180
|
/** The block's settings, built from its schema (V2 ArticleForm: the kit SchemaForm, flush to the panel's top). */
|
|
180
181
|
function ArticleForm({ schema, label, value, onChange, ro }) {
|
|
182
|
+
const { onOpenReference } = useKitEnv();
|
|
181
183
|
return /* @__PURE__ */ jsxs("div", {
|
|
182
184
|
"data-article-form": "",
|
|
183
185
|
className: "min-w-0",
|
|
@@ -192,7 +194,8 @@ function ArticleForm({ schema, label, value, onChange, ro }) {
|
|
|
192
194
|
env: {
|
|
193
195
|
docId: `article:${schema.name}`,
|
|
194
196
|
docTitle: label
|
|
195
|
-
}
|
|
197
|
+
},
|
|
198
|
+
onOpenReference
|
|
196
199
|
}), /* @__PURE__ */ jsx("style", { children: `[data-article-form] [data-kit-form] section:first-of-type { border-top-width: 0; margin-top: 0; padding-top: 0; }` })]
|
|
197
200
|
});
|
|
198
201
|
}
|