@bettercms-ai/kit 2.0.0-next.5 → 2.0.0-next.6
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/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/schema/types.d.ts +1 -0
- package/dist/schema/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"article-shell.js","names":[],"sources":["../../../src/controls/rich-text/article-shell.tsx"],"sourcesContent":["/**\n * RICH TEXT · the article-block shell (V2 article-blocks.tsx ArticleBlock), shared by every article block: the one-open\n * store (one panel or popover open at a time), the card the block draws in (a focusable group: Enter opens it, Escape\n * closes it then leaves, ⌘Z / ⌘⇧Z, ⌘D, ⌥↑/↓, Backspace), the edit / remove chip on its top edge, the empty state, the\n * schema form a panel or popover holds, and the floating properties panel (D54).\n *\n * surface \"panel\" ArticlePanelBlock: ArticleCard + useArticleOpen + ArticlePanel(ArticleForm) (pull quote, gallery,\n * related posts)\n * surface \"popover\" ArticlePopoverBlock: ArticleCard + useArticleOpen + a Popover of ArticleForm (embed, table of\n * contents, author bio)\n * surface \"inline\" ArticleCard without onOpen: the block edits in the text itself (key takeaways)\n */\nimport * as React from \"react\";\nimport { IconArrowsMove, IconCopy, IconDimensions, IconDots, IconLayoutSidebar, IconLayoutSidebarRight, IconSettings, IconTrash, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { eventKey } from \"../../lib/key-event\";\nimport { Button, IconButton } from \"../../ui/button\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from \"../../ui/overlay\";\nimport { FloatingPanel, type FloatingPanelHandle } from \"../../ui/floating-panel\";\nimport { SchemaForm } from \"../../engine/schema-form\";\nimport type { TypeSchema } from \"../../schema/types\";\nimport type { IslandEl } from \"./dom\";\nimport type { IslandCtx } from \"./blocks\";\n\n/* ── one article panel open at a time (V2 useOpenArticle) ── */\nexport interface OpenArticle {\n id: string;\n /** the field the panel focuses when it opens (a click on the preview's `data-field`), null = the first */\n focusKey: string | null;\n /** bumps on every open, so re-opening the open block refocuses */\n nonce: number;\n}\nlet openArticle: OpenArticle | null = null;\nconst articleSubs = new Set<() => void>();\nconst setOpenArticle = (next: OpenArticle | null) => {\n openArticle = next;\n articleSubs.forEach((f) => f());\n};\n/** The article block open now, if any. */\nexport const currentOpenArticle = () => openArticle;\nexport function useOpenArticle() {\n return React.useSyncExternalStore(\n (cb) => (articleSubs.add(cb), () => void articleSubs.delete(cb)),\n () => openArticle,\n () => openArticle,\n );\n}\n\n/**\n * One block's place in the one-open store: `open(field?)` opens it (closing any other), `close()` closes it if it is\n * the open one. It closes when the block unmounts, and a fresh insert (`autoFocus`) opens its form.\n */\nexport function useArticleOpen({ ro, autoFocus }: { ro: boolean; autoFocus: boolean }) {\n const uid = React.useId();\n const open = useOpenArticle();\n const editing = open?.id === uid;\n const openPanel = React.useCallback((k?: string | null) => {\n if (!ro) setOpenArticle({ id: uid, focusKey: k ?? null, nonce: (openArticle?.nonce ?? 0) + 1 });\n }, [uid, ro]);\n const close = React.useCallback(() => {\n if (openArticle?.id === uid) setOpenArticle(null);\n }, [uid]);\n React.useEffect(() => () => {\n if (openArticle?.id === uid) setOpenArticle(null);\n }, [uid]);\n React.useEffect(() => {\n // a fresh insert opens its form\n if (autoFocus && !ro) openPanel();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n return { open, editing, openPanel, close };\n}\n\nconst controlOf = (el: HTMLElement) =>\n Array.from(el.querySelectorAll<HTMLElement>(\"textarea, input:not([type=hidden]), [contenteditable=true], [role=combobox]\")).find((n) => n.getClientRects().length) ??\n Array.from(el.querySelectorAll<HTMLElement>(\":scope > :not(:first-child) button\")).find((n) => n.getClientRects().length);\n/** Focus the form row `key` names (`data-field-key`), else the first row. */\nexport function focusField(root: HTMLElement | null, key: string | null) {\n if (!root) return;\n const rows = Array.from(root.querySelectorAll<HTMLElement>(\"[data-field-key]\"));\n const row = (key && rows.find((r) => r.getAttribute(\"data-field-key\") === key)) || rows[0];\n if (!row) return;\n row.scrollIntoView({ block: \"nearest\" });\n controlOf(row)?.focus({ preventScroll: true });\n}\n\n/**\n * V2 ArticleBlock onKeyDown, on the card itself (its own fields handle their own keys). With `onOpen` (a panel or\n * popover block) Enter / Space open it and Escape closes it first; without (an inline block) Escape leaves the block.\n */\nexport function articleCardKeyDown({\n card, ctx, el, ro, editing = false, onOpen, onClose, focusCard,\n}: {\n card: React.RefObject<HTMLElement | null>;\n ctx: IslandCtx;\n el: IslandEl;\n ro: boolean;\n editing?: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n focusCard: () => void;\n}) {\n return (e: React.KeyboardEvent) => {\n if (e.defaultPrevented || e.target !== card.current) return;\n const mod = e.metaKey || e.ctrlKey;\n const k = eventKey(e);\n if (mod && k === \"z\") {\n e.preventDefault();\n e.stopPropagation();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n return;\n }\n if (onOpen && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onOpen();\n return;\n }\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n if (editing) onClose?.();\n else ctx.exit(el);\n return;\n }\n if (ro) return;\n if (mod && k === \"d\" && ctx.duplicate) {\n e.preventDefault();\n e.stopPropagation();\n ctx.duplicate(el);\n } else if (e.altKey && (e.key === \"ArrowUp\" || e.key === \"ArrowDown\") && ctx.move) {\n e.preventDefault();\n ctx.move(el, e.key === \"ArrowUp\" ? -1 : 1);\n focusCard();\n } else if (e.key === \"Backspace\" || e.key === \"Delete\") {\n e.preventDefault();\n ctx.remove(el);\n }\n };\n}\n\n/** The chip on the block's top edge (so it never covers the block's own text): Edit (with `onEdit`) and Remove. */\nexport function ArticleActions({\n label, ctx, el, editing = false, onEdit, tooltips = false,\n}: {\n label: string;\n ctx: IslandCtx;\n el: IslandEl;\n editing?: boolean;\n /** toggles the block's panel or popover; absent on an inline block */\n onEdit?: () => void;\n /** each button also says what it does in a tooltip */\n tooltips?: boolean;\n}) {\n if (ctx.readOnly) return null;\n const tip = (content: string, button: React.ReactElement) => (tooltips ? <Tooltip content={content}>{button}</Tooltip> : button);\n return (\n <div\n className={cn(\n \"absolute -top-3.5 right-2 z-[2] flex items-center gap-0.5 rounded-kit-md border border-kit-line bg-kit-surface-raised p-0.5 opacity-0 shadow-kit-sm transition-opacity\",\n \"group-hover/art:opacity-100 group-focus-within/art:opacity-100 pointer-coarse:opacity-100\",\n editing && \"opacity-100\",\n )}\n >\n {onEdit\n ? tip(\n `Edit ${label.toLowerCase()}`,\n <IconButton size=\"xs\" label={`Edit ${label.toLowerCase()}`} onClick={onEdit}>\n <IconSettings stroke={1.5} />\n </IconButton>,\n )\n : null}\n {tip(\n `Remove ${label.toLowerCase()}`,\n <IconButton size=\"xs\" label={`Remove ${label.toLowerCase()}`} onClick={() => ctx.remove(el)} className=\"hover:text-kit-danger-fg\">\n <IconTrash stroke={1.5} />\n </IconButton>,\n )}\n </div>\n );\n}\n\n/**\n * The card an article block draws in. With `onOpen` (panel / popover) it is pressable: a click opens it on the field\n * clicked (`data-field`), and it shows the open ring while `editing`. Without, it is the inline block's quiet group.\n */\nexport const ArticleCard = React.forwardRef<\n HTMLDivElement,\n { label: string; kind: string; ro: boolean; editing?: boolean; onOpen?: (field: string | null) => void; onKeyDown: (e: React.KeyboardEvent) => void; children: React.ReactNode }\n>(function ArticleCard({ label, kind, ro, editing = false, onOpen, onKeyDown, children }, ref) {\n if (!onOpen)\n return (\n <div\n ref={ref}\n role=\"group\"\n tabIndex={0}\n aria-label={label}\n aria-roledescription=\"block\"\n data-rt-isolate=\"\"\n data-article-block={kind}\n onKeyDown={onKeyDown}\n className=\"group/art relative rounded-kit-lg outline-none transition-shadow duration-150 focus-visible:shadow-[0_0_0_1px_var(--kit-line-strong)]\"\n >\n {children}\n </div>\n );\n return (\n <div\n ref={ref}\n role=\"group\"\n tabIndex={0}\n aria-label={`${label}${editing ? \", editing\" : \"\"}`}\n aria-roledescription=\"block\"\n aria-haspopup=\"dialog\"\n aria-expanded={editing}\n data-rt-isolate=\"\"\n data-article-block={kind}\n onKeyDown={onKeyDown}\n onClick={(e) => {\n if (ro || !e.currentTarget.contains(e.target as Node)) return;\n const t = e.target as HTMLElement;\n if (t.closest(\"button,a,[role=menuitem]\")) return;\n onOpen(t.closest<HTMLElement>(\"[data-field]\")?.getAttribute(\"data-field\") ?? null);\n }}\n className={cn(\n \"group/art relative rounded-kit-lg outline-none transition-shadow duration-150\",\n !ro && \"cursor-pointer\",\n \"focus-visible:shadow-[0_0_0_1px_var(--kit-line-strong)]\",\n editing ? \"shadow-[0_0_0_2px_var(--kit-accent)] focus-visible:shadow-[0_0_0_2px_var(--kit-accent)]\" : !ro && \"hover:shadow-[0_0_0_1px_var(--kit-line)]\",\n )}\n >\n {children}\n </div>\n );\n});\n\n/** The block's settings, built from its schema (V2 ArticleForm: the kit SchemaForm, flush to the panel's top). */\nexport function ArticleForm({\n schema, label, value, onChange, ro,\n}: {\n schema: TypeSchema;\n label: string;\n value: Record<string, unknown>;\n onChange: (v: Record<string, unknown>) => void;\n ro: boolean;\n}) {\n return (\n <div data-article-form=\"\" className=\"min-w-0\">\n <SchemaForm schema={schema} value={value} onChange={onChange} variant=\"panel\" scroll={false} readOnly={ro} rootLabel={label} env={{ docId: `article:${schema.name}`, docTitle: label }} />\n <style>{`[data-article-form] [data-kit-form] section:first-of-type { border-top-width: 0; margin-top: 0; padding-top: 0; }`}</style>\n </div>\n );\n}\n\n/** V2 article-blocks.tsx Empty: a block with nothing to show yet. */\nexport const ArticleEmpty = ({ icon, title, action, onAction, ro }: { icon: React.ReactNode; title: string; action: string; onAction: () => void; ro: boolean }) => (\n <div className=\"flex items-center gap-3 rounded-kit-lg border border-dashed border-kit-line-strong bg-kit-subtle px-4 py-3.5\">\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg-2 [&_svg]:size-4\">{icon}</span>\n <span className=\"min-w-0 flex-1 text-kit-sm font-medium text-kit-fg\">{title}</span>\n {ro ? null : (\n <Button size=\"sm\" onClick={onAction}>\n {action}\n </Button>\n )}\n </div>\n);\n\n/* ── Floating properties panel (D54 primitive; V2 ArticlePanel) ─────────────── */\nexport function ArticlePanel({\n label, anchor, nonce, focusKey, onClose, focusBack, ctx, el, children,\n}: {\n label: string;\n anchor: HTMLElement | null;\n nonce: number;\n focusKey: string | null;\n onClose: () => void;\n focusBack: () => void;\n ctx: IslandCtx;\n el: IslandEl;\n children: React.ReactNode;\n}) {\n const panel = React.useRef<FloatingPanelHandle>(null);\n const titleId = React.useId();\n const container = anchor?.closest<HTMLElement>(\"[data-expanded-editor]\") ?? null;\n React.useEffect(() => {\n // the panel mounts (and, inside the expanded editor, docks) over a few frames; focus lands on the field asked for,\n // and is put back while it is lost (never taken from somewhere the person went)\n const timers: number[] = [];\n let landed = false;\n for (const ms of [40, 90, 160, 260, 420, 640]) {\n timers.push(\n window.setTimeout(() => {\n const root = panel.current?.el() ?? null;\n if (!root?.querySelector(\"[data-field-key]\")) return;\n const a = document.activeElement as HTMLElement | null;\n const lost = !a || a === document.body || a.hasAttribute(\"data-expanded-editor\") || a.hasAttribute(\"data-article-block\");\n if (root.contains(a)) return void (landed = true);\n if (!landed || lost) focusField(root, focusKey);\n if (root.contains(document.activeElement)) landed = true;\n }, ms),\n );\n }\n return () => timers.forEach((t) => window.clearTimeout(t));\n }, [nonce]); // eslint-disable-line react-hooks/exhaustive-deps\n React.useEffect(() => panel.current?.announce(`${label} properties.`), [label]);\n const header = (\n <>\n <span id={titleId} className=\"min-w-0 flex-1 truncate text-kit-sm font-medium text-kit-fg\">{label}</span>\n <Menu>\n <MenuTrigger\n render={\n <IconButton size=\"sm\" label={`${label} actions`}>\n <IconDots stroke={1.5} />\n </IconButton>\n }\n />\n <MenuContent align=\"end\" className=\"w-52\">\n {ctx.readOnly || !ctx.duplicate ? null : (\n <>\n <MenuItem icon={<IconCopy stroke={1.5} />} onClick={() => ctx.duplicate?.(el)}>Duplicate</MenuItem>\n <MenuSeparator />\n </>\n )}\n <MenuItem icon={<IconArrowsMove stroke={1.5} />} onClick={() => panel.current?.keyboard(\"move\")}>Move panel</MenuItem>\n <MenuItem icon={<IconDimensions stroke={1.5} />} onClick={() => panel.current?.keyboard(\"resize\")}>Resize panel</MenuItem>\n <MenuItem icon={<IconLayoutSidebar stroke={1.5} />} onClick={() => panel.current?.dock(\"left\")}>Dock left</MenuItem>\n <MenuItem icon={<IconLayoutSidebarRight stroke={1.5} />} onClick={() => panel.current?.dock(\"right\")}>Dock right</MenuItem>\n {ctx.readOnly ? null : (\n <>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} onClick={() => ctx.remove(el)}>Remove</MenuItem>\n </>\n )}\n </MenuContent>\n </Menu>\n <IconButton size=\"sm\" label=\"Close properties\" tooltip=\"Close\" onClick={() => (onClose(), focusBack())}>\n <IconX stroke={1.5} />\n </IconButton>\n </>\n );\n return (\n <FloatingPanel\n ref={panel}\n id=\"article-properties\"\n labelledBy={titleId}\n anchor={anchor}\n container={container}\n header={header}\n onClose={onClose}\n focusBack={focusBack}\n onPanelKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && !e.altKey && eventKey(e) === \"z\" && !e.defaultPrevented) {\n e.preventDefault();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n }\n }}\n sheetFooter={\n <Button size=\"sm\" variant=\"primary\" onClick={() => (onClose(), focusBack())}>\n Done\n </Button>\n }\n >\n <div className=\"pb-3 pt-1\">{children}</div>\n </FloatingPanel>\n );\n}\n\n/* ── The two article block surfaces ────────────────────────────────── */\n/**\n * A panel article block (V2 ArticleBlock surface \"panel\": Gallery, Related posts): the shell's card + chip, its\n * settings in the floating properties panel, one undo step per field edit.\n */\nexport function ArticlePanelBlock<M extends object>({\n label, kind, schema, m, set, el, ctx, autoFocus, openOnInsert = true, toForm, fromForm, children,\n}: {\n label: string;\n kind: string;\n schema: TypeSchema;\n m: M;\n set: (fn: (m: M) => M, label?: string) => void;\n el: IslandEl;\n ctx: IslandCtx;\n autoFocus: boolean;\n /** V2 article-blocks.tsx:127-133: a fresh insert opens the panel, except Related posts, which focuses the card */\n openOnInsert?: boolean;\n toForm: (m: M) => Record<string, unknown>;\n fromForm: (v: Record<string, unknown>, prev: M) => M;\n children: (open: (field?: string | null) => void, ro: boolean) => React.ReactNode;\n}) {\n const card = React.useRef<HTMLDivElement | null>(null);\n const [cardEl, setCardEl] = React.useState<HTMLDivElement | null>(null);\n const ro = !!ctx.readOnly;\n const { open, editing, openPanel, close } = useArticleOpen({ ro, autoFocus: autoFocus && openOnInsert });\n // a stable ref: a new callback each render would pass null for a moment and remount the panel\n const cardRef = React.useCallback((n: HTMLDivElement | null) => {\n card.current = n;\n if (n) setCardEl(n);\n }, []);\n const focusCard = React.useCallback(() => requestAnimationFrame(() => card.current?.focus({ preventScroll: true })), []);\n React.useEffect(() => {\n if (autoFocus && !openOnInsert && !ro) focusCard();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n const modelRef = React.useRef(m);\n modelRef.current = m;\n\n /** a form edit joins the body's one undo history (D54); typing coalesces per field */\n const commit = (v: Record<string, unknown>) => {\n const prev = modelRef.current;\n const before = toForm(prev);\n const field = Object.keys(v).find((k) => JSON.stringify(v[k]) !== JSON.stringify(before[k])) ?? \"\";\n set(() => fromForm(v, prev), `Edit ${label.toLowerCase()} ${field}`);\n };\n\n return (\n <>\n <ArticleCard\n ref={cardRef}\n label={label}\n kind={kind}\n ro={ro}\n editing={editing}\n onOpen={openPanel}\n onKeyDown={articleCardKeyDown({ card, ctx, el, ro, editing, onOpen: openPanel, onClose: close, focusCard })}\n >\n {children(openPanel, ro)}\n <ArticleActions label={label} ctx={ctx} el={el} editing={editing} onEdit={() => (editing ? close() : openPanel())} tooltips />\n </ArticleCard>\n {editing ? (\n <ArticlePanel label={label} anchor={cardEl} nonce={open!.nonce} focusKey={open!.focusKey} onClose={close} focusBack={focusCard} ctx={ctx} el={el}>\n <ArticleForm schema={schema} label={label} value={toForm(m)} onChange={commit} ro={ro} />\n </ArticlePanel>\n ) : null}\n </>\n );\n}\n\n/**\n * A popover article block (V2 ArticleBlock surface \"popover\": TOC, Embed, Author bio): the shell's card + chip, its\n * settings in a popover from the card's top-right corner, one undo step per field edit.\n */\nexport function ArticlePopoverBlock<M extends object>({\n label, kind, schema, m, set, el, ctx, autoFocus, openOnInsert = true, toForm, fromForm, children,\n}: {\n label: string;\n kind: string;\n schema: TypeSchema;\n m: M;\n set: (fn: (m: M) => M, label?: string) => void;\n el: IslandEl;\n ctx: IslandCtx;\n autoFocus: boolean;\n /** V2 article-blocks.tsx:127-133: a fresh insert opens the form, except TOC and Related, which focus the card */\n openOnInsert?: boolean;\n toForm: (m: M) => Record<string, unknown>;\n fromForm: (v: Record<string, unknown>, prev: M) => M;\n /** the preview; `open(field)` opens the popover on that field (the empty state's action) */\n children: (open: (field?: string | null) => void, ro: boolean) => React.ReactNode;\n}) {\n const card = React.useRef<HTMLDivElement | null>(null);\n const form = React.useRef<HTMLDivElement | null>(null);\n const ro = !!ctx.readOnly;\n const { open, editing, openPanel: openPopover, close } = useArticleOpen({ ro, autoFocus: autoFocus && openOnInsert });\n const focusCard = React.useCallback(() => requestAnimationFrame(() => card.current?.focus({ preventScroll: true })), []);\n React.useEffect(() => {\n if (autoFocus && !openOnInsert && !ro) focusCard();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n const modelRef = React.useRef(m);\n modelRef.current = m;\n const nonce = editing ? open!.nonce : 0;\n React.useEffect(() => {\n if (!nonce) return;\n const id = requestAnimationFrame(() => focusField(form.current, currentOpenArticle()?.focusKey ?? null));\n return () => cancelAnimationFrame(id);\n }, [nonce]);\n\n /** a form edit joins the body's one undo history (D54); typing coalesces per field */\n const commit = (v: Record<string, unknown>) => {\n const prev = modelRef.current;\n const before = toForm(prev);\n const field = Object.keys(v).find((k) => JSON.stringify(v[k]) !== JSON.stringify(before[k])) ?? \"\";\n set(() => fromForm(v, prev), `Edit ${label.toLowerCase()} ${field}`);\n };\n\n return (\n <Popover\n open={editing}\n onOpenChange={(o, d) => {\n if (o) return;\n close();\n // V2 onCloseAutoFocus: back on the block, unless the press that closed it went somewhere else\n if (d?.reason !== \"outside-press\") focusCard();\n }}\n >\n <ArticleCard\n ref={card}\n label={label}\n kind={kind}\n ro={ro}\n editing={editing}\n onOpen={openPopover}\n onKeyDown={articleCardKeyDown({ card, ctx, el, ro, editing, onOpen: openPopover, onClose: close, focusCard })}\n >\n {children(openPopover, ro)}\n <ArticleActions label={label} ctx={ctx} el={el} editing={editing} onEdit={() => (editing ? close() : openPopover())} tooltips />\n {/* the popover opens from the block's top-right corner, over the block, wherever the block sits */}\n <PopoverAnchor render={<span aria-hidden className=\"pointer-events-none absolute right-2 top-2 size-px\" />} />\n </ArticleCard>\n {editing ? (\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n // the anchor is a 1px dot at the card's top-right: no arrow inset, so the popup's edge sits on it (V2 AB:259-300)\n arrowPadding={0}\n className=\"w-[340px] p-0\"\n initialFocus={false}\n finalFocus={false}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && !e.altKey && eventKey(e) === \"z\" && !e.defaultPrevented) {\n e.preventDefault();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n }\n }}\n >\n <div className=\"flex h-10 items-center gap-2 border-b border-kit-line-subtle pl-4 pr-1.5\">\n <span className=\"flex-1 truncate text-kit-sm font-medium text-kit-fg\">{label}</span>\n <IconButton size=\"sm\" label=\"Close\" onClick={() => (close(), focusCard())}>\n <IconX stroke={1.5} />\n </IconButton>\n </div>\n <div ref={form} className=\"max-h-[min(480px,70vh)] overflow-y-auto pb-2\">\n <ArticleForm schema={schema} label={label} value={toForm(m)} onChange={commit} ro={ro} />\n </div>\n </PopoverContent>\n ) : null}\n </Popover>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"article-shell.js","names":[],"sources":["../../../src/controls/rich-text/article-shell.tsx"],"sourcesContent":["/**\n * RICH TEXT · the article-block shell (V2 article-blocks.tsx ArticleBlock), shared by every article block: the one-open\n * store (one panel or popover open at a time), the card the block draws in (a focusable group: Enter opens it, Escape\n * closes it then leaves, ⌘Z / ⌘⇧Z, ⌘D, ⌥↑/↓, Backspace), the edit / remove chip on its top edge, the empty state, the\n * schema form a panel or popover holds, and the floating properties panel (D54).\n *\n * surface \"panel\" ArticlePanelBlock: ArticleCard + useArticleOpen + ArticlePanel(ArticleForm) (pull quote, gallery,\n * related posts)\n * surface \"popover\" ArticlePopoverBlock: ArticleCard + useArticleOpen + a Popover of ArticleForm (embed, table of\n * contents, author bio)\n * surface \"inline\" ArticleCard without onOpen: the block edits in the text itself (key takeaways)\n */\nimport * as React from \"react\";\nimport { IconArrowsMove, IconCopy, IconDimensions, IconDots, IconLayoutSidebar, IconLayoutSidebarRight, IconSettings, IconTrash, IconX } from \"@tabler/icons-react\";\nimport { cn } from \"../../lib/cn\";\nimport { eventKey } from \"../../lib/key-event\";\nimport { Button, IconButton } from \"../../ui/button\";\nimport { Menu, MenuContent, MenuItem, MenuSeparator, MenuTrigger, Popover, PopoverAnchor, PopoverContent, Tooltip } from \"../../ui/overlay\";\nimport { FloatingPanel, type FloatingPanelHandle } from \"../../ui/floating-panel\";\nimport { SchemaForm } from \"../../engine/schema-form\";\nimport { useKitEnv } from \"../../context\";\nimport type { TypeSchema } from \"../../schema/types\";\nimport type { IslandEl } from \"./dom\";\nimport type { IslandCtx } from \"./blocks\";\n\n/* ── one article panel open at a time (V2 useOpenArticle) ── */\nexport interface OpenArticle {\n id: string;\n /** the field the panel focuses when it opens (a click on the preview's `data-field`), null = the first */\n focusKey: string | null;\n /** bumps on every open, so re-opening the open block refocuses */\n nonce: number;\n}\nlet openArticle: OpenArticle | null = null;\nconst articleSubs = new Set<() => void>();\nconst setOpenArticle = (next: OpenArticle | null) => {\n openArticle = next;\n articleSubs.forEach((f) => f());\n};\n/** The article block open now, if any. */\nexport const currentOpenArticle = () => openArticle;\nexport function useOpenArticle() {\n return React.useSyncExternalStore(\n (cb) => (articleSubs.add(cb), () => void articleSubs.delete(cb)),\n () => openArticle,\n () => openArticle,\n );\n}\n\n/**\n * One block's place in the one-open store: `open(field?)` opens it (closing any other), `close()` closes it if it is\n * the open one. It closes when the block unmounts, and a fresh insert (`autoFocus`) opens its form.\n */\nexport function useArticleOpen({ ro, autoFocus }: { ro: boolean; autoFocus: boolean }) {\n const uid = React.useId();\n const open = useOpenArticle();\n const editing = open?.id === uid;\n const openPanel = React.useCallback((k?: string | null) => {\n if (!ro) setOpenArticle({ id: uid, focusKey: k ?? null, nonce: (openArticle?.nonce ?? 0) + 1 });\n }, [uid, ro]);\n const close = React.useCallback(() => {\n if (openArticle?.id === uid) setOpenArticle(null);\n }, [uid]);\n React.useEffect(() => () => {\n if (openArticle?.id === uid) setOpenArticle(null);\n }, [uid]);\n React.useEffect(() => {\n // a fresh insert opens its form\n if (autoFocus && !ro) openPanel();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n return { open, editing, openPanel, close };\n}\n\nconst controlOf = (el: HTMLElement) =>\n Array.from(el.querySelectorAll<HTMLElement>(\"textarea, input:not([type=hidden]), [contenteditable=true], [role=combobox]\")).find((n) => n.getClientRects().length) ??\n Array.from(el.querySelectorAll<HTMLElement>(\":scope > :not(:first-child) button\")).find((n) => n.getClientRects().length);\n/** Focus the form row `key` names (`data-field-key`), else the first row. */\nexport function focusField(root: HTMLElement | null, key: string | null) {\n if (!root) return;\n const rows = Array.from(root.querySelectorAll<HTMLElement>(\"[data-field-key]\"));\n const row = (key && rows.find((r) => r.getAttribute(\"data-field-key\") === key)) || rows[0];\n if (!row) return;\n row.scrollIntoView({ block: \"nearest\" });\n controlOf(row)?.focus({ preventScroll: true });\n}\n\n/**\n * V2 ArticleBlock onKeyDown, on the card itself (its own fields handle their own keys). With `onOpen` (a panel or\n * popover block) Enter / Space open it and Escape closes it first; without (an inline block) Escape leaves the block.\n */\nexport function articleCardKeyDown({\n card, ctx, el, ro, editing = false, onOpen, onClose, focusCard,\n}: {\n card: React.RefObject<HTMLElement | null>;\n ctx: IslandCtx;\n el: IslandEl;\n ro: boolean;\n editing?: boolean;\n onOpen?: () => void;\n onClose?: () => void;\n focusCard: () => void;\n}) {\n return (e: React.KeyboardEvent) => {\n if (e.defaultPrevented || e.target !== card.current) return;\n const mod = e.metaKey || e.ctrlKey;\n const k = eventKey(e);\n if (mod && k === \"z\") {\n e.preventDefault();\n e.stopPropagation();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n return;\n }\n if (onOpen && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onOpen();\n return;\n }\n if (e.key === \"Escape\") {\n e.preventDefault();\n e.stopPropagation();\n if (editing) onClose?.();\n else ctx.exit(el);\n return;\n }\n if (ro) return;\n if (mod && k === \"d\" && ctx.duplicate) {\n e.preventDefault();\n e.stopPropagation();\n ctx.duplicate(el);\n } else if (e.altKey && (e.key === \"ArrowUp\" || e.key === \"ArrowDown\") && ctx.move) {\n e.preventDefault();\n ctx.move(el, e.key === \"ArrowUp\" ? -1 : 1);\n focusCard();\n } else if (e.key === \"Backspace\" || e.key === \"Delete\") {\n e.preventDefault();\n ctx.remove(el);\n }\n };\n}\n\n/** The chip on the block's top edge (so it never covers the block's own text): Edit (with `onEdit`) and Remove. */\nexport function ArticleActions({\n label, ctx, el, editing = false, onEdit, tooltips = false,\n}: {\n label: string;\n ctx: IslandCtx;\n el: IslandEl;\n editing?: boolean;\n /** toggles the block's panel or popover; absent on an inline block */\n onEdit?: () => void;\n /** each button also says what it does in a tooltip */\n tooltips?: boolean;\n}) {\n if (ctx.readOnly) return null;\n const tip = (content: string, button: React.ReactElement) => (tooltips ? <Tooltip content={content}>{button}</Tooltip> : button);\n return (\n <div\n className={cn(\n \"absolute -top-3.5 right-2 z-[2] flex items-center gap-0.5 rounded-kit-md border border-kit-line bg-kit-surface-raised p-0.5 opacity-0 shadow-kit-sm transition-opacity\",\n \"group-hover/art:opacity-100 group-focus-within/art:opacity-100 pointer-coarse:opacity-100\",\n editing && \"opacity-100\",\n )}\n >\n {onEdit\n ? tip(\n `Edit ${label.toLowerCase()}`,\n <IconButton size=\"xs\" label={`Edit ${label.toLowerCase()}`} onClick={onEdit}>\n <IconSettings stroke={1.5} />\n </IconButton>,\n )\n : null}\n {tip(\n `Remove ${label.toLowerCase()}`,\n <IconButton size=\"xs\" label={`Remove ${label.toLowerCase()}`} onClick={() => ctx.remove(el)} className=\"hover:text-kit-danger-fg\">\n <IconTrash stroke={1.5} />\n </IconButton>,\n )}\n </div>\n );\n}\n\n/**\n * The card an article block draws in. With `onOpen` (panel / popover) it is pressable: a click opens it on the field\n * clicked (`data-field`), and it shows the open ring while `editing`. Without, it is the inline block's quiet group.\n */\nexport const ArticleCard = React.forwardRef<\n HTMLDivElement,\n { label: string; kind: string; ro: boolean; editing?: boolean; onOpen?: (field: string | null) => void; onKeyDown: (e: React.KeyboardEvent) => void; children: React.ReactNode }\n>(function ArticleCard({ label, kind, ro, editing = false, onOpen, onKeyDown, children }, ref) {\n if (!onOpen)\n return (\n <div\n ref={ref}\n role=\"group\"\n tabIndex={0}\n aria-label={label}\n aria-roledescription=\"block\"\n data-rt-isolate=\"\"\n data-article-block={kind}\n onKeyDown={onKeyDown}\n className=\"group/art relative rounded-kit-lg outline-none transition-shadow duration-150 focus-visible:shadow-[0_0_0_1px_var(--kit-line-strong)]\"\n >\n {children}\n </div>\n );\n return (\n <div\n ref={ref}\n role=\"group\"\n tabIndex={0}\n aria-label={`${label}${editing ? \", editing\" : \"\"}`}\n aria-roledescription=\"block\"\n aria-haspopup=\"dialog\"\n aria-expanded={editing}\n data-rt-isolate=\"\"\n data-article-block={kind}\n onKeyDown={onKeyDown}\n onClick={(e) => {\n if (ro || !e.currentTarget.contains(e.target as Node)) return;\n const t = e.target as HTMLElement;\n if (t.closest(\"button,a,[role=menuitem]\")) return;\n onOpen(t.closest<HTMLElement>(\"[data-field]\")?.getAttribute(\"data-field\") ?? null);\n }}\n className={cn(\n \"group/art relative rounded-kit-lg outline-none transition-shadow duration-150\",\n !ro && \"cursor-pointer\",\n \"focus-visible:shadow-[0_0_0_1px_var(--kit-line-strong)]\",\n editing ? \"shadow-[0_0_0_2px_var(--kit-accent)] focus-visible:shadow-[0_0_0_2px_var(--kit-accent)]\" : !ro && \"hover:shadow-[0_0_0_1px_var(--kit-line)]\",\n )}\n >\n {children}\n </div>\n );\n});\n\n/** The block's settings, built from its schema (V2 ArticleForm: the kit SchemaForm, flush to the panel's top). */\nexport function ArticleForm({\n schema, label, value, onChange, ro,\n}: {\n schema: TypeSchema;\n label: string;\n value: Record<string, unknown>;\n onChange: (v: Record<string, unknown>) => void;\n ro: boolean;\n}) {\n // a form of its own (its docId keys its expand and full-screen state), but the host's way to open a reference is the\n // outer form's: Open on a picked author or story, and on a picker-made draft's toast\n const { onOpenReference } = useKitEnv();\n return (\n <div data-article-form=\"\" className=\"min-w-0\">\n <SchemaForm schema={schema} value={value} onChange={onChange} variant=\"panel\" scroll={false} readOnly={ro} rootLabel={label} env={{ docId: `article:${schema.name}`, docTitle: label }} onOpenReference={onOpenReference} />\n <style>{`[data-article-form] [data-kit-form] section:first-of-type { border-top-width: 0; margin-top: 0; padding-top: 0; }`}</style>\n </div>\n );\n}\n\n/** V2 article-blocks.tsx Empty: a block with nothing to show yet. */\nexport const ArticleEmpty = ({ icon, title, action, onAction, ro }: { icon: React.ReactNode; title: string; action: string; onAction: () => void; ro: boolean }) => (\n <div className=\"flex items-center gap-3 rounded-kit-lg border border-dashed border-kit-line-strong bg-kit-subtle px-4 py-3.5\">\n <span className=\"flex size-8 shrink-0 items-center justify-center rounded-kit-md border border-kit-line bg-kit-control-bg text-kit-fg-2 [&_svg]:size-4\">{icon}</span>\n <span className=\"min-w-0 flex-1 text-kit-sm font-medium text-kit-fg\">{title}</span>\n {ro ? null : (\n <Button size=\"sm\" onClick={onAction}>\n {action}\n </Button>\n )}\n </div>\n);\n\n/* ── Floating properties panel (D54 primitive; V2 ArticlePanel) ─────────────── */\nexport function ArticlePanel({\n label, anchor, nonce, focusKey, onClose, focusBack, ctx, el, children,\n}: {\n label: string;\n anchor: HTMLElement | null;\n nonce: number;\n focusKey: string | null;\n onClose: () => void;\n focusBack: () => void;\n ctx: IslandCtx;\n el: IslandEl;\n children: React.ReactNode;\n}) {\n const panel = React.useRef<FloatingPanelHandle>(null);\n const titleId = React.useId();\n const container = anchor?.closest<HTMLElement>(\"[data-expanded-editor]\") ?? null;\n React.useEffect(() => {\n // the panel mounts (and, inside the expanded editor, docks) over a few frames; focus lands on the field asked for,\n // and is put back while it is lost (never taken from somewhere the person went)\n const timers: number[] = [];\n let landed = false;\n for (const ms of [40, 90, 160, 260, 420, 640]) {\n timers.push(\n window.setTimeout(() => {\n const root = panel.current?.el() ?? null;\n if (!root?.querySelector(\"[data-field-key]\")) return;\n const a = document.activeElement as HTMLElement | null;\n const lost = !a || a === document.body || a.hasAttribute(\"data-expanded-editor\") || a.hasAttribute(\"data-article-block\");\n if (root.contains(a)) return void (landed = true);\n if (!landed || lost) focusField(root, focusKey);\n if (root.contains(document.activeElement)) landed = true;\n }, ms),\n );\n }\n return () => timers.forEach((t) => window.clearTimeout(t));\n }, [nonce]); // eslint-disable-line react-hooks/exhaustive-deps\n React.useEffect(() => panel.current?.announce(`${label} properties.`), [label]);\n const header = (\n <>\n <span id={titleId} className=\"min-w-0 flex-1 truncate text-kit-sm font-medium text-kit-fg\">{label}</span>\n <Menu>\n <MenuTrigger\n render={\n <IconButton size=\"sm\" label={`${label} actions`}>\n <IconDots stroke={1.5} />\n </IconButton>\n }\n />\n <MenuContent align=\"end\" className=\"w-52\">\n {ctx.readOnly || !ctx.duplicate ? null : (\n <>\n <MenuItem icon={<IconCopy stroke={1.5} />} onClick={() => ctx.duplicate?.(el)}>Duplicate</MenuItem>\n <MenuSeparator />\n </>\n )}\n <MenuItem icon={<IconArrowsMove stroke={1.5} />} onClick={() => panel.current?.keyboard(\"move\")}>Move panel</MenuItem>\n <MenuItem icon={<IconDimensions stroke={1.5} />} onClick={() => panel.current?.keyboard(\"resize\")}>Resize panel</MenuItem>\n <MenuItem icon={<IconLayoutSidebar stroke={1.5} />} onClick={() => panel.current?.dock(\"left\")}>Dock left</MenuItem>\n <MenuItem icon={<IconLayoutSidebarRight stroke={1.5} />} onClick={() => panel.current?.dock(\"right\")}>Dock right</MenuItem>\n {ctx.readOnly ? null : (\n <>\n <MenuSeparator />\n <MenuItem danger icon={<IconTrash stroke={1.5} />} onClick={() => ctx.remove(el)}>Remove</MenuItem>\n </>\n )}\n </MenuContent>\n </Menu>\n <IconButton size=\"sm\" label=\"Close properties\" tooltip=\"Close\" onClick={() => (onClose(), focusBack())}>\n <IconX stroke={1.5} />\n </IconButton>\n </>\n );\n return (\n <FloatingPanel\n ref={panel}\n id=\"article-properties\"\n labelledBy={titleId}\n anchor={anchor}\n container={container}\n header={header}\n onClose={onClose}\n focusBack={focusBack}\n onPanelKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && !e.altKey && eventKey(e) === \"z\" && !e.defaultPrevented) {\n e.preventDefault();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n }\n }}\n sheetFooter={\n <Button size=\"sm\" variant=\"primary\" onClick={() => (onClose(), focusBack())}>\n Done\n </Button>\n }\n >\n <div className=\"pb-3 pt-1\">{children}</div>\n </FloatingPanel>\n );\n}\n\n/* ── The two article block surfaces ────────────────────────────────── */\n/**\n * A panel article block (V2 ArticleBlock surface \"panel\": Gallery, Related posts): the shell's card + chip, its\n * settings in the floating properties panel, one undo step per field edit.\n */\nexport function ArticlePanelBlock<M extends object>({\n label, kind, schema, m, set, el, ctx, autoFocus, openOnInsert = true, toForm, fromForm, children,\n}: {\n label: string;\n kind: string;\n schema: TypeSchema;\n m: M;\n set: (fn: (m: M) => M, label?: string) => void;\n el: IslandEl;\n ctx: IslandCtx;\n autoFocus: boolean;\n /** V2 article-blocks.tsx:127-133: a fresh insert opens the panel, except Related posts, which focuses the card */\n openOnInsert?: boolean;\n toForm: (m: M) => Record<string, unknown>;\n fromForm: (v: Record<string, unknown>, prev: M) => M;\n children: (open: (field?: string | null) => void, ro: boolean) => React.ReactNode;\n}) {\n const card = React.useRef<HTMLDivElement | null>(null);\n const [cardEl, setCardEl] = React.useState<HTMLDivElement | null>(null);\n const ro = !!ctx.readOnly;\n const { open, editing, openPanel, close } = useArticleOpen({ ro, autoFocus: autoFocus && openOnInsert });\n // a stable ref: a new callback each render would pass null for a moment and remount the panel\n const cardRef = React.useCallback((n: HTMLDivElement | null) => {\n card.current = n;\n if (n) setCardEl(n);\n }, []);\n const focusCard = React.useCallback(() => requestAnimationFrame(() => card.current?.focus({ preventScroll: true })), []);\n React.useEffect(() => {\n if (autoFocus && !openOnInsert && !ro) focusCard();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n const modelRef = React.useRef(m);\n modelRef.current = m;\n\n /** a form edit joins the body's one undo history (D54); typing coalesces per field */\n const commit = (v: Record<string, unknown>) => {\n const prev = modelRef.current;\n const before = toForm(prev);\n const field = Object.keys(v).find((k) => JSON.stringify(v[k]) !== JSON.stringify(before[k])) ?? \"\";\n set(() => fromForm(v, prev), `Edit ${label.toLowerCase()} ${field}`);\n };\n\n return (\n <>\n <ArticleCard\n ref={cardRef}\n label={label}\n kind={kind}\n ro={ro}\n editing={editing}\n onOpen={openPanel}\n onKeyDown={articleCardKeyDown({ card, ctx, el, ro, editing, onOpen: openPanel, onClose: close, focusCard })}\n >\n {children(openPanel, ro)}\n <ArticleActions label={label} ctx={ctx} el={el} editing={editing} onEdit={() => (editing ? close() : openPanel())} tooltips />\n </ArticleCard>\n {editing ? (\n <ArticlePanel label={label} anchor={cardEl} nonce={open!.nonce} focusKey={open!.focusKey} onClose={close} focusBack={focusCard} ctx={ctx} el={el}>\n <ArticleForm schema={schema} label={label} value={toForm(m)} onChange={commit} ro={ro} />\n </ArticlePanel>\n ) : null}\n </>\n );\n}\n\n/**\n * A popover article block (V2 ArticleBlock surface \"popover\": TOC, Embed, Author bio): the shell's card + chip, its\n * settings in a popover from the card's top-right corner, one undo step per field edit.\n */\nexport function ArticlePopoverBlock<M extends object>({\n label, kind, schema, m, set, el, ctx, autoFocus, openOnInsert = true, toForm, fromForm, children,\n}: {\n label: string;\n kind: string;\n schema: TypeSchema;\n m: M;\n set: (fn: (m: M) => M, label?: string) => void;\n el: IslandEl;\n ctx: IslandCtx;\n autoFocus: boolean;\n /** V2 article-blocks.tsx:127-133: a fresh insert opens the form, except TOC and Related, which focus the card */\n openOnInsert?: boolean;\n toForm: (m: M) => Record<string, unknown>;\n fromForm: (v: Record<string, unknown>, prev: M) => M;\n /** the preview; `open(field)` opens the popover on that field (the empty state's action) */\n children: (open: (field?: string | null) => void, ro: boolean) => React.ReactNode;\n}) {\n const card = React.useRef<HTMLDivElement | null>(null);\n const form = React.useRef<HTMLDivElement | null>(null);\n const ro = !!ctx.readOnly;\n const { open, editing, openPanel: openPopover, close } = useArticleOpen({ ro, autoFocus: autoFocus && openOnInsert });\n const focusCard = React.useCallback(() => requestAnimationFrame(() => card.current?.focus({ preventScroll: true })), []);\n React.useEffect(() => {\n if (autoFocus && !openOnInsert && !ro) focusCard();\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n const modelRef = React.useRef(m);\n modelRef.current = m;\n const nonce = editing ? open!.nonce : 0;\n React.useEffect(() => {\n if (!nonce) return;\n const id = requestAnimationFrame(() => focusField(form.current, currentOpenArticle()?.focusKey ?? null));\n return () => cancelAnimationFrame(id);\n }, [nonce]);\n\n /** a form edit joins the body's one undo history (D54); typing coalesces per field */\n const commit = (v: Record<string, unknown>) => {\n const prev = modelRef.current;\n const before = toForm(prev);\n const field = Object.keys(v).find((k) => JSON.stringify(v[k]) !== JSON.stringify(before[k])) ?? \"\";\n set(() => fromForm(v, prev), `Edit ${label.toLowerCase()} ${field}`);\n };\n\n return (\n <Popover\n open={editing}\n onOpenChange={(o, d) => {\n if (o) return;\n close();\n // V2 onCloseAutoFocus: back on the block, unless the press that closed it went somewhere else\n if (d?.reason !== \"outside-press\") focusCard();\n }}\n >\n <ArticleCard\n ref={card}\n label={label}\n kind={kind}\n ro={ro}\n editing={editing}\n onOpen={openPopover}\n onKeyDown={articleCardKeyDown({ card, ctx, el, ro, editing, onOpen: openPopover, onClose: close, focusCard })}\n >\n {children(openPopover, ro)}\n <ArticleActions label={label} ctx={ctx} el={el} editing={editing} onEdit={() => (editing ? close() : openPopover())} tooltips />\n {/* the popover opens from the block's top-right corner, over the block, wherever the block sits */}\n <PopoverAnchor render={<span aria-hidden className=\"pointer-events-none absolute right-2 top-2 size-px\" />} />\n </ArticleCard>\n {editing ? (\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n // the anchor is a 1px dot at the card's top-right: no arrow inset, so the popup's edge sits on it (V2 AB:259-300)\n arrowPadding={0}\n className=\"w-[340px] p-0\"\n initialFocus={false}\n finalFocus={false}\n onKeyDown={(e) => {\n if ((e.metaKey || e.ctrlKey) && !e.altKey && eventKey(e) === \"z\" && !e.defaultPrevented) {\n e.preventDefault();\n if (e.shiftKey) ctx.redo?.();\n else ctx.undo?.();\n }\n }}\n >\n <div className=\"flex h-10 items-center gap-2 border-b border-kit-line-subtle pl-4 pr-1.5\">\n <span className=\"flex-1 truncate text-kit-sm font-medium text-kit-fg\">{label}</span>\n <IconButton size=\"sm\" label=\"Close\" onClick={() => (close(), focusCard())}>\n <IconX stroke={1.5} />\n </IconButton>\n </div>\n <div ref={form} className=\"max-h-[min(480px,70vh)] overflow-y-auto pb-2\">\n <ArticleForm schema={schema} label={label} value={toForm(m)} onChange={commit} ro={ro} />\n </div>\n </PopoverContent>\n ) : null}\n </Popover>\n );\n}\n"],"mappings":"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"}
|
|
@@ -345,7 +345,8 @@ function RelatedIsland({ m, set, el, ctx, autoFocus }) {
|
|
|
345
345
|
autoFocus,
|
|
346
346
|
collection: ctx.references?.posts ?? "",
|
|
347
347
|
excludeId: ctx.references?.entryId,
|
|
348
|
-
topic: ctx.references?.topic !== false
|
|
348
|
+
topic: ctx.references?.topic !== false,
|
|
349
|
+
noun: ctx.references?.postsNoun
|
|
349
350
|
});
|
|
350
351
|
}
|
|
351
352
|
var Sep = () => /* @__PURE__ */ jsx("span", {
|