@thebes/cadmea 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["createForm","CollectionConfig","FieldConfig","validateDocument","createEffect","createSignal","For","Index","JSX","lazy","onCleanup","Show","Suspense","CollectionCapabilities","FieldWidgetProps","FieldWidget","props","Element","FieldAccessor","state","value","meta","errors","handleChange","handleBlur","pushValue","insertValue","index","removeValue","moveValue","from","to","RichTextEditor","then","mod","default","editableFields","config","Object","entries","fields","filter","key","humanize","spaced","replace","trim","charAt","toUpperCase","slice","toLowerCase","labelFor","field","admin","label","FieldGroup","name","groupFields","groups","byName","Map","entry","group","get","set","push","RelationshipOption","id","DraftActions","onSaveDraft","values","Record","Promise","onPublish","onPreview","saving","publishing","previewing","canPublish","canPreview","saveDraftLabel","publishLabel","previewLabel","autosave","autosaveMs","CollectionEditProps","initialValues","onSubmit","submitLabel","error","onUploadFile","file","File","url","relationshipOptions","Partial","onDirtyChange","dirty","onValuesChange","fieldWidgets","draftActions","capabilities","RenderContext","CollectionEdit","operation","validateForm","violations","v","severity","path","message","keys","length","undefined","form","defaultValues","validators","onSubmitAsync","editablePayload","isDefaultValue","useStore","s","formValues","fromEntries","type","ctx","fieldGroups","versioned","versions","drafts","autosaveStatus","setAutosaveStatus","autosaveTimer","ReturnType","setTimeout","clearTimeout","_el$","_tmpl$7","_el$3","firstChild","addEventListener","event","preventDefault","handleSubmit","_$insert","_$createComponent","when","children","_el$2","_tmpl$","each","fallback","FieldsGrid","_el$1","_tmpl$8","_el$10","canUpdate","_el$11","_tmpl$4","$$click","_tmpl$2","_$effect","disabled","_el$4","_tmpl$3","_el$6","_el$8","_tmpl$5","_el$0","_tmpl$6","FormApi","_el$13","_tmpl$9","condition","renderField","renderArray","spanClass","width","Field","fieldApi","_el$14","_tmpl$11","_el$15","_$className","_$setAttribute","required","_tmpl$0","description","_el$17","_tmpl$1","renderControl","_el$18","_tmpl$10","Boolean","join","Widget","lastIndexOf","fieldKey","setValue","readOnly","change","_el$19","_tmpl$12","$$input","e","currentTarget","_p$","_v$","placeholder","_v$2","t","_el$20","_tmpl$13","options","option","_el$21","_tmpl$14","_el$22","_tmpl$15","valueAsNumber","_v$3","_v$4","_el$23","_tmpl$16","formatDateValue","_el$24","_tmpl$17","checked","UploadControl","RelationshipField","relationTo","content","onChange","doc","uploading","setUploading","uploadError","setUploadError","handleFileChange","Event","HTMLInputElement","files","err","Error","_el$26","_tmpl$20","_el$28","_el$27","_tmpl$18","_el$30","_tmpl$19","_v$5","_v$6","_v$7","a","query","setQuery","open","setOpen","active","setActive","listId","isMulti","hasMany","selectedIds","Array","isArray","selectedOptions","o","includes","filtered","q","singleLabel","choose","removeId","x","onKeyDown","KeyboardEvent","Math","min","max","ids","_el$31","_tmpl$24","_el$33","_$memo","_el$32","_tmpl$21","_el$36","_tmpl$25","_el$37","$$keydown","_el$34","_tmpl$22","$$mousedown","_el$35","_tmpl$23","i","_el$38","_tmpl$26","_v$11","_v$12","classList","toggle","_v$8","_v$9","_v$0","_v$1","_v$10","mode","BlockEditor","variantLabel","disc","NonNullable","variant","variantsAdmin","collapsed","setCollapsed","Set","menuOpen","setMenuOpen","discriminator","variants","items","addBlock","seed","duplicate","move","toggleCollapse","prev","next","has","delete","add","blockTitle","item","blockSummary","f","fieldsForItem","String","_el$39","_tmpl$29","_el$40","_el$43","nextSibling","_el$42","isCollapsed","_el$47","_tmpl$32","_el$48","_el$49","_el$50","_el$51","_el$53","_el$54","_el$55","_el$56","_el$57","_el$52","_tmpl$30","_el$58","_tmpl$31","itemKey","itemField","_v$13","_v$14","_el$59","_tmpl$33","_el$60","_el$44","_tmpl$28","_el$45","_el$46","_tmpl$27","_el$61","_tmpl$35","icon","_el$62","_tmpl$34","base","variantValue","variantFields","date","Date","Number","isNaN","getTime","toLocaleString","_$delegateEvents","ColumnDef","createSolidTable","flexRender","getCoreRowModel","CollectionConfig","FieldConfig","createSignal","For","Show","Row","Record","listableFields","config","excluded","Set","Object","entries","fields","filter","key","field","has","type","formatCellValue","value","undefined","Date","toLocaleDateString","String","rowId","row","id","CollectionListProps","rows","onRowClick","page","pageSize","totalCount","onPageChange","sortField","sortDirection","onSortChange","direction","selectable","selectedIds","ReadonlySet","onSelectionChange","CollectionList","props","columns","map","accessorFn","header","cell","info","getValue","table","data","selectMode","setSelectMode","toggleSelected","next","delete","add","handleRowActivate","_el$","_tmpl$6","_el$2","firstChild","_$insert","_$createComponent","when","children","_el$3","_tmpl$","$$click","v","_el$4","_tmpl$2","_el$5","_el$6","nextSibling","addEventListener","e","currentTarget","each","getAllColumns","column","_el$14","_tmpl$7","_$effect","length","fallback","_el$15","_tmpl$8","_el$16","_el$18","_el$17","slug","_el$7","_tmpl$3","_el$8","_el$9","getHeaderGroups","headerGroup","_el$19","_tmpl$0","_tmpl$9","headers","_el$21","columnDef","getContext","getRowModel","_el$22","original","_el$23","_tmpl$1","_el$24","stopPropagation","checked","getVisibleCells","_el$25","_tmpl$10","_$className","_el$0","_tmpl$4","_el$26","_tmpl$12","_el$27","_el$29","$$keydown","preventDefault","_el$28","_tmpl$11","_el$30","_tmpl$13","_el$31","_el$32","_$memo","_el$1","_tmpl$5","_el$10","_el$11","_el$12","_el$13","_p$","_v$","_v$2","disabled","t","_$delegateEvents","ImageCrop","ImageHotspot","createMemo","createSignal","Show","ImageWithHotspot","url","hotspot","crop","round2","n","Math","round","clamp01","min","max","parseImageHotspotValue","value","trimmed","trim","startsWith","JSON","parse","serializeImageHotspotValue","stringify","FieldWidgetProps","fieldKey","setValue","onUploadFile","file","File","Promise","ImageHotspotField","props","parsed","uploading","setUploading","error","setError","patch","next","Partial","current","handleFile","e","Event","currentTarget","HTMLInputElement","files","undefined","err","Error","message","handleImageClick","MouseEvent","HTMLImageElement","rect","getBoundingClientRect","x","clientX","left","width","y","clientY","top","height","right","bottom","setCrop","edge","raw","Number","_el$","_tmpl$3","_el$2","firstChild","addEventListener","_$insert","_$createComponent","when","children","_tmpl$","_el$4","_tmpl$2","_el$5","_tmpl$4","_el$6","_el$7","nextSibling","_el$8","_el$9","_el$0","_el$1","_el$10","$$click","hs","_el$11","_tmpl$5","_$effect","_p$","_v$3","_v$4","_$setStyleProperty","t","const","map","_el$12","_tmpl$6","_el$13","_el$14","$$input","_$setAttribute","_v$","_v$2","disabled","_$delegateEvents","createEffect","createSignal","For","JSX","onCleanup","Show","SearchPaletteResult","collection","id","label","SearchPaletteProps","onSearch","query","Promise","onSelect","result","DEBOUNCE_MS","capitalize","value","length","toUpperCase","slice","SearchPalette","props","Element","open","setOpen","setQuery","results","setResults","activeIndex","setActiveIndex","inputRef","HTMLInputElement","triggeredBy","HTMLElement","debounceTimer","ReturnType","setTimeout","latestQueryToken","close","focus","runSearch","token","trim","then","found","onInput","clearTimeout","selectResult","onGlobalKeyDown","event","KeyboardEvent","metaKey","ctrlKey","key","toLowerCase","preventDefault","document","activeElement","addEventListener","removeEventListener","onDialogKeyDown","i","Math","min","max","_$createComponent","when","children","_el$","_tmpl$2","_el$2","firstChild","_el$3","_el$4","_el$5","nextSibling","$$click","$$keydown","stopPropagation","$$input","currentTarget","_ref$","_$use","_$insert","fallback","_el$7","_tmpl$3","_el$6","_tmpl$","each","index","_el$8","_tmpl$4","_el$9","_el$0","_el$1","_$effect","classList","toggle","_$delegateEvents","EditRef","PREVIEW_VALUES_MESSAGE","PreviewValuesMessage","VISUAL_EDIT_MESSAGE","VisualEditingMessage","createEffect","onCleanup","onMount","VisualEditingPaneProps","src","onEdit","ref","allowedOrigin","class","title","previewValues","Record","previewTarget","collection","id","originOf","url","URL","origin","undefined","VisualEditingPane","props","iframe","HTMLIFrameElement","targetOrigin","expected","handler","event","MessageEvent","data","Partial","type","window","addEventListener","removeEventListener","values","target","win","contentWindow","message","postMessage","_el$","_tmpl$","_$use","el","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","a","_$className"],"sources":["../../src/CollectionEdit.tsx","../../src/CollectionList.tsx","../../src/ImageHotspotField.tsx","../../src/SearchPalette.tsx","../../src/VisualEditingPane.tsx"],"sourcesContent":["import { createForm } from \"@tanstack/solid-form\";\nimport type { CollectionConfig, FieldConfig } from \"@thebes/cadmus/cms\";\nimport { validateDocument } from \"@thebes/cadmus/cms\";\nimport {\n createEffect,\n createSignal,\n For,\n Index,\n type JSX,\n lazy,\n onCleanup,\n Show,\n Suspense,\n} from \"solid-js\";\nimport type { CollectionCapabilities } from \"./capabilities.js\";\nimport type { FieldWidgetProps } from \"./ImageHotspotField.js\";\n\n/** A custom per-field editor, registered via `fieldWidgets`. */\nexport type FieldWidget = (props: FieldWidgetProps) => JSX.Element;\n\n// TanStack Form's per-field render prop hands back an accessor to the\n// FieldApi. Its generics are heavy and not worth threading through this\n// schema-driven renderer (every field is `unknown`-typed anyway), so the\n// helpers below take the accessor loosely-typed.\ntype FieldAccessor = () => {\n state: { value: unknown; meta: { errors: unknown[] } };\n handleChange: (value: unknown) => void;\n handleBlur: () => void;\n pushValue: (value: unknown) => void;\n insertValue: (index: number, value: unknown) => void;\n removeValue: (index: number) => void;\n moveValue: (from: number, to: number) => void;\n};\n\n// Dynamic import, not a static one — @tiptap/core + @tiptap/starter-kit\n// are a large dependency (pushed a consuming route's bundle from ~9KB to\n// ~800KB when statically imported, even for collections with zero\n// richText fields). Lazy-loading means only forms that actually render a\n// richText field pull this chunk in at runtime.\nconst RichTextEditor = lazy(() =>\n import(\"./RichTextEditor.js\").then((mod) => ({\n default: mod.RichTextEditor,\n })),\n);\n\n// Fields the generic form can actually render today. `id` is never\n// user-editable. `date` fields (e.g. createdAt) are server-defaulted and\n// shown read-only rather than editable in this step.\nfunction editableFields(config: CollectionConfig): [string, FieldConfig][] {\n return Object.entries(config.fields).filter(([key]) => key !== \"id\");\n}\n\n// Default label for a field with no `admin.label`: split camelCase and\n// snake/kebab into words, sentence-case the result. `metaDescription` →\n// \"Meta description\", `created_at` → \"Created at\".\nfunction humanize(key: string): string {\n const spaced = key\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\nfunction labelFor(key: string, field: FieldConfig): string {\n return field.admin?.label ?? humanize(key);\n}\n\ninterface FieldGroup {\n /** `undefined` for fields with no `admin.group` — rendered ungrouped. */\n name?: string;\n fields: [string, FieldConfig][];\n}\n\n// Partition fields into `admin.group` buckets, preserving the order each\n// group is first seen. Ungrouped fields keep their own (name: undefined)\n// bucket so they interleave correctly with grouped ones.\nfunction groupFields(entries: [string, FieldConfig][]): FieldGroup[] {\n const groups: FieldGroup[] = [];\n const byName = new Map<string | undefined, FieldGroup>();\n for (const entry of entries) {\n const name = entry[1].admin?.group;\n let group = byName.get(name);\n if (!group) {\n group = { name, fields: [] };\n byName.set(name, group);\n groups.push(group);\n }\n group.fields.push(entry);\n }\n return groups;\n}\n\nexport interface RelationshipOption {\n id: number;\n label: string;\n}\n\n/**\n * Replaces the generic \"Save\" button with \"Save draft\"/\"Publish\" when the\n * collection has `versions: { drafts: true }` — a separate privilege from\n * a plain update, matching `access.publish` in `@thebes/cadmus/cms`.\n * `onPublish` takes no values: publishing acts on whatever was last saved\n * as a draft (the consuming route tracks which version that is), not on\n * the live form state.\n */\nexport interface DraftActions {\n onSaveDraft: (values: Record<string, unknown>) => void | Promise<void>;\n onPublish?: () => void | Promise<void>;\n /**\n * Opens a live preview of the last saved draft (issue #28) — like\n * `onPublish`, acts on whatever was last saved as a draft, not the live\n * form state. Omit to not render the Preview button at all.\n */\n onPreview?: () => void | Promise<void>;\n saving?: boolean;\n publishing?: boolean;\n previewing?: boolean;\n /** Disables Publish — e.g. until a draft has been saved at least once. */\n canPublish?: boolean;\n /** Disables Preview — same gating as canPublish, a draft must exist first. */\n canPreview?: boolean;\n saveDraftLabel?: string;\n publishLabel?: string;\n previewLabel?: string;\n /**\n * Opt in to debounced autosave: while the form is dirty, `onSaveDraft` is\n * called automatically after a pause in typing, and a \"Saving…/Saved\"\n * status shows in the action bar. Off by default (existing consumers keep\n * the manual Save-draft button only).\n */\n autosave?: boolean;\n /** Debounce window for autosave, in ms. Default 1500. */\n autosaveMs?: number;\n}\n\nexport interface CollectionEditProps {\n config: CollectionConfig;\n initialValues?: Record<string, unknown>;\n onSubmit: (values: Record<string, unknown>) => void | Promise<void>;\n submitLabel?: string;\n error?: string;\n /** Disables the Save button and shows a spinner in its place. */\n saving?: boolean;\n /**\n * Resolves an `upload` field's selected file to a stored URL. Required\n * if the collection has any `upload` fields — `CollectionEdit` never\n * talks to storage directly (stays agnostic of R2/cadmus/storage), so\n * the consuming route wires this to a server function that calls an\n * `ImageService`'s `upload()`.\n */\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n /**\n * Options for `relationship` fields (both single and `hasMany`), keyed by\n * the field's `relationTo` collection slug. `CollectionEdit` can't query\n * another collection itself, so the consuming route fetches the related\n * rows and passes them in; the field renders them as a searchable combobox.\n */\n relationshipOptions?: Partial<Record<string, RelationshipOption[]>>;\n /**\n * Fired whenever the dirty (unsaved-changes) state changes — wire this\n * to a router-level navigation guard (e.g. `useBlocker` in the\n * consuming route) since `CollectionEdit` has no router access itself.\n */\n onDirtyChange?: (dirty: boolean) => void;\n /**\n * Fired with the current editable values on every change — wire this to a\n * side-by-side live preview (e.g. `VisualEditingPane`'s `previewValues`).\n * Fires on mount with the initial values too.\n */\n onValuesChange?: (values: Record<string, unknown>) => void;\n /**\n * Per-field custom editor widgets (issue #17), keyed by field name. When a\n * field has a widget here, it's rendered instead of the generic input for\n * that field's type — e.g. `{ heroImage: ImageHotspotField }`. The widget\n * receives the field value, a setter, and `onUploadFile`.\n */\n fieldWidgets?: Record<string, FieldWidget>;\n /** Only rendered when `config.versions?.drafts` is also true. */\n draftActions?: DraftActions;\n /**\n * Hides the Save button when `canUpdate` is `false` — see issue #26's\n * RBAC-aware admin UI. Undefined (the default — most collections don't\n * wire this up) reads as \"allowed\", same as `@thebes/cadmus/cms`'s own\n * \"no access fn = allowed\" default.\n */\n capabilities?: CollectionCapabilities;\n}\n\ninterface RenderContext {\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n relationshipOptions?: Partial<Record<string, RelationshipOption[]>>;\n fieldWidgets?: Record<string, FieldWidget>;\n}\n\nexport function CollectionEdit(props: CollectionEditProps) {\n // TanStack Form owns form state now (was a hand-rolled createSignal +\n // manual JSON.stringify dirty tracking). defaultValues is exactly the\n // passed-in initialValues — NOT seeded with each field's `defaultValue`,\n // so a never-touched optional field stays absent from the submitted\n // payload, matching the prior behavior the tests pin.\n const operation: \"create\" | \"update\" =\n props.initialValues?.id != null ? \"update\" : \"create\";\n\n // Field validation (issue #16's ValidationBuilder) runs client-side as a\n // TanStack Form *form-level* validator — validateDocument with no `db`\n // skips the DB-backed unique/reference checks and evaluates the rest.\n // Returning `{ fields }` (TanStack's global-error shape) distributes each\n // message to the matching field's meta.errors and blocks the submit;\n // letting TanStack own the validate→submit lifecycle (rather than\n // early-returning from the submit action) keeps isSubmitting/canSubmit\n // correct across repeated submits. The server re-validates authoritatively.\n async function validateForm(value: Record<string, unknown>) {\n const violations = await validateDocument(props.config, value, {\n operation,\n });\n const fields: Record<string, string> = {};\n for (const v of violations) {\n if (v.severity === \"error\" && !(v.path in fields)) {\n fields[v.path] = v.message;\n }\n }\n return Object.keys(fields).length > 0 ? { fields } : undefined;\n }\n\n const form = createForm(() => ({\n defaultValues: props.initialValues ?? {},\n validators: {\n onSubmitAsync: ({ value }: { value: Record<string, unknown> }) =>\n validateForm(value),\n },\n onSubmit: async ({ value }: { value: Record<string, unknown> }) => {\n await props.onSubmit(editablePayload(value));\n },\n }));\n\n // Dirty = \"differs from initial values\", reported up for the consuming\n // route's navigation guard. TanStack's `isDirty` is sticky (stays true\n // once a field is touched, even if reverted), so we use the form's\n // `isDefaultValue` aggregate instead — it flips back to true the moment\n // every field equals its default again, preserving the prior revert-to-\n // clean behavior.\n const isDefaultValue = form.useStore((s) => s.isDefaultValue);\n createEffect(() => props.onDirtyChange?.(!isDefaultValue()));\n\n // Current values for the imperative draft action + conditional fields.\n const formValues = form.useStore((s) => s.values as Record<string, unknown>);\n\n // Emit editable values on every change for side-by-side live preview.\n createEffect(() => props.onValuesChange?.(editablePayload(formValues())));\n\n // date fields are read-only — never include them in a submitted/draft payload\n function editablePayload(\n value: Record<string, unknown>,\n ): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).filter(\n ([key]) => props.config.fields[key]?.type !== \"date\",\n ),\n );\n }\n\n const ctx: RenderContext = {\n get onUploadFile() {\n return props.onUploadFile;\n },\n get relationshipOptions() {\n return props.relationshipOptions;\n },\n get fieldWidgets() {\n return props.fieldWidgets;\n },\n };\n\n const fieldGroups = groupFields(editableFields(props.config));\n const versioned = () => props.config.versions?.drafts && props.draftActions;\n\n // Debounced autosave (opt-in via draftActions.autosave). While the form is\n // dirty, persist the draft after a pause in typing and surface a status so\n // the client never wonders whether their work is saved. Manual Save\n // draft/Publish still work alongside it.\n const [autosaveStatus, setAutosaveStatus] = createSignal<\n \"idle\" | \"saving\" | \"saved\"\n >(\"idle\");\n let autosaveTimer: ReturnType<typeof setTimeout> | undefined;\n createEffect(() => {\n const dirty = !isDefaultValue();\n const values = formValues();\n if (!versioned() || !props.draftActions?.autosave) return;\n if (!dirty) {\n setAutosaveStatus(\"idle\");\n return;\n }\n clearTimeout(autosaveTimer);\n autosaveTimer = setTimeout(async () => {\n setAutosaveStatus(\"saving\");\n try {\n await props.draftActions?.onSaveDraft(editablePayload(values));\n setAutosaveStatus(\"saved\");\n } catch {\n // Surface nothing special on failure — the manual Save draft button\n // (and its error handling) remains the explicit path.\n setAutosaveStatus(\"idle\");\n }\n }, props.draftActions?.autosaveMs ?? 1500);\n });\n onCleanup(() => clearTimeout(autosaveTimer));\n\n return (\n <form\n class=\"flex flex-col gap-4\"\n onSubmit={(event) => {\n event.preventDefault();\n void form.handleSubmit();\n }}\n >\n <Show when={props.error}>\n {/* role=\"alert\" so assistive tech announces submit failures the\n moment they appear, not only if the user happens to navigate to\n them. */}\n <p class=\"text-sm text-error\" role=\"alert\">\n {props.error}\n </p>\n </Show>\n <For each={fieldGroups}>\n {(group) => (\n <Show\n when={group.name}\n fallback={\n <FieldsGrid\n form={form}\n ctx={ctx}\n fields={group.fields}\n values={formValues}\n />\n }\n >\n <fieldset class=\"border-base-300 rounded-box border p-4\">\n <legend class=\"px-2 text-sm font-semibold\">{group.name}</legend>\n <FieldsGrid\n form={form}\n ctx={ctx}\n fields={group.fields}\n values={formValues}\n />\n </fieldset>\n </Show>\n )}\n </For>\n {/* Bottom-anchored, full-width action bar — not a top toolbar, per\n issue #25's mobile-first note. */}\n <div class=\"bg-base-100 sticky bottom-0 flex gap-2 border-t py-3\">\n <Show\n when={versioned()}\n fallback={\n <Show when={props.capabilities?.canUpdate !== false}>\n {/* type=\"button\" + handleSubmit (not a native submit) so\n TanStack Form owns validation — a native `required` field\n left empty no longer silently blocks the submit event, and\n inline validation becomes the single authority. The\n <form onSubmit> above still handles Enter. */}\n <button\n type=\"button\"\n class=\"btn btn-primary flex-1\"\n disabled={props.saving}\n onClick={() => void form.handleSubmit()}\n >\n <Show\n when={props.saving}\n fallback={props.submitLabel ?? \"Save\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n </Show>\n }\n >\n <button\n type=\"button\"\n class=\"btn flex-1\"\n disabled={props.draftActions?.saving}\n onClick={() =>\n void props.draftActions?.onSaveDraft(\n editablePayload(formValues()),\n )\n }\n >\n <Show\n when={props.draftActions?.saving}\n fallback={props.draftActions?.saveDraftLabel ?? \"Save draft\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-primary flex-1\"\n disabled={\n !props.draftActions?.canPublish || props.draftActions?.publishing\n }\n onClick={() => void props.draftActions?.onPublish?.()}\n >\n <Show\n when={props.draftActions?.publishing}\n fallback={props.draftActions?.publishLabel ?? \"Publish\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n <Show when={props.draftActions?.onPreview}>\n <button\n type=\"button\"\n class=\"btn btn-outline flex-1\"\n disabled={\n !props.draftActions?.canPreview ||\n props.draftActions?.previewing\n }\n onClick={() => void props.draftActions?.onPreview?.()}\n >\n <Show\n when={props.draftActions?.previewing}\n fallback={props.draftActions?.previewLabel ?? \"Preview\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n </Show>\n <Show when={props.draftActions?.autosave}>\n {/* aria-live so assistive tech announces autosave transitions. */}\n <span\n class=\"text-base-content/60 self-center px-1 text-xs\"\n aria-live=\"polite\"\n >\n <Show when={autosaveStatus() === \"saving\"}>Saving…</Show>\n <Show when={autosaveStatus() === \"saved\"}>Saved</Show>\n </span>\n </Show>\n </Show>\n </div>\n </form>\n );\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: TanStack Form's instance generics are not worth threading through a schema-driven renderer.\ntype FormApi = any;\n\n// One responsive grid of fields. Half-width fields sit two-up on >= md;\n// everything is single-column on mobile (issue #25's mobile-first note).\n// Conditional fields (`admin.condition`) are wrapped per-field in <Show> so\n// toggling one doesn't re-render (and steal focus from) its siblings.\nfunction FieldsGrid(props: {\n form: FormApi;\n ctx: RenderContext;\n fields: [string, FieldConfig][];\n values: () => Record<string, unknown>;\n}): JSX.Element {\n return (\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <For each={props.fields}>\n {([key, field]) => (\n <Show\n when={\n !field.admin?.condition || field.admin.condition(props.values())\n }\n >\n {renderField(\n props.form,\n props.ctx,\n key,\n field,\n labelFor(key, field),\n )}\n </Show>\n )}\n </For>\n </div>\n );\n}\n\nfunction renderField(\n form: FormApi,\n ctx: RenderContext,\n name: string,\n field: FieldConfig,\n label: string,\n): JSX.Element {\n if (field.type === \"array\") return renderArray(form, ctx, name, field, label);\n\n // Half-width fields span one grid column on >= md; everything else spans\n // the full two-column width.\n const spanClass =\n field.admin?.width === \"half\" ? \"md:col-span-1\" : \"md:col-span-2\";\n\n return (\n <form.Field name={name}>\n {(fieldApi: FieldAccessor) => (\n <div class={`form-control ${spanClass}`}>\n {/* The \" *\" stays inside the label's accessible name (it reads as\n \"required\" alongside each input's `required` attribute); the\n span only colors it, it does not change the text. */}\n <label class=\"label\" for={name}>\n {label}\n <Show when={field.required}>\n <span class=\"text-error\">{\" *\"}</span>\n </Show>\n </label>\n <Show when={field.admin?.description}>\n <p class=\"text-base-content/60 mb-1 text-xs\">\n {field.admin?.description}\n </p>\n </Show>\n {renderControl(ctx, name, field, fieldApi)}\n {/* Inline validation messages from the form-level validator\n (distributed to this field's meta by TanStack). */}\n <Show when={(fieldApi().state.meta.errors?.length ?? 0) > 0}>\n <p class=\"text-error mt-1 text-sm\" role=\"alert\">\n {fieldApi().state.meta.errors.filter(Boolean).join(\", \")}\n </p>\n </Show>\n </div>\n )}\n </form.Field>\n );\n}\n\nfunction renderControl(\n ctx: RenderContext,\n name: string,\n field: FieldConfig,\n fieldApi: FieldAccessor,\n): JSX.Element {\n // A registered custom widget wins over the generic type-based input (#17).\n // Match by the full key, or by the trailing field name so a widget can\n // target a field nested inside an `array` item (whose name is a path like\n // `blocks[0].url`) without knowing the index.\n const Widget =\n ctx.fieldWidgets?.[name] ??\n ctx.fieldWidgets?.[name.slice(name.lastIndexOf(\".\") + 1)];\n if (Widget) {\n return (\n <Widget\n fieldKey={name}\n value={fieldApi().state.value}\n setValue={(v) => fieldApi().handleChange(v)}\n onUploadFile={ctx.onUploadFile}\n />\n );\n }\n\n const readOnly = field.admin?.readOnly;\n const change = (v: unknown) => fieldApi().handleChange(v);\n\n switch (field.type) {\n case \"text\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"text\"\n placeholder={field.admin?.placeholder}\n readOnly={readOnly}\n value={(fieldApi().state.value as string) ?? \"\"}\n required={field.required}\n onInput={(e) => change(e.currentTarget.value)}\n onBlur={() => fieldApi().handleBlur()}\n />\n );\n case \"select\":\n return (\n <select\n id={name}\n class=\"select\"\n value={(fieldApi().state.value as string) ?? \"\"}\n required={field.required}\n disabled={readOnly}\n onChange={(e) => change(e.currentTarget.value)}\n onBlur={() => fieldApi().handleBlur()}\n >\n <For each={field.options}>\n {(option) => <option value={option}>{option}</option>}\n </For>\n </select>\n );\n case \"number\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"number\"\n placeholder={field.admin?.placeholder}\n readOnly={readOnly}\n value={(fieldApi().state.value as number) ?? \"\"}\n required={field.required}\n onInput={(e) => change(e.currentTarget.valueAsNumber)}\n onBlur={() => fieldApi().handleBlur()}\n />\n );\n case \"date\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"text\"\n readOnly\n value={formatDateValue(fieldApi().state.value)}\n />\n );\n case \"checkbox\":\n return (\n <input\n id={name}\n class=\"checkbox\"\n type=\"checkbox\"\n disabled={readOnly}\n checked={(fieldApi().state.value as boolean) ?? false}\n onChange={(e) => change(e.currentTarget.checked)}\n />\n );\n case \"upload\":\n return (\n <UploadControl\n name={name}\n field={field}\n fieldApi={fieldApi}\n ctx={ctx}\n />\n );\n case \"relationship\":\n return (\n <RelationshipField\n name={name}\n field={field}\n fieldApi={fieldApi}\n options={ctx.relationshipOptions?.[field.relationTo] ?? []}\n />\n );\n case \"richText\":\n return (\n <Suspense\n fallback={<span class=\"loading loading-spinner loading-sm\" />}\n >\n <RichTextEditor\n id={name}\n content={fieldApi().state.value as object | undefined}\n onChange={(doc) => change(doc)}\n onUploadFile={ctx.onUploadFile}\n />\n </Suspense>\n );\n default:\n return null;\n }\n}\n\nfunction UploadControl(props: {\n name: string;\n field: FieldConfig & { type: \"upload\" };\n fieldApi: FieldAccessor;\n ctx: RenderContext;\n}) {\n const [uploading, setUploading] = createSignal(false);\n const [uploadError, setUploadError] = createSignal<string>();\n const value = () => props.fieldApi().state.value as string | undefined;\n\n async function handleFileChange(\n e: Event & { currentTarget: HTMLInputElement },\n ) {\n const file = e.currentTarget.files?.[0];\n if (!file) return;\n if (!props.ctx.onUploadFile) {\n setUploadError(\"No upload handler configured for this form.\");\n return;\n }\n setUploading(true);\n setUploadError(undefined);\n try {\n const { url } = await props.ctx.onUploadFile(file);\n props.fieldApi().handleChange(url);\n } catch (err) {\n setUploadError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }\n\n return (\n <div class=\"flex flex-col gap-2\">\n <Show when={value()}>\n <p class=\"text-sm opacity-70 break-all\">{value()}</p>\n </Show>\n <input\n id={props.name}\n class=\"file-input\"\n type=\"file\"\n required={props.field.required && !value()}\n disabled={uploading() || props.field.admin?.readOnly}\n onChange={handleFileChange}\n />\n <Show when={uploading()}>\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n <Show when={uploadError()}>\n <p class=\"text-sm text-error\">{uploadError()}</p>\n </Show>\n </div>\n );\n}\n\n// Searchable relationship picker — a filter-as-you-type combobox (replacing\n// the old plain <select>) that supports both single (hasMany:false → value is\n// a number|null) and multi (hasMany:true → value is number[], rendered as\n// removable chips). Options for `relationTo` are supplied by the consuming\n// route via `relationshipOptions`; this component never queries the DB itself.\nfunction RelationshipField(props: {\n name: string;\n field: FieldConfig & { type: \"relationship\" };\n fieldApi: FieldAccessor;\n options: RelationshipOption[];\n}): JSX.Element {\n const [query, setQuery] = createSignal(\"\");\n const [open, setOpen] = createSignal(false);\n const [active, setActive] = createSignal(0);\n const listId = `${props.name}-listbox`;\n\n const isMulti = () => props.field.hasMany === true;\n const value = () => props.fieldApi().state.value;\n const selectedIds = (): number[] => {\n const v = value();\n if (isMulti()) return Array.isArray(v) ? (v as number[]) : [];\n return v != null ? [v as number] : [];\n };\n const selectedOptions = () =>\n props.options.filter((o) => selectedIds().includes(o.id));\n const filtered = () => {\n const q = query().toLowerCase();\n return props.options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) &&\n (!isMulti() || !selectedIds().includes(o.id)),\n );\n };\n const singleLabel = () => selectedOptions()[0]?.label ?? \"\";\n\n function choose(option: RelationshipOption) {\n if (isMulti()) {\n props.fieldApi().handleChange([...selectedIds(), option.id]);\n setQuery(\"\");\n } else {\n props.fieldApi().handleChange(option.id);\n setQuery(\"\");\n setOpen(false);\n }\n setActive(0);\n }\n function removeId(id: number) {\n if (isMulti()) {\n props.fieldApi().handleChange(selectedIds().filter((x) => x !== id));\n } else {\n props.fieldApi().handleChange(null);\n }\n }\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n setActive((a) => Math.min(a + 1, filtered().length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(a - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const option = filtered()[active()];\n if (option) choose(option);\n } else if (e.key === \"Escape\") {\n setOpen(false);\n } else if (e.key === \"Backspace\" && isMulti() && query() === \"\") {\n const ids = selectedIds();\n if (ids.length > 0) removeId(ids[ids.length - 1]);\n }\n }\n\n return (\n <div class=\"relative\">\n <Show when={isMulti() && selectedOptions().length > 0}>\n <div class=\"mb-1 flex flex-wrap gap-1\">\n <For each={selectedOptions()}>\n {(option) => (\n <span class=\"badge badge-primary gap-1\">\n {option.label}\n <button\n type=\"button\"\n aria-label={`Remove ${option.label}`}\n class=\"cursor-pointer\"\n onClick={() => removeId(option.id)}\n >\n ×\n </button>\n </span>\n )}\n </For>\n </div>\n </Show>\n <input\n id={props.name}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open()}\n aria-controls={listId}\n autocomplete=\"off\"\n class=\"input\"\n required={props.field.required && selectedIds().length === 0}\n disabled={props.field.admin?.readOnly}\n placeholder={props.field.admin?.placeholder ?? \"Search…\"}\n value={open() || isMulti() ? query() : singleLabel()}\n onInput={(e) => {\n setQuery(e.currentTarget.value);\n setOpen(true);\n setActive(0);\n }}\n onFocus={() => setOpen(true)}\n // Delay so a click on an option registers before the list unmounts.\n onBlur={() => setTimeout(() => setOpen(false), 120)}\n onKeyDown={onKeyDown}\n />\n <Show when={!isMulti() && value() != null && !props.field.required}>\n <button\n type=\"button\"\n aria-label=\"Clear\"\n class=\"absolute top-2 right-2 cursor-pointer opacity-60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => removeId(value() as number)}\n >\n ×\n </button>\n </Show>\n <Show when={open() && filtered().length > 0}>\n {/* role=\"listbox\"/\"option\" live on a div + button (not ul/li) so the\n options are natively focusable interactive elements. */}\n <div\n id={listId}\n role=\"listbox\"\n class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex max-h-56 w-full flex-col overflow-auto border p-1 shadow\"\n >\n <For each={filtered()}>\n {(option, i) => (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={selectedIds().includes(option.id)}\n class=\"rounded px-3 py-2 text-left\"\n classList={{ \"bg-base-200\": i() === active() }}\n // preventDefault keeps focus on the input so onClick fires\n // before the input's blur closes the list.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => choose(option)}\n >\n {option.label}\n </button>\n )}\n </For>\n </div>\n </Show>\n </div>\n );\n}\n\nfunction renderArray(\n form: FormApi,\n ctx: RenderContext,\n name: string,\n field: FieldConfig & { type: \"array\" },\n label: string,\n): JSX.Element {\n return (\n <form.Field name={name} mode=\"array\">\n {(fieldApi: FieldAccessor) => (\n <BlockEditor\n form={form}\n ctx={ctx}\n name={name}\n field={field}\n label={label}\n fieldApi={fieldApi}\n />\n )}\n </form.Field>\n );\n}\n\nfunction variantLabel(\n disc: NonNullable<(FieldConfig & { type: \"array\" })[\"discriminator\"]>,\n variant: string,\n): string {\n return disc.variantsAdmin?.[variant]?.label ?? humanize(variant);\n}\n\n// Visual block builder (Workstream B) — turns a discriminated `array` field\n// into a page-builder: a friendly \"Add block\" picker (one entry per variant,\n// with optional icon), per-block reorder/duplicate/remove, and collapse to a\n// one-line summary so a stack of blocks reads like a page outline. A plain\n// (non-discriminated) array keeps a single \"Add\" button.\nfunction BlockEditor(props: {\n form: FormApi;\n ctx: RenderContext;\n name: string;\n field: FieldConfig & { type: \"array\" };\n label: string;\n fieldApi: FieldAccessor;\n}): JSX.Element {\n const [collapsed, setCollapsed] = createSignal<Set<number>>(new Set());\n const [menuOpen, setMenuOpen] = createSignal(false);\n\n const disc = props.field.discriminator;\n const variants = disc ? Object.keys(disc.variants) : [];\n const items = () =>\n Array.isArray(props.fieldApi().state.value)\n ? (props.fieldApi().state.value as Record<string, unknown>[])\n : [];\n\n function addBlock(variant?: string) {\n const seed = variant && disc ? { [disc.key]: variant } : {};\n props.fieldApi().pushValue(seed);\n setMenuOpen(false);\n }\n function duplicate(index: number) {\n props.fieldApi().insertValue(index + 1, { ...items()[index] });\n }\n function move(from: number, to: number) {\n if (to < 0 || to >= items().length) return;\n props.fieldApi().moveValue(from, to);\n }\n function toggleCollapse(index: number) {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n }\n\n function blockTitle(item: Record<string, unknown>): string {\n if (disc) {\n const v = item[disc.key];\n if (typeof v === \"string\") return variantLabel(disc, v);\n }\n return props.label;\n }\n // A one-line preview for a collapsed block — the first non-discriminator\n // text/select value, so the outline reads meaningfully.\n function blockSummary(item: Record<string, unknown>): string {\n for (const [key, f] of fieldsForItem(props.field, item)) {\n if (key === disc?.key) continue;\n if ((f.type === \"text\" || f.type === \"select\") && item[key]) {\n return String(item[key]);\n }\n }\n return \"\";\n }\n\n return (\n <div class=\"form-control md:col-span-2\">\n {/* A group heading for the block list, not a single-input label. */}\n <div class=\"label font-medium\">\n {props.label}\n <Show when={props.field.required}>\n <span class=\"text-error\">{\" *\"}</span>\n </Show>\n </div>\n <Show when={props.field.admin?.description}>\n <p class=\"text-base-content/60 mb-1 text-xs\">\n {props.field.admin?.description}\n </p>\n </Show>\n <div class=\"flex flex-col gap-3\">\n {/* <Index> (not <For>) keys rows by position so a keystroke in one\n item's input — which replaces the array reference via TanStack's\n immutable update — doesn't unmount/remount the whole row and steal\n focus. Item names are position-based (`blocks[0].title`). */}\n <Index each={items()}>\n {(item, index) => {\n const isCollapsed = () => collapsed().has(index);\n return (\n <div class=\"card bg-base-200 flex flex-col gap-2 p-3\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-sm gap-2\"\n aria-expanded={!isCollapsed()}\n onClick={() => toggleCollapse(index)}\n >\n <span aria-hidden=\"true\">{isCollapsed() ? \"▸\" : \"▾\"}</span>\n <span class=\"font-semibold\">{blockTitle(item())}</span>\n </button>\n <Show when={isCollapsed() && blockSummary(item())}>\n <span class=\"text-base-content/60 truncate text-sm\">\n {blockSummary(item())}\n </span>\n </Show>\n <div class=\"ml-auto flex gap-1\">\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Move up\"\n disabled={index === 0}\n onClick={() => move(index, index - 1)}\n >\n ↑\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Move down\"\n disabled={index === items().length - 1}\n onClick={() => move(index, index + 1)}\n >\n ↓\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Duplicate\"\n onClick={() => duplicate(index)}\n >\n ⧉\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs text-error\"\n aria-label=\"Remove\"\n onClick={() => props.fieldApi().removeValue(index)}\n >\n Remove\n </button>\n </div>\n </div>\n <Show when={!isCollapsed()}>\n <div class=\"flex flex-col gap-2\">\n <For each={fieldsForItem(props.field, item())}>\n {([itemKey, itemField]) =>\n renderField(\n props.form,\n props.ctx,\n `${props.name}[${index}].${itemKey}`,\n itemField,\n labelFor(itemKey, itemField),\n )\n }\n </For>\n </div>\n </Show>\n </div>\n );\n }}\n </Index>\n\n {/* Discriminated arrays get a block-type picker; plain arrays keep a\n single Add button. */}\n <Show\n when={disc && variants.length > 0}\n fallback={\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm self-start\"\n onClick={() => addBlock()}\n >\n Add {props.label}\n </button>\n }\n >\n <div class=\"relative self-start\">\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen()}\n onClick={() => setMenuOpen((o) => !o)}\n >\n Add block\n </button>\n <Show when={menuOpen()}>\n {/* role=\"menu\"/\"menuitem\" on div + button (not ul/li) so the\n menu items are natively focusable interactive elements. */}\n <div\n role=\"menu\"\n class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex flex-col border p-1 shadow\"\n >\n <For each={variants}>\n {(variant) => (\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"flex items-center gap-2 rounded px-3 py-2 text-left\"\n onClick={() => addBlock(variant)}\n >\n <Show when={disc?.variantsAdmin?.[variant]?.icon}>\n <i\n class={disc?.variantsAdmin?.[variant]?.icon}\n aria-hidden=\"true\"\n />\n </Show>\n {variantLabel(disc as NonNullable<typeof disc>, variant)}\n </button>\n )}\n </For>\n </div>\n </Show>\n </div>\n </Show>\n </div>\n </div>\n );\n}\n\nfunction fieldsForItem(\n field: FieldConfig & { type: \"array\" },\n item: Record<string, unknown>,\n): [string, FieldConfig][] {\n const base = Object.entries(field.fields);\n const discriminator = field.discriminator;\n if (!discriminator) return base;\n\n const variantValue = item[discriminator.key];\n const variantFields =\n typeof variantValue === \"string\"\n ? discriminator.variants[variantValue]\n : undefined;\n return variantFields ? [...base, ...Object.entries(variantFields)] : base;\n}\n\nfunction formatDateValue(value: unknown): string {\n if (!value) return \"—\";\n const date = value instanceof Date ? value : new Date(value as string);\n return Number.isNaN(date.getTime()) ? \"—\" : date.toLocaleString();\n}\n","import {\n type ColumnDef,\n createSolidTable,\n flexRender,\n getCoreRowModel,\n} from \"@tanstack/solid-table\";\nimport type { CollectionConfig, FieldConfig } from \"@thebes/cadmus/cms\";\nimport { createSignal, For, Show } from \"solid-js\";\n\ntype Row = Record<string, unknown>;\n\n// Field types that can be rendered as a plain table cell today.\n// `id` is intentionally excluded — it's never a useful list column.\n// `richText`/`array` are structured content, not a sensible table cell;\n// `relationship` has no resolved label available here (CollectionList\n// only receives raw row data, not the related collection's rows) so it'd\n// show a bare numeric id — excluded until that's worth solving.\nfunction listableFields(config: CollectionConfig): [string, FieldConfig][] {\n const excluded = new Set([\"richText\", \"array\", \"relationship\"]);\n return Object.entries(config.fields).filter(\n ([key, field]) => key !== \"id\" && !excluded.has(field.type),\n );\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value === null || value === undefined) return \"—\";\n if (value instanceof Date) return value.toLocaleDateString();\n return String(value);\n}\n\nfunction rowId(row: Row): number | undefined {\n return typeof row.id === \"number\" ? row.id : undefined;\n}\n\nexport interface CollectionListProps {\n config: CollectionConfig;\n rows: Row[];\n onRowClick?: (row: Row) => void;\n\n /**\n * 1-based current page. Omit (along with `pageSize`) to render without\n * the pagination bar entirely — list views with no `find()` paging\n * wired up yet still render correctly.\n */\n page?: number;\n pageSize?: number;\n /** Total row count across all pages — see `LocalApi.count()`. Enables\n * disabling \"Next\" exactly at the last page; omit to fall back to a\n * `rows.length < pageSize` heuristic. */\n totalCount?: number;\n onPageChange?: (page: number) => void;\n\n /** Field key currently sorted on. Omit to hide the sort control. */\n sortField?: string;\n sortDirection?: \"asc\" | \"desc\";\n onSortChange?: (field: string, direction: \"asc\" | \"desc\") => void;\n\n /** Shows the \"Select\" bulk-select mode toggle. */\n selectable?: boolean;\n selectedIds?: ReadonlySet<number>;\n onSelectionChange?: (selectedIds: Set<number>) => void;\n}\n\nexport function CollectionList(props: CollectionListProps) {\n // Columns are derived once from the collection schema — the single source\n // of truth feeding BOTH the desktop <table> and the mobile card list below\n // (issue #25's mobile-first note). Sorting/pagination/selection stay\n // controlled by the consuming route (server-driven), so the table is\n // configured with just the core row model; its header/cell rendering is\n // driven through flexRender so a future custom cell renderer (links,\n // badges, thumbnails) is a per-column change, not a markup fork.\n const columns = (): ColumnDef<Row>[] =>\n listableFields(props.config).map(([key]) => ({\n id: key,\n accessorFn: (row) => row[key],\n header: key,\n cell: (info) => formatCellValue(info.getValue()),\n }));\n\n const table = createSolidTable<Row>({\n get data() {\n return props.rows;\n },\n get columns() {\n return columns();\n },\n getCoreRowModel: getCoreRowModel(),\n });\n\n const [selectMode, setSelectMode] = createSignal(false);\n\n function toggleSelected(id: number) {\n const next = new Set(props.selectedIds ?? []);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n props.onSelectionChange?.(next);\n }\n\n function handleRowActivate(row: Row) {\n if (selectMode()) {\n const id = rowId(row);\n if (id !== undefined) toggleSelected(id);\n return;\n }\n props.onRowClick?.(row);\n }\n\n return (\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n <Show when={props.selectable}>\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n onClick={() => setSelectMode((v) => !v)}\n >\n {selectMode() ? \"Done\" : \"Select\"}\n </button>\n </Show>\n {/* Dropdown picker, not clickable column headers — sort works the\n same on touch and desktop, see issue #25's mobile-first note. */}\n <Show when={props.onSortChange}>\n <div class=\"join\">\n <select\n aria-label=\"Sort by\"\n class=\"select select-sm join-item\"\n value={props.sortField ?? \"\"}\n onChange={(e) =>\n props.onSortChange?.(\n e.currentTarget.value,\n props.sortDirection ?? \"asc\",\n )\n }\n >\n <For each={table.getAllColumns()}>\n {(column) => <option value={column.id}>{column.id}</option>}\n </For>\n </select>\n <select\n aria-label=\"Sort direction\"\n class=\"select select-sm join-item\"\n value={props.sortDirection ?? \"asc\"}\n onChange={(e) =>\n props.onSortChange?.(\n props.sortField ?? table.getAllColumns()[0]?.id ?? \"\",\n e.currentTarget.value as \"asc\" | \"desc\",\n )\n }\n >\n <option value=\"asc\">Ascending</option>\n <option value=\"desc\">Descending</option>\n </select>\n </div>\n </Show>\n </div>\n\n <Show\n when={props.rows.length > 0}\n fallback={<p class=\"text-sm opacity-70\">No {props.config.slug} yet.</p>}\n >\n {/* Table on desktop — hidden below md per the mobile-first card\n layout below, not the other way around. */}\n <table class=\"table hidden md:table\">\n <thead>\n <For each={table.getHeaderGroups()}>\n {(headerGroup) => (\n <tr>\n <Show when={selectMode()}>\n <th />\n </Show>\n <For each={headerGroup.headers}>\n {(header) => (\n <th>\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n </th>\n )}\n </For>\n </tr>\n )}\n </For>\n </thead>\n <tbody>\n <For each={table.getRowModel().rows}>\n {(row) => (\n <tr\n class={\n props.onRowClick || selectMode()\n ? \"cursor-pointer hover\"\n : undefined\n }\n onClick={() => handleRowActivate(row.original)}\n >\n <Show when={selectMode()}>\n <td>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm\"\n onClick={(e) => e.stopPropagation()}\n checked={\n rowId(row.original) !== undefined &&\n (props.selectedIds?.has(\n rowId(row.original) as number,\n ) ??\n false)\n }\n onChange={() => {\n const id = rowId(row.original);\n if (id !== undefined) toggleSelected(id);\n }}\n />\n </td>\n </Show>\n <For each={row.getVisibleCells()}>\n {(cell) => (\n <td>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n\n {/* Stacked card list on mobile/tablet — tap-to-select via an\n always-visible checkbox in select mode, never hover-revealed.\n Same table model as the desktop view, rendered as key/value rows. */}\n <div class=\"flex flex-col gap-2 md:hidden\">\n <For each={table.getRowModel().rows}>\n {(row) => (\n // biome-ignore lint/a11y/useSemanticElements: a native <button> can't contain interactive content (the select-mode checkbox below); role=\"button\" + tabIndex/onKeyDown is the standard fallback.\n <div\n class=\"card bg-base-200 cursor-pointer p-3\"\n role=\"button\"\n tabIndex={0}\n onClick={() => handleRowActivate(row.original)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleRowActivate(row.original);\n }\n }}\n >\n <div class=\"flex items-start gap-3\">\n <Show when={selectMode()}>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm mt-1\"\n onClick={(e) => e.stopPropagation()}\n checked={\n rowId(row.original) !== undefined &&\n (props.selectedIds?.has(\n rowId(row.original) as number,\n ) ??\n false)\n }\n onChange={() => {\n const id = rowId(row.original);\n if (id !== undefined) toggleSelected(id);\n }}\n />\n </Show>\n <div class=\"flex flex-1 flex-col gap-1\">\n <For each={row.getVisibleCells()}>\n {(cell) => (\n <div class=\"flex justify-between gap-2 text-sm\">\n <span class=\"opacity-60\">{cell.column.id}</span>\n <span class=\"text-right\">\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </span>\n </div>\n )}\n </For>\n </div>\n </div>\n </div>\n )}\n </For>\n </div>\n </Show>\n\n {/* Bottom-anchored prev/next bar — no page numbers, per issue #25's\n mobile-first note. Renders only when pagination is wired up. */}\n <Show when={props.page !== undefined && props.pageSize !== undefined}>\n <div class=\"bg-base-100 sticky bottom-0 flex items-center justify-between gap-2 border-t py-2\">\n <button\n type=\"button\"\n class=\"btn btn-sm\"\n disabled={(props.page ?? 1) <= 1}\n onClick={() => props.onPageChange?.((props.page ?? 1) - 1)}\n >\n Prev\n </button>\n <span class=\"text-sm opacity-70\">Page {props.page}</span>\n <button\n type=\"button\"\n class=\"btn btn-sm\"\n disabled={\n props.totalCount !== undefined\n ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount\n : props.rows.length < (props.pageSize ?? 0)\n }\n onClick={() => props.onPageChange?.((props.page ?? 1) + 1)}\n >\n Next\n </button>\n </div>\n </Show>\n </div>\n );\n}\n","// Copyright (c) 2026 BowenLabs. All rights reserved.\n// Cadmea is MIT licensed. See LICENSE in the repo root.\n\nimport type { ImageCrop, ImageHotspot } from \"@thebes/cadmus/storage\";\nimport { createMemo, createSignal, Show } from \"solid-js\";\n\n/**\n * Image hotspot/crop editor widget (issue #17). A custom field widget for\n * `upload` image fields: upload an image, then click it to set the focal\n * point (hotspot) and optionally enter a crop region. Stores the value as a\n * JSON string `{ url, hotspot?, crop? }` in the same column (back-compatible\n * — a plain URL string still parses). Pair with `ImageService.render`'s\n * `hotspot`/`crop` args on the read side (see @thebes/cadmus-cloudflare-images).\n *\n * Register it via `createCollectionEditPage`/`CollectionEdit`'s `fieldWidgets`\n * option, keyed by the field name.\n */\n\nexport interface ImageWithHotspot {\n url: string;\n hotspot?: ImageHotspot;\n crop?: ImageCrop;\n}\n\nconst round2 = (n: number): number => Math.round(n * 100) / 100;\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n));\n\n/**\n * Parse an upload-field value into `{ url, hotspot?, crop? }`. Accepts the\n * JSON object this widget writes, an already-parsed object, or a bare URL\n * string (legacy / non-hotspot uploads). Returns null for empty values.\n */\nexport function parseImageHotspotValue(\n value: unknown,\n): ImageWithHotspot | null {\n if (!value) return null;\n if (typeof value === \"object\") return value as ImageWithHotspot;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n return JSON.parse(trimmed) as ImageWithHotspot;\n } catch {\n // fall through to treating it as a plain URL\n }\n }\n return trimmed ? { url: trimmed } : null;\n }\n return null;\n}\n\n/** Serialize an {@link ImageWithHotspot} for storage in an upload field. */\nexport function serializeImageHotspotValue(value: ImageWithHotspot): string {\n return JSON.stringify(value);\n}\n\n/** Props every `fieldWidgets` widget receives from CollectionEdit. */\nexport interface FieldWidgetProps {\n fieldKey: string;\n value: unknown;\n setValue: (value: unknown) => void;\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n}\n\nexport function ImageHotspotField(props: FieldWidgetProps) {\n const parsed = createMemo(() => parseImageHotspotValue(props.value));\n const [uploading, setUploading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n\n const patch = (next: Partial<ImageWithHotspot>) => {\n const current = parsed() ?? { url: \"\" };\n props.setValue(serializeImageHotspotValue({ ...current, ...next }));\n };\n\n async function handleFile(e: Event & { currentTarget: HTMLInputElement }) {\n const file = e.currentTarget.files?.[0];\n if (!file) return;\n if (!props.onUploadFile) {\n setError(\"No upload handler configured for this form.\");\n return;\n }\n setUploading(true);\n setError(undefined);\n try {\n const { url } = await props.onUploadFile(file);\n patch({ url });\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }\n\n function handleImageClick(\n e: MouseEvent & { currentTarget: HTMLImageElement },\n ) {\n const rect = e.currentTarget.getBoundingClientRect();\n const x = clamp01((e.clientX - rect.left) / rect.width);\n const y = clamp01((e.clientY - rect.top) / rect.height);\n patch({ hotspot: { x: round2(x), y: round2(y) } });\n }\n\n const crop = () => parsed()?.crop ?? { top: 0, right: 0, bottom: 0, left: 0 };\n const setCrop = (edge: keyof ImageCrop, raw: string) => {\n patch({ crop: { ...crop(), [edge]: clamp01(Number(raw) || 0) } });\n };\n\n return (\n <div class=\"flex flex-col gap-3\">\n <input\n id={props.fieldKey}\n class=\"file-input\"\n type=\"file\"\n accept=\"image/*\"\n disabled={uploading()}\n onChange={handleFile}\n />\n <Show when={uploading()}>\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n <Show when={error()}>\n <p class=\"text-sm text-error\">{error()}</p>\n </Show>\n\n <Show when={parsed()?.url}>\n {(url) => (\n <div class=\"flex flex-col gap-2\">\n <p class=\"text-xs opacity-60\">\n Click the image to set the focal point.\n </p>\n <div class=\"relative inline-block max-w-md\">\n {/* biome-ignore lint/a11y/noStaticElementInteractions: the image is the hotspot-picking surface */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: pointer-based focal-point picker; numeric inputs below are the keyboard-accessible path */}\n <img\n src={url()}\n alt=\"Set focal point\"\n class=\"block w-full cursor-crosshair rounded\"\n onClick={handleImageClick}\n />\n <Show when={parsed()?.hotspot}>\n {(hs) => (\n <span\n class=\"pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white bg-[var(--accent,#56c6be)] shadow\"\n style={{\n left: `${hs().x * 100}%`,\n top: `${hs().y * 100}%`,\n }}\n />\n )}\n </Show>\n </div>\n\n <details class=\"text-sm\">\n <summary class=\"cursor-pointer opacity-70\">\n Crop (advanced)\n </summary>\n <div class=\"mt-2 grid grid-cols-4 gap-2\">\n {([\"top\", \"right\", \"bottom\", \"left\"] as const).map((edge) => (\n <label class=\"flex flex-col gap-1 text-xs\">\n <span class=\"capitalize opacity-70\">{edge}</span>\n <input\n class=\"input input-sm\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n value={crop()[edge]}\n onInput={(e) => setCrop(edge, e.currentTarget.value)}\n />\n </label>\n ))}\n </div>\n </details>\n\n <p class=\"break-all text-xs opacity-50\">{url()}</p>\n </div>\n )}\n </Show>\n </div>\n );\n}\n","import {\n createEffect,\n createSignal,\n For,\n type JSX,\n onCleanup,\n Show,\n} from \"solid-js\";\n\nexport interface SearchPaletteResult {\n collection: string;\n id: number;\n label: string;\n}\n\nexport interface SearchPaletteProps {\n /** Runs a query against `LocalApi.search()` for every searchable collection — see `@thebes/cadmus/cms`'s `getCollectionsMeta`. */\n onSearch: (query: string) => Promise<SearchPaletteResult[]>;\n /** Navigates to the chosen result; the palette closes itself afterward. */\n onSelect: (result: SearchPaletteResult) => void;\n}\n\nconst DEBOUNCE_MS = 200;\n\nfunction capitalize(value: string): string {\n return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);\n}\n\n/**\n * Self-contained Cmd+K (Ctrl+K on non-Mac) search palette — issue #29.\n * Owns its own open/closed state and keyboard listener; the host app only\n * supplies `onSearch` (wired to a server function that fans out across\n * every collection with `search` configured) and `onSelect` (navigation).\n * Mirrors PanelNav's focus-trap-on-open / restore-focus-on-close pattern\n * rather than introducing a second one.\n */\nexport function SearchPalette(props: SearchPaletteProps): JSX.Element {\n const [open, setOpen] = createSignal(false);\n const [query, setQuery] = createSignal(\"\");\n const [results, setResults] = createSignal<SearchPaletteResult[]>([]);\n const [activeIndex, setActiveIndex] = createSignal(0);\n let inputRef: HTMLInputElement | undefined;\n let triggeredBy: HTMLElement | null = null;\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n // Guards a result fetch that resolves after a newer one was already\n // kicked off (or after the palette closed) from clobbering fresher\n // results with stale ones.\n let latestQueryToken = 0;\n\n function close() {\n setOpen(false);\n setQuery(\"\");\n setResults([]);\n triggeredBy?.focus();\n }\n\n function runSearch(value: string) {\n const token = ++latestQueryToken;\n if (value.trim().length < 2) {\n setResults([]);\n return;\n }\n props.onSearch(value).then((found) => {\n if (token !== latestQueryToken) return;\n setResults(found);\n setActiveIndex(0);\n });\n }\n\n function onInput(value: string) {\n setQuery(value);\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => runSearch(value), DEBOUNCE_MS);\n }\n\n function selectResult(result: SearchPaletteResult | undefined) {\n if (!result) return;\n props.onSelect(result);\n close();\n }\n\n // Global Cmd+K / Ctrl+K listener — registered once, independent of\n // `open` (unlike PanelNav's Escape/Tab handling, which only needs to\n // exist while open).\n createEffect(() => {\n function onGlobalKeyDown(event: KeyboardEvent) {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n triggeredBy = document.activeElement as HTMLElement | null;\n setOpen(true);\n }\n }\n document.addEventListener(\"keydown\", onGlobalKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onGlobalKeyDown));\n });\n\n createEffect(() => {\n if (open()) inputRef?.focus();\n });\n\n function onDialogKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setActiveIndex((i) => Math.min(i + 1, results().length - 1));\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n selectResult(results()[activeIndex()]);\n }\n }\n\n return (\n <Show when={open()}>\n <div\n aria-hidden=\"true\"\n class=\"fixed inset-0 z-50 flex items-start justify-center bg-[var(--color-backdrop)] px-4 pt-[15vh]\"\n onClick={close}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Search\"\n class=\"w-full max-w-lg overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--surface-strong)] shadow-2xl\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={onDialogKeyDown}\n >\n <div class=\"flex items-center gap-2 border-b border-[var(--line)] px-4 py-3\">\n <i\n class=\"ph ph-magnifying-glass text-lg text-[var(--sea-ink-soft)]\"\n aria-hidden=\"true\"\n />\n <input\n ref={inputRef}\n type=\"text\"\n value={query()}\n onInput={(event) => onInput(event.currentTarget.value)}\n placeholder=\"Search…\"\n aria-label=\"Search\"\n class=\"flex-1 bg-transparent text-base text-[var(--sea-ink)] outline-none placeholder:text-[var(--sea-ink-soft)]\"\n />\n <kbd class=\"rounded border border-[var(--chip-line)] bg-[var(--chip-bg)] px-1.5 py-0.5 text-xs text-[var(--sea-ink-soft)]\">\n Esc\n </kbd>\n </div>\n\n <Show\n when={results().length > 0}\n fallback={\n <p class=\"px-4 py-6 text-center text-sm text-[var(--sea-ink-soft)]\">\n {query().trim().length < 2\n ? \"Keep typing to search…\"\n : \"No results\"}\n </p>\n }\n >\n <ul class=\"max-h-80 overflow-y-auto py-2\">\n <For each={results()}>\n {(result, index) => (\n <li>\n <button\n type=\"button\"\n onClick={() => selectResult(result)}\n onMouseEnter={() => setActiveIndex(index())}\n class=\"flex w-full items-center justify-between gap-3 px-4 py-2 text-left text-sm text-[var(--sea-ink)] hover:bg-[var(--link-bg-hover)]\"\n classList={{\n \"bg-[var(--link-bg-hover)]\": activeIndex() === index(),\n }}\n >\n <span class=\"truncate\">{result.label}</span>\n <span class=\"shrink-0 text-xs text-[var(--sea-ink-soft)]\">\n {capitalize(result.collection)}\n </span>\n </button>\n </li>\n )}\n </For>\n </ul>\n </Show>\n </div>\n </div>\n </Show>\n );\n}\n","// Copyright (c) 2026 BowenLabs. All rights reserved.\n// Cadmea is MIT licensed. See LICENSE in the repo root.\n\nimport {\n type EditRef,\n PREVIEW_VALUES_MESSAGE,\n type PreviewValuesMessage,\n VISUAL_EDIT_MESSAGE,\n type VisualEditingMessage,\n} from \"@thebes/cadmus/cms\";\nimport { createEffect, onCleanup, onMount } from \"solid-js\";\n\n/**\n * Visual-editing preview pane (issue #15, studio side). Embeds the site's\n * preview in an iframe and listens for the click-to-edit `postMessage` that\n * `@thebes/cadmus/cms`'s `mountVisualEditing` posts from inside the preview.\n * On a click, it calls `onEdit(ref)` so the studio can navigate to that\n * field's editor (e.g. `/admin/<collection>/<id>`).\n *\n * The preview page must (a) tag editable regions with `editAttr(...)` and\n * (b) call `mountVisualEditing()` client-side. This component is the parent\n * half of that handshake.\n */\nexport interface VisualEditingPaneProps {\n /** URL of the preview route to embed. */\n src: string;\n /** Called when an editable region in the preview is clicked. */\n onEdit?: (ref: EditRef) => void;\n /**\n * Origin the preview is served from — messages from any other origin are\n * ignored (postMessage security). Defaults to `src`'s origin.\n */\n allowedOrigin?: string;\n /** Class for the iframe (size it via the consumer's layout). */\n class?: string;\n title?: string;\n /**\n * In-progress form values to push into the preview for as-you-type live\n * updates. Posted to the iframe on every change; the preview page must call\n * `mountPreviewSync` to receive them. Requires `previewTarget`.\n */\n previewValues?: Record<string, unknown>;\n /** Which document `previewValues` belong to (matched by the preview). */\n previewTarget?: { collection: string; id: number };\n}\n\nfunction originOf(url: string): string | undefined {\n try {\n return new URL(url).origin;\n } catch {\n return undefined;\n }\n}\n\nexport function VisualEditingPane(props: VisualEditingPaneProps) {\n let iframe: HTMLIFrameElement | undefined;\n const targetOrigin = () => props.allowedOrigin ?? originOf(props.src) ?? \"*\";\n\n onMount(() => {\n const expected = props.allowedOrigin ?? originOf(props.src);\n const handler = (event: MessageEvent) => {\n // Same-origin-only: drop messages from any other window/origin.\n if (expected && event.origin !== expected) return;\n const data = event.data as Partial<VisualEditingMessage> | null;\n if (data?.type === VISUAL_EDIT_MESSAGE && data.ref) {\n props.onEdit?.(data.ref);\n }\n };\n window.addEventListener(\"message\", handler);\n onCleanup(() => window.removeEventListener(\"message\", handler));\n });\n\n // As-you-type live preview: push the latest form values into the iframe on\n // every change. The preview page's mountPreviewSync patches its tagged\n // text regions in response.\n createEffect(() => {\n const values = props.previewValues;\n const target = props.previewTarget;\n const win = iframe?.contentWindow;\n if (!values || !target || !win) return;\n const message: PreviewValuesMessage = {\n type: PREVIEW_VALUES_MESSAGE,\n collection: target.collection,\n id: target.id,\n values,\n };\n win.postMessage(message, targetOrigin());\n });\n\n return (\n <iframe\n ref={(el) => {\n iframe = el;\n }}\n src={props.src}\n title={props.title ?? \"Preview\"}\n class={props.class ?? \"h-full w-full border-0\"}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["createForm","CollectionConfig","FieldConfig","validateDocument","createEffect","createSignal","For","Index","JSX","lazy","onCleanup","Show","Suspense","CollectionCapabilities","FieldWidgetProps","FieldWidget","props","Element","FieldAccessor","state","value","meta","errors","handleChange","handleBlur","pushValue","insertValue","index","removeValue","moveValue","from","to","RichTextEditor","then","mod","default","editableFields","config","Object","entries","fields","filter","key","humanize","spaced","replace","trim","charAt","toUpperCase","slice","toLowerCase","labelFor","field","admin","label","FieldGroup","name","groupFields","groups","byName","Map","entry","group","get","set","push","RelationshipOption","id","DraftActions","onSaveDraft","values","Record","Promise","onPublish","onPreview","saving","publishing","previewing","canPublish","canPreview","saveDraftLabel","publishLabel","previewLabel","autosave","autosaveMs","confirmPublish","CollectionEditProps","initialValues","onSubmit","submitLabel","error","onUploadFile","file","File","url","relationshipOptions","Partial","onDirtyChange","dirty","onValuesChange","fieldWidgets","draftActions","capabilities","RenderContext","CollectionEdit","operation","validateForm","violations","v","severity","path","message","keys","length","undefined","form","defaultValues","validators","onSubmitAsync","editablePayload","isDefaultValue","useStore","s","formValues","fromEntries","type","ctx","fieldGroups","versioned","versions","drafts","autosaveStatus","setAutosaveStatus","confirmingPublish","setConfirmingPublish","requestPublish","autosaveTimer","ReturnType","setTimeout","clearTimeout","_el$","_tmpl$8","_el$3","firstChild","addEventListener","event","preventDefault","handleSubmit","_$insert","_$createComponent","when","children","_el$2","_tmpl$","each","fallback","FieldsGrid","_el$17","_tmpl$9","_el$18","canUpdate","_el$19","_tmpl$4","$$click","_tmpl$2","_$effect","disabled","_el$4","_tmpl$3","_el$6","_el$8","_tmpl$5","_el$0","_tmpl$6","_el$1","_tmpl$7","_el$10","_el$11","_el$12","nextSibling","_el$13","_el$14","_el$15","_el$16","FormApi","_el$21","_tmpl$0","condition","renderField","renderArray","spanClass","width","Field","fieldApi","_el$22","_tmpl$12","_el$23","_$className","_$setAttribute","required","_tmpl$1","description","_el$25","_tmpl$10","renderControl","_el$26","_tmpl$11","Boolean","join","Widget","lastIndexOf","fieldKey","setValue","readOnly","change","_el$27","_tmpl$13","$$input","e","currentTarget","_p$","_v$","placeholder","_v$2","t","_el$28","_tmpl$14","options","option","_el$29","_tmpl$15","_el$30","_tmpl$16","valueAsNumber","_v$3","_v$4","_el$31","_tmpl$17","formatDateValue","_el$32","_tmpl$18","checked","UploadControl","RelationshipField","relationTo","content","onChange","doc","uploading","setUploading","uploadError","setUploadError","handleFileChange","Event","HTMLInputElement","files","err","Error","_el$34","_tmpl$21","_el$36","_el$35","_tmpl$19","_el$38","_tmpl$20","_v$5","_v$6","_v$7","a","query","setQuery","open","setOpen","active","setActive","listId","isMulti","hasMany","selectedIds","Array","isArray","selectedOptions","o","includes","filtered","q","singleLabel","choose","removeId","x","onKeyDown","KeyboardEvent","Math","min","max","ids","_el$39","_tmpl$25","_el$41","_$memo","_el$40","_tmpl$22","_el$44","_tmpl$26","_el$45","$$keydown","_el$42","_tmpl$23","$$mousedown","_el$43","_tmpl$24","i","_el$46","_tmpl$27","_v$11","_v$12","classList","toggle","_v$8","_v$9","_v$0","_v$1","_v$10","mode","BlockEditor","variantLabel","disc","NonNullable","variant","variantsAdmin","collapsed","setCollapsed","Set","menuOpen","setMenuOpen","discriminator","variants","items","addBlock","seed","duplicate","move","toggleCollapse","prev","next","has","delete","add","blockTitle","item","blockSummary","f","fieldsForItem","String","_el$47","_tmpl$30","_el$48","_el$51","_el$50","isCollapsed","_el$55","_tmpl$33","_el$56","_el$57","_el$58","_el$59","_el$61","_el$62","_el$63","_el$64","_el$65","_el$60","_tmpl$31","_el$66","_tmpl$32","itemKey","itemField","_v$13","_v$14","_el$67","_tmpl$34","_el$68","_el$52","_tmpl$29","_el$53","_el$54","_tmpl$28","_el$69","_tmpl$36","icon","_el$70","_tmpl$35","base","variantValue","variantFields","date","Date","Number","isNaN","getTime","toLocaleString","_$delegateEvents","ColumnDef","createSolidTable","flexRender","getCoreRowModel","CollectionConfig","FieldConfig","createSignal","For","JSX","Show","Row","Record","listableFields","config","excluded","Set","Object","entries","fields","filter","key","field","has","type","formatCellValue","value","undefined","Date","toLocaleDateString","String","rowId","row","id","CollectionListProps","rows","onRowClick","page","pageSize","totalCount","onPageChange","sortField","sortDirection","onSortChange","direction","selectable","selectedIds","ReadonlySet","onSelectionChange","emptyState","Element","CollectionList","props","columns","map","accessorFn","header","cell","info","getValue","table","data","selectMode","setSelectMode","toggleSelected","next","delete","add","handleRowActivate","_el$","_tmpl$6","_el$2","firstChild","_$insert","_$createComponent","when","children","_el$3","_tmpl$","$$click","v","_el$4","_tmpl$2","_el$5","_el$6","nextSibling","addEventListener","e","currentTarget","each","getAllColumns","column","_el$14","_tmpl$7","_$effect","length","fallback","_el$15","_tmpl$8","_el$16","_el$17","_el$19","_el$18","slug","_el$7","_tmpl$3","_el$8","_el$9","getHeaderGroups","headerGroup","_el$20","_tmpl$0","_tmpl$9","headers","_el$22","columnDef","getContext","getRowModel","_el$23","original","_el$24","_tmpl$1","_el$25","stopPropagation","checked","getVisibleCells","_el$26","_tmpl$10","_$className","_el$0","_tmpl$4","_el$27","_tmpl$12","_el$28","_el$30","$$keydown","preventDefault","_el$29","_tmpl$11","_el$31","_tmpl$13","_el$32","_el$33","_$memo","_el$1","_tmpl$5","_el$10","_el$11","_el$12","_el$13","_p$","_v$","_v$2","disabled","t","_$delegateEvents","ImageCrop","ImageHotspot","createMemo","createSignal","Show","ImageWithHotspot","url","hotspot","crop","round2","n","Math","round","clamp01","min","max","parseImageHotspotValue","value","trimmed","trim","startsWith","JSON","parse","serializeImageHotspotValue","stringify","FieldWidgetProps","fieldKey","setValue","onUploadFile","file","File","Promise","ImageHotspotField","props","parsed","uploading","setUploading","error","setError","patch","next","Partial","current","handleFile","e","Event","currentTarget","HTMLInputElement","files","undefined","err","Error","message","handleImageClick","MouseEvent","HTMLImageElement","rect","getBoundingClientRect","x","clientX","left","width","y","clientY","top","height","right","bottom","setCrop","edge","raw","Number","_el$","_tmpl$3","_el$2","firstChild","addEventListener","_$insert","_$createComponent","when","children","_tmpl$","_el$4","_tmpl$2","_el$5","_tmpl$4","_el$6","_el$7","nextSibling","_el$8","_el$9","_el$0","_el$1","_el$10","$$click","hs","_el$11","_tmpl$5","_$effect","_p$","_v$3","_v$4","_$setStyleProperty","t","const","map","_el$12","_tmpl$6","_el$13","_el$14","$$input","_$setAttribute","_v$","_v$2","disabled","_$delegateEvents","createEffect","createSignal","For","JSX","onCleanup","Show","SearchPaletteResult","collection","id","label","SearchPaletteProps","onSearch","query","Promise","onSelect","result","DEBOUNCE_MS","capitalize","value","length","toUpperCase","slice","SearchPalette","props","Element","open","setOpen","setQuery","results","setResults","activeIndex","setActiveIndex","inputRef","HTMLInputElement","triggeredBy","HTMLElement","debounceTimer","ReturnType","setTimeout","latestQueryToken","close","focus","runSearch","token","trim","then","found","onInput","clearTimeout","selectResult","onGlobalKeyDown","event","KeyboardEvent","metaKey","ctrlKey","key","toLowerCase","preventDefault","document","activeElement","addEventListener","removeEventListener","onDialogKeyDown","i","Math","min","max","_$createComponent","when","children","_el$","_tmpl$2","_el$2","firstChild","_el$3","_el$4","_el$5","nextSibling","$$click","$$keydown","stopPropagation","$$input","currentTarget","_ref$","_$use","_$insert","fallback","_el$7","_tmpl$3","_el$6","_tmpl$","each","index","_el$8","_tmpl$4","_el$9","_el$0","_el$1","_$effect","classList","toggle","_$delegateEvents","EditRef","PREVIEW_VALUES_MESSAGE","PreviewValuesMessage","VISUAL_EDIT_MESSAGE","VisualEditingMessage","createEffect","onCleanup","onMount","VisualEditingPaneProps","src","onEdit","ref","allowedOrigin","class","title","previewValues","Record","previewTarget","collection","id","originOf","url","URL","origin","undefined","VisualEditingPane","props","iframe","HTMLIFrameElement","targetOrigin","expected","handler","event","MessageEvent","data","Partial","type","window","addEventListener","removeEventListener","values","target","win","contentWindow","message","postMessage","_el$","_tmpl$","_$use","el","_$effect","_p$","_v$","_v$2","_v$3","e","_$setAttribute","t","a","_$className"],"sources":["../../src/CollectionEdit.tsx","../../src/CollectionList.tsx","../../src/ImageHotspotField.tsx","../../src/SearchPalette.tsx","../../src/VisualEditingPane.tsx"],"sourcesContent":["import { createForm } from \"@tanstack/solid-form\";\nimport type { CollectionConfig, FieldConfig } from \"@thebes/cadmus/cms\";\nimport { validateDocument } from \"@thebes/cadmus/cms\";\nimport {\n createEffect,\n createSignal,\n For,\n Index,\n type JSX,\n lazy,\n onCleanup,\n Show,\n Suspense,\n} from \"solid-js\";\nimport type { CollectionCapabilities } from \"./capabilities.js\";\nimport type { FieldWidgetProps } from \"./ImageHotspotField.js\";\n\n/** A custom per-field editor, registered via `fieldWidgets`. */\nexport type FieldWidget = (props: FieldWidgetProps) => JSX.Element;\n\n// TanStack Form's per-field render prop hands back an accessor to the\n// FieldApi. Its generics are heavy and not worth threading through this\n// schema-driven renderer (every field is `unknown`-typed anyway), so the\n// helpers below take the accessor loosely-typed.\ntype FieldAccessor = () => {\n state: { value: unknown; meta: { errors: unknown[] } };\n handleChange: (value: unknown) => void;\n handleBlur: () => void;\n pushValue: (value: unknown) => void;\n insertValue: (index: number, value: unknown) => void;\n removeValue: (index: number) => void;\n moveValue: (from: number, to: number) => void;\n};\n\n// Dynamic import, not a static one — @tiptap/core + @tiptap/starter-kit\n// are a large dependency (pushed a consuming route's bundle from ~9KB to\n// ~800KB when statically imported, even for collections with zero\n// richText fields). Lazy-loading means only forms that actually render a\n// richText field pull this chunk in at runtime.\nconst RichTextEditor = lazy(() =>\n import(\"./RichTextEditor.js\").then((mod) => ({\n default: mod.RichTextEditor,\n })),\n);\n\n// Fields the generic form can actually render today. `id` is never\n// user-editable. `date` fields (e.g. createdAt) are server-defaulted and\n// shown read-only rather than editable in this step.\nfunction editableFields(config: CollectionConfig): [string, FieldConfig][] {\n return Object.entries(config.fields).filter(([key]) => key !== \"id\");\n}\n\n// Default label for a field with no `admin.label`: split camelCase and\n// snake/kebab into words, sentence-case the result. `metaDescription` →\n// \"Meta description\", `created_at` → \"Created at\".\nfunction humanize(key: string): string {\n const spaced = key\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1).toLowerCase();\n}\n\nfunction labelFor(key: string, field: FieldConfig): string {\n return field.admin?.label ?? humanize(key);\n}\n\ninterface FieldGroup {\n /** `undefined` for fields with no `admin.group` — rendered ungrouped. */\n name?: string;\n fields: [string, FieldConfig][];\n}\n\n// Partition fields into `admin.group` buckets, preserving the order each\n// group is first seen. Ungrouped fields keep their own (name: undefined)\n// bucket so they interleave correctly with grouped ones.\nfunction groupFields(entries: [string, FieldConfig][]): FieldGroup[] {\n const groups: FieldGroup[] = [];\n const byName = new Map<string | undefined, FieldGroup>();\n for (const entry of entries) {\n const name = entry[1].admin?.group;\n let group = byName.get(name);\n if (!group) {\n group = { name, fields: [] };\n byName.set(name, group);\n groups.push(group);\n }\n group.fields.push(entry);\n }\n return groups;\n}\n\nexport interface RelationshipOption {\n id: number;\n label: string;\n}\n\n/**\n * Replaces the generic \"Save\" button with \"Save draft\"/\"Publish\" when the\n * collection has `versions: { drafts: true }` — a separate privilege from\n * a plain update, matching `access.publish` in `@thebes/cadmus/cms`.\n * `onPublish` takes no values: publishing acts on whatever was last saved\n * as a draft (the consuming route tracks which version that is), not on\n * the live form state.\n */\nexport interface DraftActions {\n onSaveDraft: (values: Record<string, unknown>) => void | Promise<void>;\n onPublish?: () => void | Promise<void>;\n /**\n * Opens a live preview of the last saved draft (issue #28) — like\n * `onPublish`, acts on whatever was last saved as a draft, not the live\n * form state. Omit to not render the Preview button at all.\n */\n onPreview?: () => void | Promise<void>;\n saving?: boolean;\n publishing?: boolean;\n previewing?: boolean;\n /** Disables Publish — e.g. until a draft has been saved at least once. */\n canPublish?: boolean;\n /** Disables Preview — same gating as canPublish, a draft must exist first. */\n canPreview?: boolean;\n saveDraftLabel?: string;\n publishLabel?: string;\n previewLabel?: string;\n /**\n * Opt in to debounced autosave: while the form is dirty, `onSaveDraft` is\n * called automatically after a pause in typing, and a \"Saving…/Saved\"\n * status shows in the action bar. Off by default (existing consumers keep\n * the manual Save-draft button only).\n */\n autosave?: boolean;\n /** Debounce window for autosave, in ms. Default 1500. */\n autosaveMs?: number;\n /** Ask for confirmation (a dialog) before publishing. */\n confirmPublish?: boolean;\n}\n\nexport interface CollectionEditProps {\n config: CollectionConfig;\n initialValues?: Record<string, unknown>;\n onSubmit: (values: Record<string, unknown>) => void | Promise<void>;\n submitLabel?: string;\n error?: string;\n /** Disables the Save button and shows a spinner in its place. */\n saving?: boolean;\n /**\n * Resolves an `upload` field's selected file to a stored URL. Required\n * if the collection has any `upload` fields — `CollectionEdit` never\n * talks to storage directly (stays agnostic of R2/cadmus/storage), so\n * the consuming route wires this to a server function that calls an\n * `ImageService`'s `upload()`.\n */\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n /**\n * Options for `relationship` fields (both single and `hasMany`), keyed by\n * the field's `relationTo` collection slug. `CollectionEdit` can't query\n * another collection itself, so the consuming route fetches the related\n * rows and passes them in; the field renders them as a searchable combobox.\n */\n relationshipOptions?: Partial<Record<string, RelationshipOption[]>>;\n /**\n * Fired whenever the dirty (unsaved-changes) state changes — wire this\n * to a router-level navigation guard (e.g. `useBlocker` in the\n * consuming route) since `CollectionEdit` has no router access itself.\n */\n onDirtyChange?: (dirty: boolean) => void;\n /**\n * Fired with the current editable values on every change — wire this to a\n * side-by-side live preview (e.g. `VisualEditingPane`'s `previewValues`).\n * Fires on mount with the initial values too.\n */\n onValuesChange?: (values: Record<string, unknown>) => void;\n /**\n * Per-field custom editor widgets (issue #17), keyed by field name. When a\n * field has a widget here, it's rendered instead of the generic input for\n * that field's type — e.g. `{ heroImage: ImageHotspotField }`. The widget\n * receives the field value, a setter, and `onUploadFile`.\n */\n fieldWidgets?: Record<string, FieldWidget>;\n /** Only rendered when `config.versions?.drafts` is also true. */\n draftActions?: DraftActions;\n /**\n * Hides the Save button when `canUpdate` is `false` — see issue #26's\n * RBAC-aware admin UI. Undefined (the default — most collections don't\n * wire this up) reads as \"allowed\", same as `@thebes/cadmus/cms`'s own\n * \"no access fn = allowed\" default.\n */\n capabilities?: CollectionCapabilities;\n}\n\ninterface RenderContext {\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n relationshipOptions?: Partial<Record<string, RelationshipOption[]>>;\n fieldWidgets?: Record<string, FieldWidget>;\n}\n\nexport function CollectionEdit(props: CollectionEditProps) {\n // TanStack Form owns form state now (was a hand-rolled createSignal +\n // manual JSON.stringify dirty tracking). defaultValues is exactly the\n // passed-in initialValues — NOT seeded with each field's `defaultValue`,\n // so a never-touched optional field stays absent from the submitted\n // payload, matching the prior behavior the tests pin.\n const operation: \"create\" | \"update\" =\n props.initialValues?.id != null ? \"update\" : \"create\";\n\n // Field validation (issue #16's ValidationBuilder) runs client-side as a\n // TanStack Form *form-level* validator — validateDocument with no `db`\n // skips the DB-backed unique/reference checks and evaluates the rest.\n // Returning `{ fields }` (TanStack's global-error shape) distributes each\n // message to the matching field's meta.errors and blocks the submit;\n // letting TanStack own the validate→submit lifecycle (rather than\n // early-returning from the submit action) keeps isSubmitting/canSubmit\n // correct across repeated submits. The server re-validates authoritatively.\n async function validateForm(value: Record<string, unknown>) {\n const violations = await validateDocument(props.config, value, {\n operation,\n });\n const fields: Record<string, string> = {};\n for (const v of violations) {\n if (v.severity === \"error\" && !(v.path in fields)) {\n fields[v.path] = v.message;\n }\n }\n return Object.keys(fields).length > 0 ? { fields } : undefined;\n }\n\n const form = createForm(() => ({\n defaultValues: props.initialValues ?? {},\n validators: {\n onSubmitAsync: ({ value }: { value: Record<string, unknown> }) =>\n validateForm(value),\n },\n onSubmit: async ({ value }: { value: Record<string, unknown> }) => {\n await props.onSubmit(editablePayload(value));\n },\n }));\n\n // Dirty = \"differs from initial values\", reported up for the consuming\n // route's navigation guard. TanStack's `isDirty` is sticky (stays true\n // once a field is touched, even if reverted), so we use the form's\n // `isDefaultValue` aggregate instead — it flips back to true the moment\n // every field equals its default again, preserving the prior revert-to-\n // clean behavior.\n const isDefaultValue = form.useStore((s) => s.isDefaultValue);\n createEffect(() => props.onDirtyChange?.(!isDefaultValue()));\n\n // Current values for the imperative draft action + conditional fields.\n const formValues = form.useStore((s) => s.values as Record<string, unknown>);\n\n // Emit editable values on every change for side-by-side live preview.\n createEffect(() => props.onValuesChange?.(editablePayload(formValues())));\n\n // date fields are read-only — never include them in a submitted/draft payload\n function editablePayload(\n value: Record<string, unknown>,\n ): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(value).filter(\n ([key]) => props.config.fields[key]?.type !== \"date\",\n ),\n );\n }\n\n const ctx: RenderContext = {\n get onUploadFile() {\n return props.onUploadFile;\n },\n get relationshipOptions() {\n return props.relationshipOptions;\n },\n get fieldWidgets() {\n return props.fieldWidgets;\n },\n };\n\n const fieldGroups = groupFields(editableFields(props.config));\n const versioned = () => props.config.versions?.drafts && props.draftActions;\n\n // Debounced autosave (opt-in via draftActions.autosave). While the form is\n // dirty, persist the draft after a pause in typing and surface a status so\n // the client never wonders whether their work is saved. Manual Save\n // draft/Publish still work alongside it.\n const [autosaveStatus, setAutosaveStatus] = createSignal<\n \"idle\" | \"saving\" | \"saved\"\n >(\"idle\");\n // Publish-confirmation dialog (opt-in via draftActions.confirmPublish).\n const [confirmingPublish, setConfirmingPublish] = createSignal(false);\n function requestPublish() {\n if (props.draftActions?.confirmPublish) setConfirmingPublish(true);\n else void props.draftActions?.onPublish?.();\n }\n let autosaveTimer: ReturnType<typeof setTimeout> | undefined;\n createEffect(() => {\n const dirty = !isDefaultValue();\n const values = formValues();\n if (!versioned() || !props.draftActions?.autosave) return;\n if (!dirty) {\n setAutosaveStatus(\"idle\");\n return;\n }\n clearTimeout(autosaveTimer);\n autosaveTimer = setTimeout(async () => {\n setAutosaveStatus(\"saving\");\n try {\n await props.draftActions?.onSaveDraft(editablePayload(values));\n setAutosaveStatus(\"saved\");\n } catch {\n // Surface nothing special on failure — the manual Save draft button\n // (and its error handling) remains the explicit path.\n setAutosaveStatus(\"idle\");\n }\n }, props.draftActions?.autosaveMs ?? 1500);\n });\n onCleanup(() => clearTimeout(autosaveTimer));\n\n return (\n <form\n class=\"flex flex-col gap-4\"\n onSubmit={(event) => {\n event.preventDefault();\n void form.handleSubmit();\n }}\n >\n <Show when={props.error}>\n {/* role=\"alert\" so assistive tech announces submit failures the\n moment they appear, not only if the user happens to navigate to\n them. */}\n <p class=\"text-sm text-error\" role=\"alert\">\n {props.error}\n </p>\n </Show>\n <For each={fieldGroups}>\n {(group) => (\n <Show\n when={group.name}\n fallback={\n <FieldsGrid\n form={form}\n ctx={ctx}\n fields={group.fields}\n values={formValues}\n />\n }\n >\n <fieldset class=\"border-base-300 rounded-box border p-4\">\n <legend class=\"px-2 text-sm font-semibold\">{group.name}</legend>\n <FieldsGrid\n form={form}\n ctx={ctx}\n fields={group.fields}\n values={formValues}\n />\n </fieldset>\n </Show>\n )}\n </For>\n {/* Bottom-anchored, full-width action bar — not a top toolbar, per\n issue #25's mobile-first note. */}\n <div class=\"bg-base-100 sticky bottom-0 flex gap-2 border-t py-3\">\n <Show\n when={versioned()}\n fallback={\n <Show when={props.capabilities?.canUpdate !== false}>\n {/* type=\"button\" + handleSubmit (not a native submit) so\n TanStack Form owns validation — a native `required` field\n left empty no longer silently blocks the submit event, and\n inline validation becomes the single authority. The\n <form onSubmit> above still handles Enter. */}\n <button\n type=\"button\"\n class=\"btn btn-primary flex-1\"\n disabled={props.saving}\n onClick={() => void form.handleSubmit()}\n >\n <Show\n when={props.saving}\n fallback={props.submitLabel ?? \"Save\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n </Show>\n }\n >\n <button\n type=\"button\"\n class=\"btn flex-1\"\n disabled={props.draftActions?.saving}\n onClick={() =>\n void props.draftActions?.onSaveDraft(\n editablePayload(formValues()),\n )\n }\n >\n <Show\n when={props.draftActions?.saving}\n fallback={props.draftActions?.saveDraftLabel ?? \"Save draft\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n <button\n type=\"button\"\n class=\"btn btn-primary flex-1\"\n disabled={\n !props.draftActions?.canPublish || props.draftActions?.publishing\n }\n onClick={requestPublish}\n >\n <Show\n when={props.draftActions?.publishing}\n fallback={props.draftActions?.publishLabel ?? \"Publish\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n <Show when={props.draftActions?.onPreview}>\n <button\n type=\"button\"\n class=\"btn btn-outline flex-1\"\n disabled={\n !props.draftActions?.canPreview ||\n props.draftActions?.previewing\n }\n onClick={() => void props.draftActions?.onPreview?.()}\n >\n <Show\n when={props.draftActions?.previewing}\n fallback={props.draftActions?.previewLabel ?? \"Preview\"}\n >\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n </button>\n </Show>\n <Show when={props.draftActions?.autosave}>\n {/* aria-live so assistive tech announces autosave transitions. */}\n <span\n class=\"text-base-content/60 self-center px-1 text-xs\"\n aria-live=\"polite\"\n >\n <Show when={autosaveStatus() === \"saving\"}>Saving…</Show>\n <Show when={autosaveStatus() === \"saved\"}>Saved</Show>\n </span>\n </Show>\n </Show>\n </div>\n\n {/* Publish-confirmation dialog — a gentle gate before content goes live. */}\n <Show when={confirmingPublish()}>\n <div class=\"modal modal-open\" role=\"dialog\" aria-modal=\"true\">\n <div class=\"modal-box\">\n <h3 class=\"text-lg font-semibold\">Publish changes?</h3>\n <p class=\"text-base-content/70 py-2 text-sm\">\n Your latest saved draft will go live on the site.\n </p>\n <div class=\"modal-action\">\n <button\n type=\"button\"\n class=\"btn btn-ghost\"\n onClick={() => setConfirmingPublish(false)}\n >\n Cancel\n </button>\n <button\n type=\"button\"\n class=\"btn btn-primary\"\n onClick={() => {\n setConfirmingPublish(false);\n void props.draftActions?.onPublish?.();\n }}\n >\n Publish\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"modal-backdrop\"\n aria-label=\"Cancel\"\n onClick={() => setConfirmingPublish(false)}\n />\n </div>\n </Show>\n </form>\n );\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: TanStack Form's instance generics are not worth threading through a schema-driven renderer.\ntype FormApi = any;\n\n// One responsive grid of fields. Half-width fields sit two-up on >= md;\n// everything is single-column on mobile (issue #25's mobile-first note).\n// Conditional fields (`admin.condition`) are wrapped per-field in <Show> so\n// toggling one doesn't re-render (and steal focus from) its siblings.\nfunction FieldsGrid(props: {\n form: FormApi;\n ctx: RenderContext;\n fields: [string, FieldConfig][];\n values: () => Record<string, unknown>;\n}): JSX.Element {\n return (\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2\">\n <For each={props.fields}>\n {([key, field]) => (\n <Show\n when={\n !field.admin?.condition || field.admin.condition(props.values())\n }\n >\n {renderField(\n props.form,\n props.ctx,\n key,\n field,\n labelFor(key, field),\n )}\n </Show>\n )}\n </For>\n </div>\n );\n}\n\nfunction renderField(\n form: FormApi,\n ctx: RenderContext,\n name: string,\n field: FieldConfig,\n label: string,\n): JSX.Element {\n if (field.type === \"array\") return renderArray(form, ctx, name, field, label);\n\n // Half-width fields span one grid column on >= md; everything else spans\n // the full two-column width.\n const spanClass =\n field.admin?.width === \"half\" ? \"md:col-span-1\" : \"md:col-span-2\";\n\n return (\n <form.Field name={name}>\n {(fieldApi: FieldAccessor) => (\n <div class={`form-control ${spanClass}`}>\n {/* The \" *\" stays inside the label's accessible name (it reads as\n \"required\" alongside each input's `required` attribute); the\n span only colors it, it does not change the text. */}\n <label class=\"label\" for={name}>\n {label}\n <Show when={field.required}>\n <span class=\"text-error\">{\" *\"}</span>\n </Show>\n </label>\n <Show when={field.admin?.description}>\n <p class=\"text-base-content/60 mb-1 text-xs\">\n {field.admin?.description}\n </p>\n </Show>\n {renderControl(ctx, name, field, fieldApi)}\n {/* Inline validation messages from the form-level validator\n (distributed to this field's meta by TanStack). */}\n <Show when={(fieldApi().state.meta.errors?.length ?? 0) > 0}>\n <p class=\"text-error mt-1 text-sm\" role=\"alert\">\n {fieldApi().state.meta.errors.filter(Boolean).join(\", \")}\n </p>\n </Show>\n </div>\n )}\n </form.Field>\n );\n}\n\nfunction renderControl(\n ctx: RenderContext,\n name: string,\n field: FieldConfig,\n fieldApi: FieldAccessor,\n): JSX.Element {\n // A registered custom widget wins over the generic type-based input (#17).\n // Match by the full key, or by the trailing field name so a widget can\n // target a field nested inside an `array` item (whose name is a path like\n // `blocks[0].url`) without knowing the index.\n const Widget =\n ctx.fieldWidgets?.[name] ??\n ctx.fieldWidgets?.[name.slice(name.lastIndexOf(\".\") + 1)];\n if (Widget) {\n return (\n <Widget\n fieldKey={name}\n value={fieldApi().state.value}\n setValue={(v) => fieldApi().handleChange(v)}\n onUploadFile={ctx.onUploadFile}\n />\n );\n }\n\n const readOnly = field.admin?.readOnly;\n const change = (v: unknown) => fieldApi().handleChange(v);\n\n switch (field.type) {\n case \"text\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"text\"\n placeholder={field.admin?.placeholder}\n readOnly={readOnly}\n value={(fieldApi().state.value as string) ?? \"\"}\n required={field.required}\n onInput={(e) => change(e.currentTarget.value)}\n onBlur={() => fieldApi().handleBlur()}\n />\n );\n case \"select\":\n return (\n <select\n id={name}\n class=\"select\"\n value={(fieldApi().state.value as string) ?? \"\"}\n required={field.required}\n disabled={readOnly}\n onChange={(e) => change(e.currentTarget.value)}\n onBlur={() => fieldApi().handleBlur()}\n >\n <For each={field.options}>\n {(option) => <option value={option}>{option}</option>}\n </For>\n </select>\n );\n case \"number\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"number\"\n placeholder={field.admin?.placeholder}\n readOnly={readOnly}\n value={(fieldApi().state.value as number) ?? \"\"}\n required={field.required}\n onInput={(e) => change(e.currentTarget.valueAsNumber)}\n onBlur={() => fieldApi().handleBlur()}\n />\n );\n case \"date\":\n return (\n <input\n id={name}\n class=\"input\"\n type=\"text\"\n readOnly\n value={formatDateValue(fieldApi().state.value)}\n />\n );\n case \"checkbox\":\n return (\n <input\n id={name}\n class=\"checkbox\"\n type=\"checkbox\"\n disabled={readOnly}\n checked={(fieldApi().state.value as boolean) ?? false}\n onChange={(e) => change(e.currentTarget.checked)}\n />\n );\n case \"upload\":\n return (\n <UploadControl\n name={name}\n field={field}\n fieldApi={fieldApi}\n ctx={ctx}\n />\n );\n case \"relationship\":\n return (\n <RelationshipField\n name={name}\n field={field}\n fieldApi={fieldApi}\n options={ctx.relationshipOptions?.[field.relationTo] ?? []}\n />\n );\n case \"richText\":\n return (\n <Suspense\n fallback={<span class=\"loading loading-spinner loading-sm\" />}\n >\n <RichTextEditor\n id={name}\n content={fieldApi().state.value as object | undefined}\n onChange={(doc) => change(doc)}\n onUploadFile={ctx.onUploadFile}\n />\n </Suspense>\n );\n default:\n return null;\n }\n}\n\nfunction UploadControl(props: {\n name: string;\n field: FieldConfig & { type: \"upload\" };\n fieldApi: FieldAccessor;\n ctx: RenderContext;\n}) {\n const [uploading, setUploading] = createSignal(false);\n const [uploadError, setUploadError] = createSignal<string>();\n const value = () => props.fieldApi().state.value as string | undefined;\n\n async function handleFileChange(\n e: Event & { currentTarget: HTMLInputElement },\n ) {\n const file = e.currentTarget.files?.[0];\n if (!file) return;\n if (!props.ctx.onUploadFile) {\n setUploadError(\"No upload handler configured for this form.\");\n return;\n }\n setUploading(true);\n setUploadError(undefined);\n try {\n const { url } = await props.ctx.onUploadFile(file);\n props.fieldApi().handleChange(url);\n } catch (err) {\n setUploadError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }\n\n return (\n <div class=\"flex flex-col gap-2\">\n <Show when={value()}>\n <p class=\"text-sm opacity-70 break-all\">{value()}</p>\n </Show>\n <input\n id={props.name}\n class=\"file-input\"\n type=\"file\"\n required={props.field.required && !value()}\n disabled={uploading() || props.field.admin?.readOnly}\n onChange={handleFileChange}\n />\n <Show when={uploading()}>\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n <Show when={uploadError()}>\n <p class=\"text-sm text-error\">{uploadError()}</p>\n </Show>\n </div>\n );\n}\n\n// Searchable relationship picker — a filter-as-you-type combobox (replacing\n// the old plain <select>) that supports both single (hasMany:false → value is\n// a number|null) and multi (hasMany:true → value is number[], rendered as\n// removable chips). Options for `relationTo` are supplied by the consuming\n// route via `relationshipOptions`; this component never queries the DB itself.\nfunction RelationshipField(props: {\n name: string;\n field: FieldConfig & { type: \"relationship\" };\n fieldApi: FieldAccessor;\n options: RelationshipOption[];\n}): JSX.Element {\n const [query, setQuery] = createSignal(\"\");\n const [open, setOpen] = createSignal(false);\n const [active, setActive] = createSignal(0);\n const listId = `${props.name}-listbox`;\n\n const isMulti = () => props.field.hasMany === true;\n const value = () => props.fieldApi().state.value;\n const selectedIds = (): number[] => {\n const v = value();\n if (isMulti()) return Array.isArray(v) ? (v as number[]) : [];\n return v != null ? [v as number] : [];\n };\n const selectedOptions = () =>\n props.options.filter((o) => selectedIds().includes(o.id));\n const filtered = () => {\n const q = query().toLowerCase();\n return props.options.filter(\n (o) =>\n o.label.toLowerCase().includes(q) &&\n (!isMulti() || !selectedIds().includes(o.id)),\n );\n };\n const singleLabel = () => selectedOptions()[0]?.label ?? \"\";\n\n function choose(option: RelationshipOption) {\n if (isMulti()) {\n props.fieldApi().handleChange([...selectedIds(), option.id]);\n setQuery(\"\");\n } else {\n props.fieldApi().handleChange(option.id);\n setQuery(\"\");\n setOpen(false);\n }\n setActive(0);\n }\n function removeId(id: number) {\n if (isMulti()) {\n props.fieldApi().handleChange(selectedIds().filter((x) => x !== id));\n } else {\n props.fieldApi().handleChange(null);\n }\n }\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setOpen(true);\n setActive((a) => Math.min(a + 1, filtered().length - 1));\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive((a) => Math.max(a - 1, 0));\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const option = filtered()[active()];\n if (option) choose(option);\n } else if (e.key === \"Escape\") {\n setOpen(false);\n } else if (e.key === \"Backspace\" && isMulti() && query() === \"\") {\n const ids = selectedIds();\n if (ids.length > 0) removeId(ids[ids.length - 1]);\n }\n }\n\n return (\n <div class=\"relative\">\n <Show when={isMulti() && selectedOptions().length > 0}>\n <div class=\"mb-1 flex flex-wrap gap-1\">\n <For each={selectedOptions()}>\n {(option) => (\n <span class=\"badge badge-primary gap-1\">\n {option.label}\n <button\n type=\"button\"\n aria-label={`Remove ${option.label}`}\n class=\"cursor-pointer\"\n onClick={() => removeId(option.id)}\n >\n ×\n </button>\n </span>\n )}\n </For>\n </div>\n </Show>\n <input\n id={props.name}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={open()}\n aria-controls={listId}\n autocomplete=\"off\"\n class=\"input\"\n required={props.field.required && selectedIds().length === 0}\n disabled={props.field.admin?.readOnly}\n placeholder={props.field.admin?.placeholder ?? \"Search…\"}\n value={open() || isMulti() ? query() : singleLabel()}\n onInput={(e) => {\n setQuery(e.currentTarget.value);\n setOpen(true);\n setActive(0);\n }}\n onFocus={() => setOpen(true)}\n // Delay so a click on an option registers before the list unmounts.\n onBlur={() => setTimeout(() => setOpen(false), 120)}\n onKeyDown={onKeyDown}\n />\n <Show when={!isMulti() && value() != null && !props.field.required}>\n <button\n type=\"button\"\n aria-label=\"Clear\"\n class=\"absolute top-2 right-2 cursor-pointer opacity-60\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => removeId(value() as number)}\n >\n ×\n </button>\n </Show>\n <Show when={open() && filtered().length > 0}>\n {/* role=\"listbox\"/\"option\" live on a div + button (not ul/li) so the\n options are natively focusable interactive elements. */}\n <div\n id={listId}\n role=\"listbox\"\n class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex max-h-56 w-full flex-col overflow-auto border p-1 shadow\"\n >\n <For each={filtered()}>\n {(option, i) => (\n <button\n type=\"button\"\n role=\"option\"\n aria-selected={selectedIds().includes(option.id)}\n class=\"rounded px-3 py-2 text-left\"\n classList={{ \"bg-base-200\": i() === active() }}\n // preventDefault keeps focus on the input so onClick fires\n // before the input's blur closes the list.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => choose(option)}\n >\n {option.label}\n </button>\n )}\n </For>\n </div>\n </Show>\n </div>\n );\n}\n\nfunction renderArray(\n form: FormApi,\n ctx: RenderContext,\n name: string,\n field: FieldConfig & { type: \"array\" },\n label: string,\n): JSX.Element {\n return (\n <form.Field name={name} mode=\"array\">\n {(fieldApi: FieldAccessor) => (\n <BlockEditor\n form={form}\n ctx={ctx}\n name={name}\n field={field}\n label={label}\n fieldApi={fieldApi}\n />\n )}\n </form.Field>\n );\n}\n\nfunction variantLabel(\n disc: NonNullable<(FieldConfig & { type: \"array\" })[\"discriminator\"]>,\n variant: string,\n): string {\n return disc.variantsAdmin?.[variant]?.label ?? humanize(variant);\n}\n\n// Visual block builder (Workstream B) — turns a discriminated `array` field\n// into a page-builder: a friendly \"Add block\" picker (one entry per variant,\n// with optional icon), per-block reorder/duplicate/remove, and collapse to a\n// one-line summary so a stack of blocks reads like a page outline. A plain\n// (non-discriminated) array keeps a single \"Add\" button.\nfunction BlockEditor(props: {\n form: FormApi;\n ctx: RenderContext;\n name: string;\n field: FieldConfig & { type: \"array\" };\n label: string;\n fieldApi: FieldAccessor;\n}): JSX.Element {\n const [collapsed, setCollapsed] = createSignal<Set<number>>(new Set());\n const [menuOpen, setMenuOpen] = createSignal(false);\n\n const disc = props.field.discriminator;\n const variants = disc ? Object.keys(disc.variants) : [];\n const items = () =>\n Array.isArray(props.fieldApi().state.value)\n ? (props.fieldApi().state.value as Record<string, unknown>[])\n : [];\n\n function addBlock(variant?: string) {\n const seed = variant && disc ? { [disc.key]: variant } : {};\n props.fieldApi().pushValue(seed);\n setMenuOpen(false);\n }\n function duplicate(index: number) {\n props.fieldApi().insertValue(index + 1, { ...items()[index] });\n }\n function move(from: number, to: number) {\n if (to < 0 || to >= items().length) return;\n props.fieldApi().moveValue(from, to);\n }\n function toggleCollapse(index: number) {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(index)) next.delete(index);\n else next.add(index);\n return next;\n });\n }\n\n function blockTitle(item: Record<string, unknown>): string {\n if (disc) {\n const v = item[disc.key];\n if (typeof v === \"string\") return variantLabel(disc, v);\n }\n return props.label;\n }\n // A one-line preview for a collapsed block — the first non-discriminator\n // text/select value, so the outline reads meaningfully.\n function blockSummary(item: Record<string, unknown>): string {\n for (const [key, f] of fieldsForItem(props.field, item)) {\n if (key === disc?.key) continue;\n if ((f.type === \"text\" || f.type === \"select\") && item[key]) {\n return String(item[key]);\n }\n }\n return \"\";\n }\n\n return (\n <div class=\"form-control md:col-span-2\">\n {/* A group heading for the block list, not a single-input label. */}\n <div class=\"label font-medium\">\n {props.label}\n <Show when={props.field.required}>\n <span class=\"text-error\">{\" *\"}</span>\n </Show>\n </div>\n <Show when={props.field.admin?.description}>\n <p class=\"text-base-content/60 mb-1 text-xs\">\n {props.field.admin?.description}\n </p>\n </Show>\n <div class=\"flex flex-col gap-3\">\n {/* <Index> (not <For>) keys rows by position so a keystroke in one\n item's input — which replaces the array reference via TanStack's\n immutable update — doesn't unmount/remount the whole row and steal\n focus. Item names are position-based (`blocks[0].title`). */}\n <Index each={items()}>\n {(item, index) => {\n const isCollapsed = () => collapsed().has(index);\n return (\n <div class=\"card bg-base-200 flex flex-col gap-2 p-3\">\n <div class=\"flex items-center gap-2\">\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-sm gap-2\"\n aria-expanded={!isCollapsed()}\n onClick={() => toggleCollapse(index)}\n >\n <span aria-hidden=\"true\">{isCollapsed() ? \"▸\" : \"▾\"}</span>\n <span class=\"font-semibold\">{blockTitle(item())}</span>\n </button>\n <Show when={isCollapsed() && blockSummary(item())}>\n <span class=\"text-base-content/60 truncate text-sm\">\n {blockSummary(item())}\n </span>\n </Show>\n <div class=\"ml-auto flex gap-1\">\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Move up\"\n disabled={index === 0}\n onClick={() => move(index, index - 1)}\n >\n ↑\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Move down\"\n disabled={index === items().length - 1}\n onClick={() => move(index, index + 1)}\n >\n ↓\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs\"\n aria-label=\"Duplicate\"\n onClick={() => duplicate(index)}\n >\n ⧉\n </button>\n <button\n type=\"button\"\n class=\"btn btn-ghost btn-xs text-error\"\n aria-label=\"Remove\"\n onClick={() => props.fieldApi().removeValue(index)}\n >\n Remove\n </button>\n </div>\n </div>\n <Show when={!isCollapsed()}>\n <div class=\"flex flex-col gap-2\">\n <For each={fieldsForItem(props.field, item())}>\n {([itemKey, itemField]) =>\n renderField(\n props.form,\n props.ctx,\n `${props.name}[${index}].${itemKey}`,\n itemField,\n labelFor(itemKey, itemField),\n )\n }\n </For>\n </div>\n </Show>\n </div>\n );\n }}\n </Index>\n\n {/* Discriminated arrays get a block-type picker; plain arrays keep a\n single Add button. */}\n <Show\n when={disc && variants.length > 0}\n fallback={\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm self-start\"\n onClick={() => addBlock()}\n >\n Add {props.label}\n </button>\n }\n >\n <div class=\"relative self-start\">\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen()}\n onClick={() => setMenuOpen((o) => !o)}\n >\n Add block\n </button>\n <Show when={menuOpen()}>\n {/* role=\"menu\"/\"menuitem\" on div + button (not ul/li) so the\n menu items are natively focusable interactive elements. */}\n <div\n role=\"menu\"\n class=\"bg-base-100 border-base-300 rounded-box absolute z-10 mt-1 flex flex-col border p-1 shadow\"\n >\n <For each={variants}>\n {(variant) => (\n <button\n type=\"button\"\n role=\"menuitem\"\n class=\"flex items-center gap-2 rounded px-3 py-2 text-left\"\n onClick={() => addBlock(variant)}\n >\n <Show when={disc?.variantsAdmin?.[variant]?.icon}>\n <i\n class={disc?.variantsAdmin?.[variant]?.icon}\n aria-hidden=\"true\"\n />\n </Show>\n {variantLabel(disc as NonNullable<typeof disc>, variant)}\n </button>\n )}\n </For>\n </div>\n </Show>\n </div>\n </Show>\n </div>\n </div>\n );\n}\n\nfunction fieldsForItem(\n field: FieldConfig & { type: \"array\" },\n item: Record<string, unknown>,\n): [string, FieldConfig][] {\n const base = Object.entries(field.fields);\n const discriminator = field.discriminator;\n if (!discriminator) return base;\n\n const variantValue = item[discriminator.key];\n const variantFields =\n typeof variantValue === \"string\"\n ? discriminator.variants[variantValue]\n : undefined;\n return variantFields ? [...base, ...Object.entries(variantFields)] : base;\n}\n\nfunction formatDateValue(value: unknown): string {\n if (!value) return \"—\";\n const date = value instanceof Date ? value : new Date(value as string);\n return Number.isNaN(date.getTime()) ? \"—\" : date.toLocaleString();\n}\n","import {\n type ColumnDef,\n createSolidTable,\n flexRender,\n getCoreRowModel,\n} from \"@tanstack/solid-table\";\nimport type { CollectionConfig, FieldConfig } from \"@thebes/cadmus/cms\";\nimport { createSignal, For, type JSX, Show } from \"solid-js\";\n\ntype Row = Record<string, unknown>;\n\n// Field types that can be rendered as a plain table cell today.\n// `id` is intentionally excluded — it's never a useful list column.\n// `richText`/`array` are structured content, not a sensible table cell;\n// `relationship` has no resolved label available here (CollectionList\n// only receives raw row data, not the related collection's rows) so it'd\n// show a bare numeric id — excluded until that's worth solving.\nfunction listableFields(config: CollectionConfig): [string, FieldConfig][] {\n const excluded = new Set([\"richText\", \"array\", \"relationship\"]);\n return Object.entries(config.fields).filter(\n ([key, field]) => key !== \"id\" && !excluded.has(field.type),\n );\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value === null || value === undefined) return \"—\";\n if (value instanceof Date) return value.toLocaleDateString();\n return String(value);\n}\n\nfunction rowId(row: Row): number | undefined {\n return typeof row.id === \"number\" ? row.id : undefined;\n}\n\nexport interface CollectionListProps {\n config: CollectionConfig;\n rows: Row[];\n onRowClick?: (row: Row) => void;\n\n /**\n * 1-based current page. Omit (along with `pageSize`) to render without\n * the pagination bar entirely — list views with no `find()` paging\n * wired up yet still render correctly.\n */\n page?: number;\n pageSize?: number;\n /** Total row count across all pages — see `LocalApi.count()`. Enables\n * disabling \"Next\" exactly at the last page; omit to fall back to a\n * `rows.length < pageSize` heuristic. */\n totalCount?: number;\n onPageChange?: (page: number) => void;\n\n /** Field key currently sorted on. Omit to hide the sort control. */\n sortField?: string;\n sortDirection?: \"asc\" | \"desc\";\n onSortChange?: (field: string, direction: \"asc\" | \"desc\") => void;\n\n /** Shows the \"Select\" bulk-select mode toggle. */\n selectable?: boolean;\n selectedIds?: ReadonlySet<number>;\n onSelectionChange?: (selectedIds: Set<number>) => void;\n\n /**\n * Friendly empty state shown when there are no rows — pass one with a \"New\"\n * CTA (the list factory does this). Falls back to a simple default.\n */\n emptyState?: JSX.Element;\n}\n\nexport function CollectionList(props: CollectionListProps) {\n // Columns are derived once from the collection schema — the single source\n // of truth feeding BOTH the desktop <table> and the mobile card list below\n // (issue #25's mobile-first note). Sorting/pagination/selection stay\n // controlled by the consuming route (server-driven), so the table is\n // configured with just the core row model; its header/cell rendering is\n // driven through flexRender so a future custom cell renderer (links,\n // badges, thumbnails) is a per-column change, not a markup fork.\n const columns = (): ColumnDef<Row>[] =>\n listableFields(props.config).map(([key]) => ({\n id: key,\n accessorFn: (row) => row[key],\n header: key,\n cell: (info) => formatCellValue(info.getValue()),\n }));\n\n const table = createSolidTable<Row>({\n get data() {\n return props.rows;\n },\n get columns() {\n return columns();\n },\n getCoreRowModel: getCoreRowModel(),\n });\n\n const [selectMode, setSelectMode] = createSignal(false);\n\n function toggleSelected(id: number) {\n const next = new Set(props.selectedIds ?? []);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n props.onSelectionChange?.(next);\n }\n\n function handleRowActivate(row: Row) {\n if (selectMode()) {\n const id = rowId(row);\n if (id !== undefined) toggleSelected(id);\n return;\n }\n props.onRowClick?.(row);\n }\n\n return (\n <div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n <Show when={props.selectable}>\n <button\n type=\"button\"\n class=\"btn btn-outline btn-sm\"\n onClick={() => setSelectMode((v) => !v)}\n >\n {selectMode() ? \"Done\" : \"Select\"}\n </button>\n </Show>\n {/* Dropdown picker, not clickable column headers — sort works the\n same on touch and desktop, see issue #25's mobile-first note. */}\n <Show when={props.onSortChange}>\n <div class=\"join\">\n <select\n aria-label=\"Sort by\"\n class=\"select select-sm join-item\"\n value={props.sortField ?? \"\"}\n onChange={(e) =>\n props.onSortChange?.(\n e.currentTarget.value,\n props.sortDirection ?? \"asc\",\n )\n }\n >\n <For each={table.getAllColumns()}>\n {(column) => <option value={column.id}>{column.id}</option>}\n </For>\n </select>\n <select\n aria-label=\"Sort direction\"\n class=\"select select-sm join-item\"\n value={props.sortDirection ?? \"asc\"}\n onChange={(e) =>\n props.onSortChange?.(\n props.sortField ?? table.getAllColumns()[0]?.id ?? \"\",\n e.currentTarget.value as \"asc\" | \"desc\",\n )\n }\n >\n <option value=\"asc\">Ascending</option>\n <option value=\"desc\">Descending</option>\n </select>\n </div>\n </Show>\n </div>\n\n <Show\n when={props.rows.length > 0}\n fallback={\n props.emptyState ?? (\n <div class=\"border-base-300 rounded-box flex flex-col items-center gap-1 border border-dashed py-12 text-center\">\n <p class=\"text-base-content/70 m-0\">\n No {props.config.slug} yet.\n </p>\n </div>\n )\n }\n >\n {/* Table on desktop — hidden below md per the mobile-first card\n layout below, not the other way around. */}\n <table class=\"table hidden md:table\">\n <thead>\n <For each={table.getHeaderGroups()}>\n {(headerGroup) => (\n <tr>\n <Show when={selectMode()}>\n <th />\n </Show>\n <For each={headerGroup.headers}>\n {(header) => (\n <th>\n {flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n </th>\n )}\n </For>\n </tr>\n )}\n </For>\n </thead>\n <tbody>\n <For each={table.getRowModel().rows}>\n {(row) => (\n <tr\n class={\n props.onRowClick || selectMode()\n ? \"cursor-pointer hover\"\n : undefined\n }\n onClick={() => handleRowActivate(row.original)}\n >\n <Show when={selectMode()}>\n <td>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm\"\n onClick={(e) => e.stopPropagation()}\n checked={\n rowId(row.original) !== undefined &&\n (props.selectedIds?.has(\n rowId(row.original) as number,\n ) ??\n false)\n }\n onChange={() => {\n const id = rowId(row.original);\n if (id !== undefined) toggleSelected(id);\n }}\n />\n </td>\n </Show>\n <For each={row.getVisibleCells()}>\n {(cell) => (\n <td>\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </td>\n )}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n\n {/* Stacked card list on mobile/tablet — tap-to-select via an\n always-visible checkbox in select mode, never hover-revealed.\n Same table model as the desktop view, rendered as key/value rows. */}\n <div class=\"flex flex-col gap-2 md:hidden\">\n <For each={table.getRowModel().rows}>\n {(row) => (\n // biome-ignore lint/a11y/useSemanticElements: a native <button> can't contain interactive content (the select-mode checkbox below); role=\"button\" + tabIndex/onKeyDown is the standard fallback.\n <div\n class=\"card bg-base-200 cursor-pointer p-3\"\n role=\"button\"\n tabIndex={0}\n onClick={() => handleRowActivate(row.original)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleRowActivate(row.original);\n }\n }}\n >\n <div class=\"flex items-start gap-3\">\n <Show when={selectMode()}>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm mt-1\"\n onClick={(e) => e.stopPropagation()}\n checked={\n rowId(row.original) !== undefined &&\n (props.selectedIds?.has(\n rowId(row.original) as number,\n ) ??\n false)\n }\n onChange={() => {\n const id = rowId(row.original);\n if (id !== undefined) toggleSelected(id);\n }}\n />\n </Show>\n <div class=\"flex flex-1 flex-col gap-1\">\n <For each={row.getVisibleCells()}>\n {(cell) => (\n <div class=\"flex justify-between gap-2 text-sm\">\n <span class=\"opacity-60\">{cell.column.id}</span>\n <span class=\"text-right\">\n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n </span>\n </div>\n )}\n </For>\n </div>\n </div>\n </div>\n )}\n </For>\n </div>\n </Show>\n\n {/* Bottom-anchored prev/next bar — no page numbers, per issue #25's\n mobile-first note. Renders only when pagination is wired up. */}\n <Show when={props.page !== undefined && props.pageSize !== undefined}>\n <div class=\"bg-base-100 sticky bottom-0 flex items-center justify-between gap-2 border-t py-2\">\n <button\n type=\"button\"\n class=\"btn btn-sm\"\n disabled={(props.page ?? 1) <= 1}\n onClick={() => props.onPageChange?.((props.page ?? 1) - 1)}\n >\n Prev\n </button>\n <span class=\"text-sm opacity-70\">Page {props.page}</span>\n <button\n type=\"button\"\n class=\"btn btn-sm\"\n disabled={\n props.totalCount !== undefined\n ? (props.page ?? 1) * (props.pageSize ?? 0) >= props.totalCount\n : props.rows.length < (props.pageSize ?? 0)\n }\n onClick={() => props.onPageChange?.((props.page ?? 1) + 1)}\n >\n Next\n </button>\n </div>\n </Show>\n </div>\n );\n}\n","// Copyright (c) 2026 BowenLabs. All rights reserved.\n// Cadmea is MIT licensed. See LICENSE in the repo root.\n\nimport type { ImageCrop, ImageHotspot } from \"@thebes/cadmus/storage\";\nimport { createMemo, createSignal, Show } from \"solid-js\";\n\n/**\n * Image hotspot/crop editor widget (issue #17). A custom field widget for\n * `upload` image fields: upload an image, then click it to set the focal\n * point (hotspot) and optionally enter a crop region. Stores the value as a\n * JSON string `{ url, hotspot?, crop? }` in the same column (back-compatible\n * — a plain URL string still parses). Pair with `ImageService.render`'s\n * `hotspot`/`crop` args on the read side (see @thebes/cadmus-cloudflare-images).\n *\n * Register it via `createCollectionEditPage`/`CollectionEdit`'s `fieldWidgets`\n * option, keyed by the field name.\n */\n\nexport interface ImageWithHotspot {\n url: string;\n hotspot?: ImageHotspot;\n crop?: ImageCrop;\n}\n\nconst round2 = (n: number): number => Math.round(n * 100) / 100;\nconst clamp01 = (n: number): number => Math.min(1, Math.max(0, n));\n\n/**\n * Parse an upload-field value into `{ url, hotspot?, crop? }`. Accepts the\n * JSON object this widget writes, an already-parsed object, or a bare URL\n * string (legacy / non-hotspot uploads). Returns null for empty values.\n */\nexport function parseImageHotspotValue(\n value: unknown,\n): ImageWithHotspot | null {\n if (!value) return null;\n if (typeof value === \"object\") return value as ImageWithHotspot;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.startsWith(\"{\")) {\n try {\n return JSON.parse(trimmed) as ImageWithHotspot;\n } catch {\n // fall through to treating it as a plain URL\n }\n }\n return trimmed ? { url: trimmed } : null;\n }\n return null;\n}\n\n/** Serialize an {@link ImageWithHotspot} for storage in an upload field. */\nexport function serializeImageHotspotValue(value: ImageWithHotspot): string {\n return JSON.stringify(value);\n}\n\n/** Props every `fieldWidgets` widget receives from CollectionEdit. */\nexport interface FieldWidgetProps {\n fieldKey: string;\n value: unknown;\n setValue: (value: unknown) => void;\n onUploadFile?: (file: File) => Promise<{ url: string }>;\n}\n\nexport function ImageHotspotField(props: FieldWidgetProps) {\n const parsed = createMemo(() => parseImageHotspotValue(props.value));\n const [uploading, setUploading] = createSignal(false);\n const [error, setError] = createSignal<string>();\n\n const patch = (next: Partial<ImageWithHotspot>) => {\n const current = parsed() ?? { url: \"\" };\n props.setValue(serializeImageHotspotValue({ ...current, ...next }));\n };\n\n async function handleFile(e: Event & { currentTarget: HTMLInputElement }) {\n const file = e.currentTarget.files?.[0];\n if (!file) return;\n if (!props.onUploadFile) {\n setError(\"No upload handler configured for this form.\");\n return;\n }\n setUploading(true);\n setError(undefined);\n try {\n const { url } = await props.onUploadFile(file);\n patch({ url });\n } catch (err) {\n setError(err instanceof Error ? err.message : \"Upload failed\");\n } finally {\n setUploading(false);\n }\n }\n\n function handleImageClick(\n e: MouseEvent & { currentTarget: HTMLImageElement },\n ) {\n const rect = e.currentTarget.getBoundingClientRect();\n const x = clamp01((e.clientX - rect.left) / rect.width);\n const y = clamp01((e.clientY - rect.top) / rect.height);\n patch({ hotspot: { x: round2(x), y: round2(y) } });\n }\n\n const crop = () => parsed()?.crop ?? { top: 0, right: 0, bottom: 0, left: 0 };\n const setCrop = (edge: keyof ImageCrop, raw: string) => {\n patch({ crop: { ...crop(), [edge]: clamp01(Number(raw) || 0) } });\n };\n\n return (\n <div class=\"flex flex-col gap-3\">\n <input\n id={props.fieldKey}\n class=\"file-input\"\n type=\"file\"\n accept=\"image/*\"\n disabled={uploading()}\n onChange={handleFile}\n />\n <Show when={uploading()}>\n <span class=\"loading loading-spinner loading-sm\" />\n </Show>\n <Show when={error()}>\n <p class=\"text-sm text-error\">{error()}</p>\n </Show>\n\n <Show when={parsed()?.url}>\n {(url) => (\n <div class=\"flex flex-col gap-2\">\n <p class=\"text-xs opacity-60\">\n Click the image to set the focal point.\n </p>\n <div class=\"relative inline-block max-w-md\">\n {/* biome-ignore lint/a11y/noStaticElementInteractions: the image is the hotspot-picking surface */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: pointer-based focal-point picker; numeric inputs below are the keyboard-accessible path */}\n <img\n src={url()}\n alt=\"Set focal point\"\n class=\"block w-full cursor-crosshair rounded\"\n onClick={handleImageClick}\n />\n <Show when={parsed()?.hotspot}>\n {(hs) => (\n <span\n class=\"pointer-events-none absolute h-4 w-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white bg-[var(--accent,#56c6be)] shadow\"\n style={{\n left: `${hs().x * 100}%`,\n top: `${hs().y * 100}%`,\n }}\n />\n )}\n </Show>\n </div>\n\n <details class=\"text-sm\">\n <summary class=\"cursor-pointer opacity-70\">\n Crop (advanced)\n </summary>\n <div class=\"mt-2 grid grid-cols-4 gap-2\">\n {([\"top\", \"right\", \"bottom\", \"left\"] as const).map((edge) => (\n <label class=\"flex flex-col gap-1 text-xs\">\n <span class=\"capitalize opacity-70\">{edge}</span>\n <input\n class=\"input input-sm\"\n type=\"number\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n value={crop()[edge]}\n onInput={(e) => setCrop(edge, e.currentTarget.value)}\n />\n </label>\n ))}\n </div>\n </details>\n\n <p class=\"break-all text-xs opacity-50\">{url()}</p>\n </div>\n )}\n </Show>\n </div>\n );\n}\n","import {\n createEffect,\n createSignal,\n For,\n type JSX,\n onCleanup,\n Show,\n} from \"solid-js\";\n\nexport interface SearchPaletteResult {\n collection: string;\n id: number;\n label: string;\n}\n\nexport interface SearchPaletteProps {\n /** Runs a query against `LocalApi.search()` for every searchable collection — see `@thebes/cadmus/cms`'s `getCollectionsMeta`. */\n onSearch: (query: string) => Promise<SearchPaletteResult[]>;\n /** Navigates to the chosen result; the palette closes itself afterward. */\n onSelect: (result: SearchPaletteResult) => void;\n}\n\nconst DEBOUNCE_MS = 200;\n\nfunction capitalize(value: string): string {\n return value.length === 0 ? value : value[0].toUpperCase() + value.slice(1);\n}\n\n/**\n * Self-contained Cmd+K (Ctrl+K on non-Mac) search palette — issue #29.\n * Owns its own open/closed state and keyboard listener; the host app only\n * supplies `onSearch` (wired to a server function that fans out across\n * every collection with `search` configured) and `onSelect` (navigation).\n * Mirrors PanelNav's focus-trap-on-open / restore-focus-on-close pattern\n * rather than introducing a second one.\n */\nexport function SearchPalette(props: SearchPaletteProps): JSX.Element {\n const [open, setOpen] = createSignal(false);\n const [query, setQuery] = createSignal(\"\");\n const [results, setResults] = createSignal<SearchPaletteResult[]>([]);\n const [activeIndex, setActiveIndex] = createSignal(0);\n let inputRef: HTMLInputElement | undefined;\n let triggeredBy: HTMLElement | null = null;\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\n // Guards a result fetch that resolves after a newer one was already\n // kicked off (or after the palette closed) from clobbering fresher\n // results with stale ones.\n let latestQueryToken = 0;\n\n function close() {\n setOpen(false);\n setQuery(\"\");\n setResults([]);\n triggeredBy?.focus();\n }\n\n function runSearch(value: string) {\n const token = ++latestQueryToken;\n if (value.trim().length < 2) {\n setResults([]);\n return;\n }\n props.onSearch(value).then((found) => {\n if (token !== latestQueryToken) return;\n setResults(found);\n setActiveIndex(0);\n });\n }\n\n function onInput(value: string) {\n setQuery(value);\n clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => runSearch(value), DEBOUNCE_MS);\n }\n\n function selectResult(result: SearchPaletteResult | undefined) {\n if (!result) return;\n props.onSelect(result);\n close();\n }\n\n // Global Cmd+K / Ctrl+K listener — registered once, independent of\n // `open` (unlike PanelNav's Escape/Tab handling, which only needs to\n // exist while open).\n createEffect(() => {\n function onGlobalKeyDown(event: KeyboardEvent) {\n if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n event.preventDefault();\n triggeredBy = document.activeElement as HTMLElement | null;\n setOpen(true);\n }\n }\n document.addEventListener(\"keydown\", onGlobalKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onGlobalKeyDown));\n });\n\n createEffect(() => {\n if (open()) inputRef?.focus();\n });\n\n function onDialogKeyDown(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n close();\n return;\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setActiveIndex((i) => Math.min(i + 1, results().length - 1));\n return;\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n return;\n }\n if (event.key === \"Enter\") {\n event.preventDefault();\n selectResult(results()[activeIndex()]);\n }\n }\n\n return (\n <Show when={open()}>\n <div\n aria-hidden=\"true\"\n class=\"fixed inset-0 z-50 flex items-start justify-center bg-[var(--color-backdrop)] px-4 pt-[15vh]\"\n onClick={close}\n >\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Search\"\n class=\"w-full max-w-lg overflow-hidden rounded-2xl border border-[var(--line)] bg-[var(--surface-strong)] shadow-2xl\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={onDialogKeyDown}\n >\n <div class=\"flex items-center gap-2 border-b border-[var(--line)] px-4 py-3\">\n <i\n class=\"ph ph-magnifying-glass text-lg text-[var(--sea-ink-soft)]\"\n aria-hidden=\"true\"\n />\n <input\n ref={inputRef}\n type=\"text\"\n value={query()}\n onInput={(event) => onInput(event.currentTarget.value)}\n placeholder=\"Search…\"\n aria-label=\"Search\"\n class=\"flex-1 bg-transparent text-base text-[var(--sea-ink)] outline-none placeholder:text-[var(--sea-ink-soft)]\"\n />\n <kbd class=\"rounded border border-[var(--chip-line)] bg-[var(--chip-bg)] px-1.5 py-0.5 text-xs text-[var(--sea-ink-soft)]\">\n Esc\n </kbd>\n </div>\n\n <Show\n when={results().length > 0}\n fallback={\n <p class=\"px-4 py-6 text-center text-sm text-[var(--sea-ink-soft)]\">\n {query().trim().length < 2\n ? \"Keep typing to search…\"\n : \"No results\"}\n </p>\n }\n >\n <ul class=\"max-h-80 overflow-y-auto py-2\">\n <For each={results()}>\n {(result, index) => (\n <li>\n <button\n type=\"button\"\n onClick={() => selectResult(result)}\n onMouseEnter={() => setActiveIndex(index())}\n class=\"flex w-full items-center justify-between gap-3 px-4 py-2 text-left text-sm text-[var(--sea-ink)] hover:bg-[var(--link-bg-hover)]\"\n classList={{\n \"bg-[var(--link-bg-hover)]\": activeIndex() === index(),\n }}\n >\n <span class=\"truncate\">{result.label}</span>\n <span class=\"shrink-0 text-xs text-[var(--sea-ink-soft)]\">\n {capitalize(result.collection)}\n </span>\n </button>\n </li>\n )}\n </For>\n </ul>\n </Show>\n </div>\n </div>\n </Show>\n );\n}\n","// Copyright (c) 2026 BowenLabs. All rights reserved.\n// Cadmea is MIT licensed. See LICENSE in the repo root.\n\nimport {\n type EditRef,\n PREVIEW_VALUES_MESSAGE,\n type PreviewValuesMessage,\n VISUAL_EDIT_MESSAGE,\n type VisualEditingMessage,\n} from \"@thebes/cadmus/cms\";\nimport { createEffect, onCleanup, onMount } from \"solid-js\";\n\n/**\n * Visual-editing preview pane (issue #15, studio side). Embeds the site's\n * preview in an iframe and listens for the click-to-edit `postMessage` that\n * `@thebes/cadmus/cms`'s `mountVisualEditing` posts from inside the preview.\n * On a click, it calls `onEdit(ref)` so the studio can navigate to that\n * field's editor (e.g. `/admin/<collection>/<id>`).\n *\n * The preview page must (a) tag editable regions with `editAttr(...)` and\n * (b) call `mountVisualEditing()` client-side. This component is the parent\n * half of that handshake.\n */\nexport interface VisualEditingPaneProps {\n /** URL of the preview route to embed. */\n src: string;\n /** Called when an editable region in the preview is clicked. */\n onEdit?: (ref: EditRef) => void;\n /**\n * Origin the preview is served from — messages from any other origin are\n * ignored (postMessage security). Defaults to `src`'s origin.\n */\n allowedOrigin?: string;\n /** Class for the iframe (size it via the consumer's layout). */\n class?: string;\n title?: string;\n /**\n * In-progress form values to push into the preview for as-you-type live\n * updates. Posted to the iframe on every change; the preview page must call\n * `mountPreviewSync` to receive them. Requires `previewTarget`.\n */\n previewValues?: Record<string, unknown>;\n /** Which document `previewValues` belong to (matched by the preview). */\n previewTarget?: { collection: string; id: number };\n}\n\nfunction originOf(url: string): string | undefined {\n try {\n return new URL(url).origin;\n } catch {\n return undefined;\n }\n}\n\nexport function VisualEditingPane(props: VisualEditingPaneProps) {\n let iframe: HTMLIFrameElement | undefined;\n const targetOrigin = () => props.allowedOrigin ?? originOf(props.src) ?? \"*\";\n\n onMount(() => {\n const expected = props.allowedOrigin ?? originOf(props.src);\n const handler = (event: MessageEvent) => {\n // Same-origin-only: drop messages from any other window/origin.\n if (expected && event.origin !== expected) return;\n const data = event.data as Partial<VisualEditingMessage> | null;\n if (data?.type === VISUAL_EDIT_MESSAGE && data.ref) {\n props.onEdit?.(data.ref);\n }\n };\n window.addEventListener(\"message\", handler);\n onCleanup(() => window.removeEventListener(\"message\", handler));\n });\n\n // As-you-type live preview: push the latest form values into the iframe on\n // every change. The preview page's mountPreviewSync patches its tagged\n // text regions in response.\n createEffect(() => {\n const values = props.previewValues;\n const target = props.previewTarget;\n const win = iframe?.contentWindow;\n if (!values || !target || !win) return;\n const message: PreviewValuesMessage = {\n type: PREVIEW_VALUES_MESSAGE,\n collection: target.collection,\n id: target.id,\n values,\n };\n win.postMessage(message, targetOrigin());\n });\n\n return (\n <iframe\n ref={(el) => {\n iframe = el;\n }}\n src={props.src}\n title={props.title ?? \"Preview\"}\n class={props.class ?? \"h-full w-full border-0\"}\n />\n );\n}\n"],"mappings":"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"}