@elytracms/studio 0.0.79 → 0.0.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/convex/contract-parity.test.ts +1 -1
- package/convex/functions.ts +13 -3
- package/convex/http-routes.test.ts +143 -0
- package/convex/http.ts +19 -9
- package/convex/schema.ts +0 -19
- package/convex/users.ts +1 -1
- package/dist/components/app-views/default-modules.d.ts +141 -44
- package/dist/components/app-views/default-modules.js +229 -65
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/app-views/module.d.ts +38 -0
- package/dist/components/app-views/module.js.map +1 -1
- package/dist/components/app-views/sidebar.d.ts +5 -2
- package/dist/components/app-views/sidebar.js +16 -5
- package/dist/components/app-views/sidebar.js.map +1 -1
- package/dist/components/app-views/studio-config.d.ts +27 -0
- package/dist/components/app-views/studio-config.js.map +1 -1
- package/dist/components/builder/canvas-render-context.js +7 -1
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/reuse-context.js +7 -1
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.d.ts +94 -16
- package/dist/components/builder/reuse.js +201 -19
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/cms/bulk-actions.js +3 -1
- package/dist/components/cms/bulk-actions.js.map +1 -1
- package/dist/components/cms/cell-edit.js +6 -2
- package/dist/components/cms/cell-edit.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +40 -13
- package/dist/components/cms/cms-store.js +50 -22
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +2 -2
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/date-input-core.d.ts +21 -0
- package/dist/components/cms/date-input-core.js +20 -0
- package/dist/components/cms/date-input-core.js.map +1 -1
- package/dist/components/cms/date-input.d.ts +9 -1
- package/dist/components/cms/date-input.js +2 -2
- package/dist/components/cms/date-input.js.map +1 -1
- package/dist/components/cms/detail-editor.js +11 -5
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/editable-cell.js +2 -1
- package/dist/components/cms/editable-cell.js.map +1 -1
- package/dist/components/cms/field-control.js +4 -2
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/field-renderer.js +8 -1
- package/dist/components/cms/field-renderer.js.map +1 -1
- package/dist/components/cms/import-export.js +2 -1
- package/dist/components/cms/import-export.js.map +1 -1
- package/dist/components/cms/issues-pane.d.ts +4 -2
- package/dist/components/cms/issues-pane.js +6 -4
- package/dist/components/cms/issues-pane.js.map +1 -1
- package/dist/components/cms/scalar-value-editor.js +2 -1
- package/dist/components/cms/scalar-value-editor.js.map +1 -1
- package/dist/components/components/transfer-dialog.js +10 -12
- package/dist/components/components/transfer-dialog.js.map +1 -1
- package/dist/components/project-list.d.ts +9 -3
- package/dist/components/project-list.js +11 -5
- package/dist/components/project-list.js.map +1 -1
- package/dist/components/project-switcher.d.ts +3 -1
- package/dist/components/project-switcher.js +4 -2
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/components/redirects/redirects-store.d.ts +21 -0
- package/dist/components/redirects/redirects-store.js +17 -4
- package/dist/components/redirects/redirects-store.js.map +1 -1
- package/dist/components/section-nav.js +102 -4
- package/dist/components/section-nav.js.map +1 -1
- package/dist/customization.d.ts +7 -0
- package/dist/customization.js.map +1 -1
- package/dist/lib/data/collection-content.d.ts +6 -1
- package/dist/lib/data/collection-content.js +50 -12
- package/dist/lib/data/collection-content.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +132 -0
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +103 -0
- package/dist/lib/i18n/messages.en.js +146 -0
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/locale/binding-fallback.d.ts +8 -1
- package/dist/lib/locale/binding-fallback.js +8 -1
- package/dist/lib/locale/binding-fallback.js.map +1 -1
- package/dist/lib/locale/locale-store.d.ts +41 -9
- package/dist/lib/locale/locale-store.js +34 -15
- package/dist/lib/locale/locale-store.js.map +1 -1
- package/dist/lib/locale/locale-switcher.d.ts +3 -1
- package/dist/lib/locale/locale-switcher.js +4 -2
- package/dist/lib/locale/locale-switcher.js.map +1 -1
- package/dist/lib/locale/use-studio-locale.d.ts +9 -4
- package/dist/lib/locale/use-studio-locale.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.d.ts +1 -3
- package/dist/lib/persistence/convex-adapter.js +0 -55
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/persona/labels.d.ts +42 -1
- package/dist/lib/persona/labels.js +57 -0
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/routes/route-issues.d.ts +9 -0
- package/dist/lib/routes/route-issues.js +117 -0
- package/dist/lib/routes/route-issues.js.map +1 -0
- package/dist/lib/workspace/config-issues.d.ts +54 -0
- package/dist/lib/workspace/config-issues.js +70 -0
- package/dist/lib/workspace/config-issues.js.map +1 -0
- package/dist/lib/workspace/index.d.ts +9 -0
- package/dist/lib/workspace/index.js +11 -0
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/lib/workspace/switcher-source.d.ts +20 -3
- package/dist/lib/workspace/switcher-source.js.map +1 -1
- package/package.json +2 -2
- package/convex/cliTokens.ts +0 -63
- package/convex/sync.ts +0 -297
|
@@ -8,6 +8,7 @@ import { editCreatesVariant, resolveDisplayedValue } from '@elytracms/studio/lib
|
|
|
8
8
|
import { applyAssetSelection, singleAssetIdOf } from '../assets/asset-selection.js';
|
|
9
9
|
import { CellValue, toRefArray } from './cell.js';
|
|
10
10
|
import { DateInput } from './date-input.js';
|
|
11
|
+
import { datePickerBounds } from './date-input-core.js';
|
|
11
12
|
import { cellEditKind, cellKey } from './cell-edit.js';
|
|
12
13
|
import { fieldLabel } from './cms-labels.js';
|
|
13
14
|
import { useCollectionView } from '../collection-view/collection-view-context.js';
|
|
@@ -146,7 +147,7 @@ function CellEditorControl({ field, draft, onDraft, }) {
|
|
|
146
147
|
// EC-463: the shared date control. The cell's own draft already commits on
|
|
147
148
|
// Enter/Tab/blur, so what this adds here is the working insert/paste path
|
|
148
149
|
// and the guard against a re-render clobbering half-typed segments.
|
|
149
|
-
return (_jsx(DateInput, { autoFocus: true, value: typeof draft === 'string' ? draft : '', onChange: (stored) => onDraft(stored ? stored.slice(0, 10) : ''), className: "h-7 text-sm", testId: "cell-editor-date" }));
|
|
150
|
+
return (_jsx(DateInput, { autoFocus: true, value: typeof draft === 'string' ? draft : '', onChange: (stored) => onDraft(stored ? stored.slice(0, 10) : ''), className: "h-7 text-sm", testId: "cell-editor-date", ...datePickerBounds(field.validation) }));
|
|
150
151
|
case 'select':
|
|
151
152
|
if (field.multiple) {
|
|
152
153
|
return _jsx(MultiSelectControl, { field: field, draft: draft, onDraft: onDraft });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editable-cell.js","sourceRoot":"","sources":["../../../src/components/cms/editable-cell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useRef, useState } from 'react'\nimport type { FocusEvent, KeyboardEvent, ReactNode } from 'react'\nimport { isFieldLocalized } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, FieldDef, Locale, SelectFieldDef } from '@elytracms/core/cms-core'\nimport { Badge, Input, Row, Select, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { editCreatesVariant, resolveDisplayedValue } from '@elytracms/studio/lib/locale'\nimport { applyAssetSelection, singleAssetIdOf } from '../assets/asset-selection'\nimport { CellValue, toRefArray } from './cell'\nimport { DateInput } from './date-input'\nimport { cellEditKind, cellKey } from './cell-edit'\nimport { fieldLabel } from './cms-labels'\nimport type { AdvanceDirection } from './cell-edit'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { RelationPicker } from './relation-picker'\nimport { AssetPicker } from './asset-picker'\n\n/**\n * One editable table cell (EC-168, the Airtable-feel wedge of vision 3.2).\n *\n * Renders the field's `CellValue` until activated (click / Enter / F2), then\n * swaps to an inline editor (text, number, boolean, select, date) or opens the\n * existing relation/asset picker from the cell. Commits flow through the\n * table's cell-edit controller; rejections render as an error ring + message\n * on this cell — never a toast.\n */\nexport function EditableCell({\n collection,\n doc,\n field,\n editing,\n busy,\n errorMessage,\n onStartEdit,\n onCancel,\n onCommit,\n}: {\n collection: CollectionDef\n doc: CmsDocument\n field: FieldDef\n editing: boolean\n busy: boolean\n errorMessage: string | null\n onStartEdit: () => void\n onCancel: () => void\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n}) {\n const source = useCollectionView()\n // Inline editing is a capability. EC-463: the gate used to sit only on the\n // Tab-advance list, so a rail WITHOUT it (redirects, users, the self-account\n // view) still rendered focusable, clickable, editor-opening cells whose commit\n // then hit \"no `inlineEditing.commitField` → close without dispatching\" — the\n // edit was accepted on screen and silently thrown away. A read-only rail now\n // really does yield no editable cells.\n const kind = source.capabilities.inlineEdit\n ? cellEditKind(field, source.isFieldReadOnly(field))\n : 'none'\n // The table's locale resolution (EC-176): the cell displays the AMBIENT\n // active locale (EC-018 fallback applied) and edits write that locale only.\n // Editing a fallback-shown value therefore creates the localized variant —\n // the fallback locale's value is never mutated.\n const locale = source.activeLocale\n const localized = isFieldLocalized(collection, field.name)\n const { value, fallback } = resolveDisplayedValue(\n collection,\n doc,\n field.name,\n locale,\n source.localeConfig,\n )\n const key = cellKey({ docId: doc.id, field: field.name })\n\n if (editing && kind === 'inline') {\n return (\n <CellEditorFrame\n locale={localized ? locale : null}\n createsLocalizedVariant={\n fallback !== null &&\n editCreatesVariant(collection, doc, field.name, locale, source.localeConfig)\n }\n cellKeyId={key}\n >\n <InlineCellEditor field={field} value={value} busy={busy} onCommit={onCommit} onCancel={onCancel} />\n </CellEditorFrame>\n )\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n // EC-463: Space too — it is half of the native activation contract the\n // `role=\"button\"` this cell now carries promises.\n if (event.key === 'Enter' || event.key === 'F2' || event.key === ' ') {\n event.preventDefault()\n onStartEdit()\n }\n }\n\n const editable = kind !== 'none'\n return (\n <div\n data-cell-key={key}\n data-testid={`cell-${key}`}\n tabIndex={editable ? 0 : undefined}\n // EC-463: an editable cell WAS an anonymous focusable `div` — the\n // accessibility tree listed it as a nameless \"generic, clickable\", so\n // neither a screen reader nor an agent editor could tell what activating it\n // would edit. It is an activation surface, so it says so and names itself.\n role={editable ? 'button' : undefined}\n aria-label={\n editable\n ? translate('cms.cell.editAria', {\n field: fieldLabel(field),\n title: source.titleOf({ collection: collection.id, id: doc.id }),\n })\n : undefined\n }\n // While a picker cell is editing, the dialog renders inside this div. React\n // bubbles portal events through the COMPONENT tree, so a click on the picker\n // (e.g. its ✕) would re-fire onStartEdit and reopen it — hence the `editing`\n // guard. ESC/click-outside dodge this (keydown / close-on-pointerdown).\n onClick={kind === 'none' || editing ? undefined : onStartEdit}\n onKeyDown={kind === 'none' || editing ? undefined : handleKeyDown}\n aria-invalid={errorMessage ? true : undefined}\n className={cn(\n '-mx-1.5 min-h-7 rounded-md px-1.5 py-0.5 outline-none',\n kind !== 'none' &&\n 'cursor-pointer transition-colors hover:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring/50',\n errorMessage && 'bg-destructive/5 ring-2 ring-inset ring-destructive/60',\n busy && 'opacity-60',\n )}\n >\n <CellValue collection={collection} doc={doc} field={field} />\n {errorMessage ? (\n <Text size=\"xs\" className=\"mt-0.5 text-destructive\" data-testid={`cell-error-${key}`}>\n {errorMessage}\n </Text>\n ) : null}\n {editing && kind === 'picker' ? (\n <CellPicker field={field} value={value} onCommit={onCommit} onCancel={onCancel} />\n ) : null}\n </div>\n )\n}\n\n/**\n * Editing chrome: marks the edited locale at the point of edit (EC-018), and\n * says so explicitly when committing will CREATE the active locale's variant\n * from a fallback-shown value (EC-176) — translation is a visible act.\n */\nfunction CellEditorFrame({\n locale,\n createsLocalizedVariant = false,\n cellKeyId,\n children,\n}: {\n locale: Locale | null\n /** True when the cell showed a fallback — committing creates the variant. */\n createsLocalizedVariant?: boolean\n cellKeyId: string\n children: ReactNode\n}) {\n return (\n <Row gap=\"1\" align=\"center\" data-cell-key={cellKeyId} className=\"-mx-1.5 min-w-[9rem]\">\n {locale ? (\n <Badge\n variant={createsLocalizedVariant ? 'info' : 'outline'}\n className=\"uppercase\"\n data-testid=\"cell-editing-locale\"\n title={\n createsLocalizedVariant\n ? translate('cms.cell.createsVariantTitle', { locale: locale.toUpperCase() })\n : undefined\n }\n >\n {locale}\n {createsLocalizedVariant ? (\n <span className=\"lowercase\"> · {translate('cms.cell.newVariant')}</span>\n ) : null}\n </Badge>\n ) : null}\n {children}\n </Row>\n )\n}\n\ntype CellDraft = string | boolean | string[]\n\n/**\n * The in-cell editor: draft → commit on Enter (advance down), Tab/Shift-Tab\n * (advance next/prev) or blur; Esc cancels without dispatching anything.\n */\nfunction InlineCellEditor({\n field,\n value,\n busy,\n onCommit,\n onCancel,\n}: {\n field: FieldDef\n value: unknown\n busy: boolean\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n onCancel: () => void\n}) {\n const [draft, setDraft] = useState<CellDraft>(() => initialDraft(field, value))\n const draftRef = useRef(draft)\n draftRef.current = draft\n // EC-463: the ref moves SYNCHRONOUSLY with the control, not at the next\n // render. A control that only emits its final value on the settling keystroke\n // (the date control's Enter) would otherwise be committed one render stale —\n // the same event that produces the value also triggers `commit()` below.\n function updateDraft(next: CellDraft) {\n draftRef.current = next\n setDraft(next)\n }\n // Each editor instance settles exactly once (Tab keydown + the blur it\n // causes must not commit twice).\n const settledRef = useRef(false)\n\n function commit(advance: AdvanceDirection | null) {\n if (settledRef.current) return\n settledRef.current = true\n onCommit(draftValue(field, draftRef.current), advance)\n }\n\n function cancel() {\n if (settledRef.current) return\n settledRef.current = true\n onCancel()\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key === 'Enter') {\n event.preventDefault()\n commit('down')\n } else if (event.key === 'Tab') {\n event.preventDefault()\n commit(event.shiftKey ? 'prev' : 'next')\n } else if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n cancel()\n }\n }\n\n function handleBlur(event: FocusEvent<HTMLDivElement>) {\n // Focus left the editor entirely (e.g. a click elsewhere) → commit in place.\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) commit(null)\n }\n\n return (\n <div\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onClick={(event) => event.stopPropagation()}\n className=\"min-w-0 flex-1\"\n data-testid=\"cell-editor\"\n aria-busy={busy || undefined}\n >\n <CellEditorControl field={field} draft={draft} onDraft={updateDraft} />\n </div>\n )\n}\n\n/** The actual input for the field type (compact, table-density variants). */\nfunction CellEditorControl({\n field,\n draft,\n onDraft,\n}: {\n field: FieldDef\n draft: CellDraft\n onDraft: (draft: CellDraft) => void\n}) {\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-7 items-center gap-2 text-sm\">\n <input\n autoFocus\n type=\"checkbox\"\n checked={draft === true}\n onChange={(event) => onDraft(event.target.checked)}\n className=\"size-4 accent-primary\"\n data-testid=\"cell-editor-boolean\"\n />\n <Text as=\"span\" size=\"xs\" tone=\"muted\">\n {draft === true ? translate('common.true') : translate('common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n autoFocus\n type=\"number\"\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 text-sm\"\n data-testid=\"cell-editor-number\"\n />\n )\n case 'date':\n // EC-463: the shared date control. The cell's own draft already commits on\n // Enter/Tab/blur, so what this adds here is the working insert/paste path\n // and the guard against a re-render clobbering half-typed segments.\n return (\n <DateInput\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(stored) => onDraft(stored ? stored.slice(0, 10) : '')}\n className=\"h-7 text-sm\"\n testId=\"cell-editor-date\"\n />\n )\n case 'select':\n if (field.multiple) {\n return <MultiSelectControl field={field} draft={draft} onDraft={onDraft} />\n }\n return (\n <Select\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 py-0 text-sm\"\n data-testid=\"cell-editor-select\"\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n default:\n return (\n <Input\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 text-sm\"\n data-testid=\"cell-editor-text\"\n />\n )\n }\n}\n\nfunction MultiSelectControl({\n field,\n draft,\n onDraft,\n}: {\n field: SelectFieldDef\n draft: CellDraft\n onDraft: (draft: CellDraft) => void\n}) {\n const selected = Array.isArray(draft) ? draft : []\n return (\n <Row gap=\"2\" wrap data-testid=\"cell-editor-multiselect\">\n {field.options.map((opt, index) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-xs\">\n <input\n autoFocus={index === 0}\n type=\"checkbox\"\n checked={on}\n onChange={() =>\n onDraft(on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value])\n }\n className=\"size-3.5 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n}\n\n/** Relation/asset cells reuse the existing lightweight pickers, opened from the cell. */\nfunction CellPicker({\n field,\n value,\n onCommit,\n onCancel,\n}: {\n field: FieldDef\n value: unknown\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n onCancel: () => void\n}) {\n if (field.type === 'relation') {\n return (\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={toRefArray(value)}\n open\n onOpenChange={(open) => {\n if (!open) onCancel()\n }}\n onChange={(refs) => onCommit(field.multiple ? refs : refs[0], null)}\n />\n )\n }\n if (field.type === 'asset') {\n return (\n <AssetPicker\n value={field.multiple === false ? singleAssetIdOf(value) : null}\n open\n onOpenChange={(open) => {\n if (!open) onCancel()\n }}\n onChange={(picked) => onCommit(applyAssetSelection(value, picked, field.multiple), null)}\n />\n )\n }\n return null\n}\n\n// --- Draft <-> stored value mapping (mirrors `FieldControl`'s conventions) -----\n\nfunction initialDraft(field: FieldDef, value: unknown): CellDraft {\n switch (field.type) {\n case 'boolean':\n return value === true\n case 'number':\n return typeof value === 'number' ? String(value) : ''\n case 'date':\n return typeof value === 'string' ? value.slice(0, 10) : ''\n case 'select':\n if (field.multiple) {\n return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : []\n }\n return typeof value === 'string' ? value : ''\n default:\n return typeof value === 'string' ? value : ''\n }\n}\n\nfunction draftValue(field: FieldDef, draft: CellDraft): unknown {\n switch (field.type) {\n case 'boolean':\n return draft === true\n case 'number':\n return draft === '' ? undefined : Number(draft)\n case 'date':\n return draft === '' || typeof draft !== 'string' ? undefined : `${draft}T00:00:00.000Z`\n case 'select':\n if (field.multiple) return Array.isArray(draft) ? draft : []\n return draft === '' ? undefined : draft\n default:\n return draft === '' ? undefined : draft\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editable-cell.js","sourceRoot":"","sources":["../../../src/components/cms/editable-cell.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useRef, useState } from 'react'\nimport type { FocusEvent, KeyboardEvent, ReactNode } from 'react'\nimport { isFieldLocalized } from '@elytracms/core/cms-core'\nimport type { CmsDocument, CollectionDef, FieldDef, Locale, SelectFieldDef } from '@elytracms/core/cms-core'\nimport { Badge, Input, Row, Select, Text } from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { editCreatesVariant, resolveDisplayedValue } from '@elytracms/studio/lib/locale'\nimport { applyAssetSelection, singleAssetIdOf } from '../assets/asset-selection'\nimport { CellValue, toRefArray } from './cell'\nimport { DateInput } from './date-input'\nimport { datePickerBounds } from './date-input-core'\nimport { cellEditKind, cellKey } from './cell-edit'\nimport { fieldLabel } from './cms-labels'\nimport type { AdvanceDirection } from './cell-edit'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { RelationPicker } from './relation-picker'\nimport { AssetPicker } from './asset-picker'\n\n/**\n * One editable table cell (EC-168, the Airtable-feel wedge of vision 3.2).\n *\n * Renders the field's `CellValue` until activated (click / Enter / F2), then\n * swaps to an inline editor (text, number, boolean, select, date) or opens the\n * existing relation/asset picker from the cell. Commits flow through the\n * table's cell-edit controller; rejections render as an error ring + message\n * on this cell — never a toast.\n */\nexport function EditableCell({\n collection,\n doc,\n field,\n editing,\n busy,\n errorMessage,\n onStartEdit,\n onCancel,\n onCommit,\n}: {\n collection: CollectionDef\n doc: CmsDocument\n field: FieldDef\n editing: boolean\n busy: boolean\n errorMessage: string | null\n onStartEdit: () => void\n onCancel: () => void\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n}) {\n const source = useCollectionView()\n // Inline editing is a capability. EC-463: the gate used to sit only on the\n // Tab-advance list, so a rail WITHOUT it (redirects, users, the self-account\n // view) still rendered focusable, clickable, editor-opening cells whose commit\n // then hit \"no `inlineEditing.commitField` → close without dispatching\" — the\n // edit was accepted on screen and silently thrown away. A read-only rail now\n // really does yield no editable cells.\n const kind = source.capabilities.inlineEdit\n ? cellEditKind(field, source.isFieldReadOnly(field))\n : 'none'\n // The table's locale resolution (EC-176): the cell displays the AMBIENT\n // active locale (EC-018 fallback applied) and edits write that locale only.\n // Editing a fallback-shown value therefore creates the localized variant —\n // the fallback locale's value is never mutated.\n const locale = source.activeLocale\n const localized = isFieldLocalized(collection, field.name)\n const { value, fallback } = resolveDisplayedValue(\n collection,\n doc,\n field.name,\n locale,\n source.localeConfig,\n )\n const key = cellKey({ docId: doc.id, field: field.name })\n\n if (editing && kind === 'inline') {\n return (\n <CellEditorFrame\n locale={localized ? locale : null}\n createsLocalizedVariant={\n fallback !== null &&\n editCreatesVariant(collection, doc, field.name, locale, source.localeConfig)\n }\n cellKeyId={key}\n >\n <InlineCellEditor field={field} value={value} busy={busy} onCommit={onCommit} onCancel={onCancel} />\n </CellEditorFrame>\n )\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n // EC-463: Space too — it is half of the native activation contract the\n // `role=\"button\"` this cell now carries promises.\n if (event.key === 'Enter' || event.key === 'F2' || event.key === ' ') {\n event.preventDefault()\n onStartEdit()\n }\n }\n\n const editable = kind !== 'none'\n return (\n <div\n data-cell-key={key}\n data-testid={`cell-${key}`}\n tabIndex={editable ? 0 : undefined}\n // EC-463: an editable cell WAS an anonymous focusable `div` — the\n // accessibility tree listed it as a nameless \"generic, clickable\", so\n // neither a screen reader nor an agent editor could tell what activating it\n // would edit. It is an activation surface, so it says so and names itself.\n role={editable ? 'button' : undefined}\n aria-label={\n editable\n ? translate('cms.cell.editAria', {\n field: fieldLabel(field),\n title: source.titleOf({ collection: collection.id, id: doc.id }),\n })\n : undefined\n }\n // While a picker cell is editing, the dialog renders inside this div. React\n // bubbles portal events through the COMPONENT tree, so a click on the picker\n // (e.g. its ✕) would re-fire onStartEdit and reopen it — hence the `editing`\n // guard. ESC/click-outside dodge this (keydown / close-on-pointerdown).\n onClick={kind === 'none' || editing ? undefined : onStartEdit}\n onKeyDown={kind === 'none' || editing ? undefined : handleKeyDown}\n aria-invalid={errorMessage ? true : undefined}\n className={cn(\n '-mx-1.5 min-h-7 rounded-md px-1.5 py-0.5 outline-none',\n kind !== 'none' &&\n 'cursor-pointer transition-colors hover:bg-muted/70 focus-visible:ring-2 focus-visible:ring-ring/50',\n errorMessage && 'bg-destructive/5 ring-2 ring-inset ring-destructive/60',\n busy && 'opacity-60',\n )}\n >\n <CellValue collection={collection} doc={doc} field={field} />\n {errorMessage ? (\n <Text size=\"xs\" className=\"mt-0.5 text-destructive\" data-testid={`cell-error-${key}`}>\n {errorMessage}\n </Text>\n ) : null}\n {editing && kind === 'picker' ? (\n <CellPicker field={field} value={value} onCommit={onCommit} onCancel={onCancel} />\n ) : null}\n </div>\n )\n}\n\n/**\n * Editing chrome: marks the edited locale at the point of edit (EC-018), and\n * says so explicitly when committing will CREATE the active locale's variant\n * from a fallback-shown value (EC-176) — translation is a visible act.\n */\nfunction CellEditorFrame({\n locale,\n createsLocalizedVariant = false,\n cellKeyId,\n children,\n}: {\n locale: Locale | null\n /** True when the cell showed a fallback — committing creates the variant. */\n createsLocalizedVariant?: boolean\n cellKeyId: string\n children: ReactNode\n}) {\n return (\n <Row gap=\"1\" align=\"center\" data-cell-key={cellKeyId} className=\"-mx-1.5 min-w-[9rem]\">\n {locale ? (\n <Badge\n variant={createsLocalizedVariant ? 'info' : 'outline'}\n className=\"uppercase\"\n data-testid=\"cell-editing-locale\"\n title={\n createsLocalizedVariant\n ? translate('cms.cell.createsVariantTitle', { locale: locale.toUpperCase() })\n : undefined\n }\n >\n {locale}\n {createsLocalizedVariant ? (\n <span className=\"lowercase\"> · {translate('cms.cell.newVariant')}</span>\n ) : null}\n </Badge>\n ) : null}\n {children}\n </Row>\n )\n}\n\ntype CellDraft = string | boolean | string[]\n\n/**\n * The in-cell editor: draft → commit on Enter (advance down), Tab/Shift-Tab\n * (advance next/prev) or blur; Esc cancels without dispatching anything.\n */\nfunction InlineCellEditor({\n field,\n value,\n busy,\n onCommit,\n onCancel,\n}: {\n field: FieldDef\n value: unknown\n busy: boolean\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n onCancel: () => void\n}) {\n const [draft, setDraft] = useState<CellDraft>(() => initialDraft(field, value))\n const draftRef = useRef(draft)\n draftRef.current = draft\n // EC-463: the ref moves SYNCHRONOUSLY with the control, not at the next\n // render. A control that only emits its final value on the settling keystroke\n // (the date control's Enter) would otherwise be committed one render stale —\n // the same event that produces the value also triggers `commit()` below.\n function updateDraft(next: CellDraft) {\n draftRef.current = next\n setDraft(next)\n }\n // Each editor instance settles exactly once (Tab keydown + the blur it\n // causes must not commit twice).\n const settledRef = useRef(false)\n\n function commit(advance: AdvanceDirection | null) {\n if (settledRef.current) return\n settledRef.current = true\n onCommit(draftValue(field, draftRef.current), advance)\n }\n\n function cancel() {\n if (settledRef.current) return\n settledRef.current = true\n onCancel()\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLDivElement>) {\n if (event.key === 'Enter') {\n event.preventDefault()\n commit('down')\n } else if (event.key === 'Tab') {\n event.preventDefault()\n commit(event.shiftKey ? 'prev' : 'next')\n } else if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n cancel()\n }\n }\n\n function handleBlur(event: FocusEvent<HTMLDivElement>) {\n // Focus left the editor entirely (e.g. a click elsewhere) → commit in place.\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) commit(null)\n }\n\n return (\n <div\n onKeyDown={handleKeyDown}\n onBlur={handleBlur}\n onClick={(event) => event.stopPropagation()}\n className=\"min-w-0 flex-1\"\n data-testid=\"cell-editor\"\n aria-busy={busy || undefined}\n >\n <CellEditorControl field={field} draft={draft} onDraft={updateDraft} />\n </div>\n )\n}\n\n/** The actual input for the field type (compact, table-density variants). */\nfunction CellEditorControl({\n field,\n draft,\n onDraft,\n}: {\n field: FieldDef\n draft: CellDraft\n onDraft: (draft: CellDraft) => void\n}) {\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-7 items-center gap-2 text-sm\">\n <input\n autoFocus\n type=\"checkbox\"\n checked={draft === true}\n onChange={(event) => onDraft(event.target.checked)}\n className=\"size-4 accent-primary\"\n data-testid=\"cell-editor-boolean\"\n />\n <Text as=\"span\" size=\"xs\" tone=\"muted\">\n {draft === true ? translate('common.true') : translate('common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n autoFocus\n type=\"number\"\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 text-sm\"\n data-testid=\"cell-editor-number\"\n />\n )\n case 'date':\n // EC-463: the shared date control. The cell's own draft already commits on\n // Enter/Tab/blur, so what this adds here is the working insert/paste path\n // and the guard against a re-render clobbering half-typed segments.\n return (\n <DateInput\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(stored) => onDraft(stored ? stored.slice(0, 10) : '')}\n className=\"h-7 text-sm\"\n testId=\"cell-editor-date\"\n {...datePickerBounds(field.validation)}\n />\n )\n case 'select':\n if (field.multiple) {\n return <MultiSelectControl field={field} draft={draft} onDraft={onDraft} />\n }\n return (\n <Select\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 py-0 text-sm\"\n data-testid=\"cell-editor-select\"\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n default:\n return (\n <Input\n autoFocus\n value={typeof draft === 'string' ? draft : ''}\n onChange={(event) => onDraft(event.target.value)}\n className=\"h-7 text-sm\"\n data-testid=\"cell-editor-text\"\n />\n )\n }\n}\n\nfunction MultiSelectControl({\n field,\n draft,\n onDraft,\n}: {\n field: SelectFieldDef\n draft: CellDraft\n onDraft: (draft: CellDraft) => void\n}) {\n const selected = Array.isArray(draft) ? draft : []\n return (\n <Row gap=\"2\" wrap data-testid=\"cell-editor-multiselect\">\n {field.options.map((opt, index) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-xs\">\n <input\n autoFocus={index === 0}\n type=\"checkbox\"\n checked={on}\n onChange={() =>\n onDraft(on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value])\n }\n className=\"size-3.5 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n}\n\n/** Relation/asset cells reuse the existing lightweight pickers, opened from the cell. */\nfunction CellPicker({\n field,\n value,\n onCommit,\n onCancel,\n}: {\n field: FieldDef\n value: unknown\n onCommit: (value: unknown, advance: AdvanceDirection | null) => void\n onCancel: () => void\n}) {\n if (field.type === 'relation') {\n return (\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={toRefArray(value)}\n open\n onOpenChange={(open) => {\n if (!open) onCancel()\n }}\n onChange={(refs) => onCommit(field.multiple ? refs : refs[0], null)}\n />\n )\n }\n if (field.type === 'asset') {\n return (\n <AssetPicker\n value={field.multiple === false ? singleAssetIdOf(value) : null}\n open\n onOpenChange={(open) => {\n if (!open) onCancel()\n }}\n onChange={(picked) => onCommit(applyAssetSelection(value, picked, field.multiple), null)}\n />\n )\n }\n return null\n}\n\n// --- Draft <-> stored value mapping (mirrors `FieldControl`'s conventions) -----\n\nfunction initialDraft(field: FieldDef, value: unknown): CellDraft {\n switch (field.type) {\n case 'boolean':\n return value === true\n case 'number':\n return typeof value === 'number' ? String(value) : ''\n case 'date':\n return typeof value === 'string' ? value.slice(0, 10) : ''\n case 'select':\n if (field.multiple) {\n return Array.isArray(value) ? value.filter((v): v is string => typeof v === 'string') : []\n }\n return typeof value === 'string' ? value : ''\n default:\n return typeof value === 'string' ? value : ''\n }\n}\n\nfunction draftValue(field: FieldDef, draft: CellDraft): unknown {\n switch (field.type) {\n case 'boolean':\n return draft === true\n case 'number':\n return draft === '' ? undefined : Number(draft)\n case 'date':\n return draft === '' || typeof draft !== 'string' ? undefined : `${draft}T00:00:00.000Z`\n case 'select':\n if (field.multiple) return Array.isArray(draft) ? draft : []\n return draft === '' ? undefined : draft\n default:\n return draft === '' ? undefined : draft\n }\n}\n"]}
|
|
@@ -7,6 +7,7 @@ import { resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace';
|
|
|
7
7
|
import { Button, Input, Row, RowItem, Select, Stack, Text, } from '@elytracms/studio/ui';
|
|
8
8
|
import { cn } from '@elytracms/studio/lib/utils';
|
|
9
9
|
import { localizedLabel, translate } from '@elytracms/studio/lib/i18n';
|
|
10
|
+
import { customizationIssueMessage } from '@elytracms/studio/lib/persona/labels';
|
|
10
11
|
import { activeLocaleValues } from '@elytracms/studio/lib/locale';
|
|
11
12
|
import { useCollectionView } from '../collection-view/collection-view-context.js';
|
|
12
13
|
import { fieldLabel } from './cms-labels.js';
|
|
@@ -16,6 +17,7 @@ import { RelationPicker } from './relation-picker.js';
|
|
|
16
17
|
import { RichTextEditor } from './rich-text/index.js';
|
|
17
18
|
import { DocumentUrlSegment } from './document-url-path.js';
|
|
18
19
|
import { DateInput } from './date-input.js';
|
|
20
|
+
import { datePickerBounds } from './date-input-core.js';
|
|
19
21
|
import { AssetField } from './asset-field.js';
|
|
20
22
|
import { SegmentedOptions } from './field-control-lib.js';
|
|
21
23
|
import { slugAutoDeriveDecision } from './slug-auto-derive.js';
|
|
@@ -48,7 +50,7 @@ export function FieldControl(props) {
|
|
|
48
50
|
if (control) {
|
|
49
51
|
const rejected = renderers.issues.find((issue) => issue.id === control);
|
|
50
52
|
if (rejected) {
|
|
51
|
-
return (_jsxs(Stack, { gap: "1", children: [_jsx(FieldRendererIssue, { message: rejected
|
|
53
|
+
return (_jsxs(Stack, { gap: "1", children: [_jsx(FieldRendererIssue, { message: customizationIssueMessage(rejected) }), builtIn] }));
|
|
52
54
|
}
|
|
53
55
|
// The field asks for a control with no registered renderer and no built-in
|
|
54
56
|
// name — surface it (a typo'd `control` would otherwise read as a plain input).
|
|
@@ -87,7 +89,7 @@ function BuiltInFieldControl({ field, value, onChange, readOnly, id }) {
|
|
|
87
89
|
// EC-463: never write a mid-entry segment state into the document — see
|
|
88
90
|
// `date-input.tsx` (this control silently stored `0002-09-18` for an
|
|
89
91
|
// editor typing 2026-09-18).
|
|
90
|
-
return (_jsx(DateInput, { id: id, value: value, onChange: onChange, disabled: readOnly, testId: `field-date-${field.name}
|
|
92
|
+
return (_jsx(DateInput, { id: id, value: value, onChange: onChange, disabled: readOnly, testId: `field-date-${field.name}`, ...datePickerBounds(field.validation) }));
|
|
91
93
|
case 'select':
|
|
92
94
|
if (field.multiple) {
|
|
93
95
|
const selected = Array.isArray(value) ? value : [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-control.js","sourceRoot":"","sources":["../../../src/components/cms/field-control.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AlertTriangle, Link2, Pencil, Plus, RotateCw, X } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport type {\n DocumentRef,\n FieldDef,\n RelationFieldDef,\n UrlSegment,\n} from '@elytracms/core/cms-core'\nimport {\n BUILTIN_FIELD_CONTROLS,\n applySlugify,\n descendantIds,\n documentDefaultLocale,\n findSlugCollision,\n isFieldLocalized,\n parentRelationField,\n resolveSlugPath,\n resolveUrlSegments,\n slugSourceValue,\n} from '@elytracms/core/cms-core'\nimport type { SlugFieldConfig, SlugPathParts } from '@elytracms/core/cms-core'\nimport { resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport {\n Button,\n Input,\n Row,\n RowItem,\n Select,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { activeLocaleValues } from '@elytracms/studio/lib/locale'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { fieldLabel } from './cms-labels'\nimport { useOptionalDocumentEditor } from './document-editor-context'\nimport { toRefArray } from './cell'\nimport { RelationPicker } from './relation-picker'\nimport { RichTextEditor } from './rich-text'\nimport { DocumentUrlSegment } from './document-url-path'\nimport { DateInput } from './date-input'\nimport { AssetField } from './asset-field'\nimport { SegmentedOptions } from './field-control-lib'\nimport { slugAutoDeriveDecision } from './slug-auto-derive'\nimport { ObjectField } from './object-array-field'\nimport {\n FieldRendererBoundary,\n FieldRendererIssue,\n useFieldRenderers,\n} from './field-renderer'\n\ninterface FieldControlProps {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}\n\n/**\n * The document-editor field control. Resolves a project's custom renderer by the\n * field's `form.control` (EC-238, customization seam EC-236) and falls back to the\n * built-in control for the field's datatype: a registered renderer renders inside\n * an error boundary (a throw → the built-in + a visible issue); a rejected\n * registration (non-component) shows the built-in with the issue above it; a field\n * naming a control with NO renderer and NO built-in name (a typo) shows the\n * built-in with a loud issue — never a silent fall-through; otherwise the built-in\n * renders alone.\n *\n * EC-330 split: the asset-field family lives in `asset-field.tsx`, the object /\n * repeater editors in `object-array-field.tsx`, and their pure companions\n * (reorder/summary/depth/table decisions, the `options` segmented control) in\n * `field-control-lib.tsx` — this file keeps the dispatcher plus the slug and\n * relation controls.\n */\nexport function FieldControl(props: FieldControlProps) {\n const renderers = useFieldRenderers()\n const builtIn = <BuiltInFieldControl {...props} />\n const control = props.field.form?.control\n const Custom = control ? renderers.get(control) : undefined\n if (Custom) {\n return (\n <FieldRendererBoundary\n fallback={builtIn}\n issue={<FieldRendererIssue message={translate('cms.field.rendererCrashed')} />}\n >\n <Custom {...props} />\n </FieldRendererBoundary>\n )\n }\n if (control) {\n const rejected = renderers.issues.find((issue) => issue.id === control)\n if (rejected) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={rejected.message} />\n {builtIn}\n </Stack>\n )\n }\n // The field asks for a control with no registered renderer and no built-in\n // name — surface it (a typo'd `control` would otherwise read as a plain input).\n if (!(BUILTIN_FIELD_CONTROLS as readonly string[]).includes(control)) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={translate('cms.field.noRenderer', { control })} />\n {builtIn}\n </Stack>\n )\n }\n }\n return builtIn\n}\n\n/** The conventional slug field name (mirrors `url-for-document`'s `SLUG_FIELD`). */\nconst SLUG_FIELD_NAME = 'slug'\n/** The built-in control name that opts any `text` field into the slug control (EC-315). */\nconst SLUG_CONTROL = 'slug'\n\n/**\n * EC-315: a `text` field is rendered by the smart slug control when it opts in via\n * `form.control: 'slug'`, OR (the default auto-upgrade) when it is simply named\n * `slug` — the long-standing convention `url-for-document`/hierarchy already key off.\n */\nfunction isSlugControl(field: FieldDef): boolean {\n return field.type === 'text' && (field.form?.control === SLUG_CONTROL || field.name === SLUG_FIELD_NAME)\n}\n\nfunction BuiltInFieldControl({ field, value, onChange, readOnly, id }: FieldControlProps) {\n // EC-315: the smart slug control (composed path, auto-slug, per-locale segments)\n // subsumes the old inline `slug` input + PathPreview. It degrades to a plain input\n // when the collection isn't routable (name-based auto-upgrade only) or no document\n // editor context is present (e.g. a table-cell picker).\n if (isSlugControl(field)) {\n return <SlugField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n }\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={value === true}\n disabled={readOnly}\n onChange={(e) => onChange(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {translate(value === true ? 'common.true' : 'common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={typeof value === 'number' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? undefined : Number(e.target.value))}\n />\n )\n case 'date':\n // EC-463: never write a mid-entry segment state into the document — see\n // `date-input.tsx` (this control silently stored `0002-09-18` for an\n // editor typing 2026-09-18).\n return (\n <DateInput\n id={id}\n value={value}\n onChange={onChange}\n disabled={readOnly}\n testId={`field-date-${field.name}`}\n />\n )\n case 'select':\n if (field.multiple) {\n const selected = Array.isArray(value) ? (value as string[]) : []\n return (\n <Row gap=\"2\" wrap>\n {field.options.map((opt) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={on}\n disabled={readOnly}\n onChange={() =>\n onChange(\n on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value],\n )\n }\n className=\"size-4 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n }\n // EC-295: the `options` control renders a small fixed enumeration as inline\n // segmented buttons instead of the dropdown (single-select only).\n if (field.form?.control === 'options') {\n return (\n <SegmentedOptions field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n )\n }\n return (\n <Select\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'richText':\n return (\n <RichTextEditor\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n id={id}\n allow={field.allow}\n // EC-436: the SAME resolved localized label the field row renders (the\n // EC-241 `fieldLabel` path) — titles the expand stage \"<label> — Rich text\".\n label={fieldLabel(field)}\n />\n )\n case 'relation':\n return <RelationField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'asset':\n return <AssetField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'object':\n return <ObjectField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n default:\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n}\n\n/**\n * EC-315 — the smart slug / URL-segment control. A `text` field named `slug` (or any\n * `text` field with `form.control: 'slug'`) renders here instead of a bare input:\n *\n * - **Composed path**: the route-derived URL, decomposed by {@link resolveSlugPath}\n * into read-only parent/context segments + the editable slug segment inline + the\n * locale prefix (non-default locales). Reuses the same `urlForDocument` the live\n * site uses, so the preview matches what visitors get. Draft-derived (updates as\n * you type); the live \"View live\" button in the header stays the published open.\n * - **Auto-slug**: while the slug is empty or was last produced by auto-derivation,\n * it live-derives from the source field (default: the collection's `titleField`).\n * A manual edit stops the auto-fill; the ↻ button always re-derives.\n * - **Per-locale**: reads/writes through the shared `value`/`onChange` seam, so a\n * `localized` slug edits the active locale's segment with no bespoke locale code.\n * - **Uniqueness**: an inline warning when the candidate collides with a sibling in\n * the same scope (same parent when hierarchical, same locale). A custom\n * `slug.unique` hook replaces the default sibling scan.\n *\n * Degrades to a plain input when there is no document editor context (a table-cell\n * picker) or when a name-based auto-upgrade lands on a non-routable collection.\n */\nfunction SlugField({\n field,\n value,\n onChange,\n readOnly,\n id,\n}: {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const slugConfig = field.slug as SlugFieldConfig | undefined\n const explicit = field.form?.control === SLUG_CONTROL\n const current = typeof value === 'string' ? value : ''\n const locale = source.activeLocale\n const localeConfig = source.localeConfig\n\n // 0.0.39 regression fix: resolve the deployment routes on EVERY render (a cheap\n // synchronous accessor), never freeze them at first paint. The earlier\n // `useMemo(() => resolveDeploymentRoutes(), [])` captured the EMPTY route set from\n // before the workspace/config finished loading — so the composed path never\n // appeared once routes arrived, and a stale set could paint a misleading prefix.\n const routes = resolveDeploymentRoutes()\n const routable = routes.some((r) => r.document?.collection === source.collectionId)\n\n const draft = editor?.draft\n // EC-463: a slug field that is NOT localized holds ONE value for every locale,\n // so its auto-slug must read ONE locale's source fields — the document's base\n // locale. Deriving from the ACTIVE locale made switching to the DE tab show a\n // German-derived slug preview for a field that is shared across locales (and,\n // with the EC-461 derive latch, a locale switch alone could then WRITE it).\n // A localized slug keeps per-locale derivation, which is the whole point of it.\n const deriveLocale =\n isFieldLocalized(source.schema, field.name) || !draft\n ? locale\n : documentDefaultLocale(draft, localeConfig)\n const values = useMemo<Record<string, unknown>>(\n () => (draft ? activeLocaleValues(draft, deriveLocale) : {}),\n [draft, deriveLocale],\n )\n const derived = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n\n // Track whether the slug was manually set — auto-derive stays active while the\n // slug is empty or was last produced by auto-derivation (never overwrites a manual\n // slug). Seeded true when the loaded document already carries a slug.\n const [manuallyEdited, setManuallyEdited] = useState(() => current.trim() !== '')\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n // EC-461: opening a document is not an edit. Auto-derive fires only once the\n // derived value has moved away from its mount state (the editor actually\n // changed a source field this session) — the old on-mount fill made every\n // slug-less document dirty on open, and the 1s autosave then WROTE it (in the\n // playground: the stale re-seeded baseline over the adapter's newer record —\n // the destructive half of the EC-461 loss family). Decision extracted pure in\n // `slug-auto-derive.ts`; the latch keeps derivation live after the first\n // divergence so title edits that return to the initial value still land.\n const initialDerivedRef = useRef(derived)\n const deriveLatchRef = useRef(false)\n useEffect(() => {\n const decision = slugAutoDeriveDecision({\n derived,\n current,\n initialDerived: initialDerivedRef.current,\n latchOpen: deriveLatchRef.current,\n manuallyEdited,\n readOnly,\n })\n if (decision.openLatch) deriveLatchRef.current = true\n if (decision.write) onChangeRef.current(derived)\n }, [derived, manuallyEdited, readOnly, current])\n\n // The composed path parts (routable collections with a document editor only).\n const siblings = draft ? source.documents() : []\n // Draft-derived (routes + locale only, no `frontendUrl`) — the composed path is a\n // read-only preview that updates as you type, mirroring the detail editor's draft\n // URL. The header's published-gated \"View live\" stays the sole open-live action,\n // so the draft/live distinction is preserved (an unpublished slug never links out).\n const parts: SlugPathParts | undefined =\n draft && routable\n ? resolveSlugPath({ routes, localeConfig }, source.schema, draft, { siblings, locale })\n : undefined\n // The classified context segments (0.0.42, round 3) — the same `resolveUrlSegments`\n // the header URL row uses, so the slug prefix and the header path attribute each\n // segment identically. Everything before this document's own `current` slug is the\n // context prefix; its LAST segment is the immediate parent shown in the compact pill.\n const contextSegments: UrlSegment[] =\n draft && routable\n ? resolveUrlSegments({ routes, localeConfig }, source.schema, draft, { siblings, locale }).filter(\n (s) => s.kind !== 'current',\n )\n : []\n const lastContext = contextSegments[contextSegments.length - 1]\n\n // Default (sync) uniqueness — the first colliding sibling's title, or null.\n const defaultCollisionTitle = useMemo<string | null>(() => {\n if (slugConfig?.unique || !draft) return null\n const trimmed = current.trim()\n if (trimmed === '') return null\n const hit = findSlugCollision(trimmed, draft, source.documents(), {\n collection: source.schema,\n locale,\n localeConfig,\n })\n return hit ? source.titleOf({ collection: source.collectionId, id: hit.id }) : null\n }, [current, draft, slugConfig, locale, localeConfig, source])\n\n // Custom (possibly async) uniqueness hook — race-guarded.\n const [asyncTaken, setAsyncTaken] = useState(false)\n useEffect(() => {\n const unique = slugConfig?.unique\n if (!unique || !draft) {\n setAsyncTaken(false)\n return\n }\n const trimmed = current.trim()\n if (trimmed === '') {\n setAsyncTaken(false)\n return\n }\n let cancelled = false\n Promise.resolve(unique(trimmed, { document: draft, locale, siblings: source.documents() }))\n .then((ok) => {\n if (!cancelled) setAsyncTaken(ok === false)\n })\n .catch(() => {\n if (!cancelled) setAsyncTaken(false)\n })\n return () => {\n cancelled = true\n }\n }, [current, slugConfig, draft, locale, source])\n\n const collisionMessage = slugConfig?.unique\n ? asyncTaken\n ? translate('cms.field.slug.takenGeneric')\n : undefined\n : defaultCollisionTitle\n ? translate('cms.field.slug.taken', { title: defaultCollisionTitle })\n : undefined\n\n function handleInput(next: string) {\n onChange(next || undefined)\n // Clearing re-enables auto-derive; any non-empty entry is a manual override.\n setManuallyEdited(next.trim() !== '')\n }\n\n function regenerate() {\n setManuallyEdited(false)\n const next = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n onChange(next || undefined)\n }\n\n // No document editor (a picker), or a name-based auto-upgrade on a non-routable\n // collection: keep the historical plain input, no slug chrome (no regression).\n if (!editor || (!explicit && !routable)) {\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n\n const input = (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n placeholder={derived || undefined}\n onChange={(e) => handleInput(e.target.value)}\n className={cn(parts ? 'h-7 min-w-[10ch] flex-1 bg-background font-mono text-xs' : 'flex-1')}\n />\n )\n const regenerateButton = !readOnly ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={regenerate}\n aria-label={translate('cms.field.slug.regenerate')}\n title={translate('cms.field.slug.regenerate')}\n >\n <RotateCw />\n </Button>\n ) : null\n\n // The compact, ellipsized read-only prefix (0.0.39 \"hybrid split\", round-3 clickable):\n // only the LAST context segment (`…/produkte/`) so a deep path can't overflow the\n // narrow Details sidebar — but that shown segment is now CLICKABLE with the same\n // navigation semantics as the header URL row (an ancestor DOCUMENT links to its\n // editor; a static route literal stays plain). The full composed path is the tooltip.\n const prefixTitle =\n parts?.path ??\n (contextSegments.length > 0 ? `/${contextSegments.map((s) => s.text).join('/')}/` : '/')\n\n return (\n <Stack gap=\"2\">\n {parts ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-composed-path\">\n <span\n className=\"inline-flex min-w-0 shrink-0 items-center rounded bg-muted/40 px-1.5 py-1 font-mono text-xs text-muted-foreground ring-1 ring-inset ring-border\"\n title={prefixTitle}\n data-testid=\"slug-prefix\"\n >\n {contextSegments.length === 0 ? (\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n ) : (\n <>\n <span aria-hidden className=\"text-muted-foreground/50\">\n {contextSegments.length > 1 ? '…/' : '/'}\n </span>\n {lastContext ? (\n <DocumentUrlSegment\n segment={lastContext}\n projectId={editor?.projectId}\n collectionId={source.collectionId}\n />\n ) : null}\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n </>\n )}\n </span>\n {input}\n {regenerateButton}\n </Row>\n ) : (\n <Row gap=\"1\" align=\"center\">\n {input}\n {regenerateButton}\n </Row>\n )}\n\n {collisionMessage ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-collision\">\n <AlertTriangle className=\"size-3.5 shrink-0 text-warning\" aria-hidden />\n <Text size=\"xs\" tone=\"muted\">\n {collisionMessage}\n </Text>\n </Row>\n ) : null}\n </Stack>\n )\n}\n\nfunction RelationField({\n field,\n value,\n onChange,\n readOnly,\n}: {\n field: RelationFieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const [open, setOpen] = useState(false)\n const refs = toRefArray(value)\n const projectId = source.projectId\n\n // EC-218: for the editing document's `parent` self-relation, exclude the\n // document itself and its descendants from the picker — choosing one would make\n // the page its own ancestor (a cycle). Only applies to the parent field of a\n // hierarchical collection; ordinary relations (and other self-relations) are\n // unrestricted. validateDocument is the backstop where this context is absent.\n const excludeIds = useMemo<Set<string> | undefined>(() => {\n if (!editor || field.target !== editor.collection.id) return undefined\n if (parentRelationField(editor.collection)?.name !== field.name) return undefined\n const ids = descendantIds(editor.docRef.id, source.referenceCandidates(editor.collection.id))\n ids.add(editor.docRef.id)\n return ids\n }, [editor, field.target, field.name, source])\n\n function apply(next: DocumentRef[]) {\n onChange(field.multiple ? next : (next[0] ?? undefined))\n }\n\n return (\n <Stack gap=\"2\">\n {refs.length > 0 ? (\n <Stack gap=\"1\">\n {refs.map((ref, i) => {\n // EC-296: the relation title navigates to the referenced document (autosave\n // keeps the current edit safe). Without a projectId (no persistence, e.g.\n // fixtures) it stays plain text. EC-246c: full-width row, not a pill —\n // long titles wrap awkwardly in a pill and a narrow field crushes it.\n const title = source.titleOf(ref)\n const label = (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <Link2 className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{title}</span>\n </span>\n )\n return (\n <RowItem\n key={`${ref.id}-${i}`}\n data-testid=\"relation-value\"\n actions={\n !readOnly ? (\n <>\n {field.multiple === false ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('cms.relation.change')}\n title={translate('cms.relation.change')}\n onClick={() => setOpen(true)}\n >\n <Pencil />\n </Button>\n ) : null}\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('common.remove')}\n title={translate('common.remove')}\n className=\"hover:text-destructive\"\n onClick={() => apply(refs.filter((r) => r.id !== ref.id))}\n >\n <X />\n </Button>\n </>\n ) : undefined\n }\n >\n {projectId ? (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(ref.collection, ref.id) }}\n title={translate('cms.relation.openTitle', { title })}\n className=\"text-sm font-medium hover:text-primary hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <Text as=\"span\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n </RowItem>\n )\n })}\n </Stack>\n ) : null}\n {!readOnly && (refs.length === 0 || field.multiple) ? (\n <Row>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Plus /> {refs.length === 0 ? translate('cms.relation.pick') : translate('common.add')}\n </Button>\n </Row>\n ) : null}\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={refs}\n open={open}\n onOpenChange={setOpen}\n onChange={apply}\n excludeIds={excludeIds}\n />\n </Stack>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"field-control.js","sourceRoot":"","sources":["../../../src/components/cms/field-control.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AlertTriangle, Link2, Pencil, Plus, RotateCw, X } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport type {\n DocumentRef,\n FieldDef,\n RelationFieldDef,\n UrlSegment,\n} from '@elytracms/core/cms-core'\nimport {\n BUILTIN_FIELD_CONTROLS,\n applySlugify,\n descendantIds,\n documentDefaultLocale,\n findSlugCollision,\n isFieldLocalized,\n parentRelationField,\n resolveSlugPath,\n resolveUrlSegments,\n slugSourceValue,\n} from '@elytracms/core/cms-core'\nimport type { SlugFieldConfig, SlugPathParts } from '@elytracms/core/cms-core'\nimport { resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport {\n Button,\n Input,\n Row,\n RowItem,\n Select,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { customizationIssueMessage } from '@elytracms/studio/lib/persona/labels'\nimport { activeLocaleValues } from '@elytracms/studio/lib/locale'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { fieldLabel } from './cms-labels'\nimport { useOptionalDocumentEditor } from './document-editor-context'\nimport { toRefArray } from './cell'\nimport { RelationPicker } from './relation-picker'\nimport { RichTextEditor } from './rich-text'\nimport { DocumentUrlSegment } from './document-url-path'\nimport { DateInput } from './date-input'\nimport { datePickerBounds } from './date-input-core'\nimport { AssetField } from './asset-field'\nimport { SegmentedOptions } from './field-control-lib'\nimport { slugAutoDeriveDecision } from './slug-auto-derive'\nimport { ObjectField } from './object-array-field'\nimport {\n FieldRendererBoundary,\n FieldRendererIssue,\n useFieldRenderers,\n} from './field-renderer'\n\ninterface FieldControlProps {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}\n\n/**\n * The document-editor field control. Resolves a project's custom renderer by the\n * field's `form.control` (EC-238, customization seam EC-236) and falls back to the\n * built-in control for the field's datatype: a registered renderer renders inside\n * an error boundary (a throw → the built-in + a visible issue); a rejected\n * registration (non-component) shows the built-in with the issue above it; a field\n * naming a control with NO renderer and NO built-in name (a typo) shows the\n * built-in with a loud issue — never a silent fall-through; otherwise the built-in\n * renders alone.\n *\n * EC-330 split: the asset-field family lives in `asset-field.tsx`, the object /\n * repeater editors in `object-array-field.tsx`, and their pure companions\n * (reorder/summary/depth/table decisions, the `options` segmented control) in\n * `field-control-lib.tsx` — this file keeps the dispatcher plus the slug and\n * relation controls.\n */\nexport function FieldControl(props: FieldControlProps) {\n const renderers = useFieldRenderers()\n const builtIn = <BuiltInFieldControl {...props} />\n const control = props.field.form?.control\n const Custom = control ? renderers.get(control) : undefined\n if (Custom) {\n return (\n <FieldRendererBoundary\n fallback={builtIn}\n issue={<FieldRendererIssue message={translate('cms.field.rendererCrashed')} />}\n >\n <Custom {...props} />\n </FieldRendererBoundary>\n )\n }\n if (control) {\n const rejected = renderers.issues.find((issue) => issue.id === control)\n if (rejected) {\n return (\n <Stack gap=\"1\">\n {/* EC-478: the issue's catalog ref, resolved for the active locale. */}\n <FieldRendererIssue message={customizationIssueMessage(rejected)} />\n {builtIn}\n </Stack>\n )\n }\n // The field asks for a control with no registered renderer and no built-in\n // name — surface it (a typo'd `control` would otherwise read as a plain input).\n if (!(BUILTIN_FIELD_CONTROLS as readonly string[]).includes(control)) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={translate('cms.field.noRenderer', { control })} />\n {builtIn}\n </Stack>\n )\n }\n }\n return builtIn\n}\n\n/** The conventional slug field name (mirrors `url-for-document`'s `SLUG_FIELD`). */\nconst SLUG_FIELD_NAME = 'slug'\n/** The built-in control name that opts any `text` field into the slug control (EC-315). */\nconst SLUG_CONTROL = 'slug'\n\n/**\n * EC-315: a `text` field is rendered by the smart slug control when it opts in via\n * `form.control: 'slug'`, OR (the default auto-upgrade) when it is simply named\n * `slug` — the long-standing convention `url-for-document`/hierarchy already key off.\n */\nfunction isSlugControl(field: FieldDef): boolean {\n return field.type === 'text' && (field.form?.control === SLUG_CONTROL || field.name === SLUG_FIELD_NAME)\n}\n\nfunction BuiltInFieldControl({ field, value, onChange, readOnly, id }: FieldControlProps) {\n // EC-315: the smart slug control (composed path, auto-slug, per-locale segments)\n // subsumes the old inline `slug` input + PathPreview. It degrades to a plain input\n // when the collection isn't routable (name-based auto-upgrade only) or no document\n // editor context is present (e.g. a table-cell picker).\n if (isSlugControl(field)) {\n return <SlugField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n }\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={value === true}\n disabled={readOnly}\n onChange={(e) => onChange(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {translate(value === true ? 'common.true' : 'common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={typeof value === 'number' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? undefined : Number(e.target.value))}\n />\n )\n case 'date':\n // EC-463: never write a mid-entry segment state into the document — see\n // `date-input.tsx` (this control silently stored `0002-09-18` for an\n // editor typing 2026-09-18).\n return (\n <DateInput\n id={id}\n value={value}\n onChange={onChange}\n disabled={readOnly}\n testId={`field-date-${field.name}`}\n {...datePickerBounds(field.validation)}\n />\n )\n case 'select':\n if (field.multiple) {\n const selected = Array.isArray(value) ? (value as string[]) : []\n return (\n <Row gap=\"2\" wrap>\n {field.options.map((opt) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={on}\n disabled={readOnly}\n onChange={() =>\n onChange(\n on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value],\n )\n }\n className=\"size-4 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n }\n // EC-295: the `options` control renders a small fixed enumeration as inline\n // segmented buttons instead of the dropdown (single-select only).\n if (field.form?.control === 'options') {\n return (\n <SegmentedOptions field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n )\n }\n return (\n <Select\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'richText':\n return (\n <RichTextEditor\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n id={id}\n allow={field.allow}\n // EC-436: the SAME resolved localized label the field row renders (the\n // EC-241 `fieldLabel` path) — titles the expand stage \"<label> — Rich text\".\n label={fieldLabel(field)}\n />\n )\n case 'relation':\n return <RelationField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'asset':\n return <AssetField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'object':\n return <ObjectField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n default:\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n}\n\n/**\n * EC-315 — the smart slug / URL-segment control. A `text` field named `slug` (or any\n * `text` field with `form.control: 'slug'`) renders here instead of a bare input:\n *\n * - **Composed path**: the route-derived URL, decomposed by {@link resolveSlugPath}\n * into read-only parent/context segments + the editable slug segment inline + the\n * locale prefix (non-default locales). Reuses the same `urlForDocument` the live\n * site uses, so the preview matches what visitors get. Draft-derived (updates as\n * you type); the live \"View live\" button in the header stays the published open.\n * - **Auto-slug**: while the slug is empty or was last produced by auto-derivation,\n * it live-derives from the source field (default: the collection's `titleField`).\n * A manual edit stops the auto-fill; the ↻ button always re-derives.\n * - **Per-locale**: reads/writes through the shared `value`/`onChange` seam, so a\n * `localized` slug edits the active locale's segment with no bespoke locale code.\n * - **Uniqueness**: an inline warning when the candidate collides with a sibling in\n * the same scope (same parent when hierarchical, same locale). A custom\n * `slug.unique` hook replaces the default sibling scan.\n *\n * Degrades to a plain input when there is no document editor context (a table-cell\n * picker) or when a name-based auto-upgrade lands on a non-routable collection.\n */\nfunction SlugField({\n field,\n value,\n onChange,\n readOnly,\n id,\n}: {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const slugConfig = field.slug as SlugFieldConfig | undefined\n const explicit = field.form?.control === SLUG_CONTROL\n const current = typeof value === 'string' ? value : ''\n const locale = source.activeLocale\n const localeConfig = source.localeConfig\n\n // 0.0.39 regression fix: resolve the deployment routes on EVERY render (a cheap\n // synchronous accessor), never freeze them at first paint. The earlier\n // `useMemo(() => resolveDeploymentRoutes(), [])` captured the EMPTY route set from\n // before the workspace/config finished loading — so the composed path never\n // appeared once routes arrived, and a stale set could paint a misleading prefix.\n const routes = resolveDeploymentRoutes()\n const routable = routes.some((r) => r.document?.collection === source.collectionId)\n\n const draft = editor?.draft\n // EC-463: a slug field that is NOT localized holds ONE value for every locale,\n // so its auto-slug must read ONE locale's source fields — the document's base\n // locale. Deriving from the ACTIVE locale made switching to the DE tab show a\n // German-derived slug preview for a field that is shared across locales (and,\n // with the EC-461 derive latch, a locale switch alone could then WRITE it).\n // A localized slug keeps per-locale derivation, which is the whole point of it.\n const deriveLocale =\n isFieldLocalized(source.schema, field.name) || !draft\n ? locale\n : documentDefaultLocale(draft, localeConfig)\n const values = useMemo<Record<string, unknown>>(\n () => (draft ? activeLocaleValues(draft, deriveLocale) : {}),\n [draft, deriveLocale],\n )\n const derived = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n\n // Track whether the slug was manually set — auto-derive stays active while the\n // slug is empty or was last produced by auto-derivation (never overwrites a manual\n // slug). Seeded true when the loaded document already carries a slug.\n const [manuallyEdited, setManuallyEdited] = useState(() => current.trim() !== '')\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n // EC-461: opening a document is not an edit. Auto-derive fires only once the\n // derived value has moved away from its mount state (the editor actually\n // changed a source field this session) — the old on-mount fill made every\n // slug-less document dirty on open, and the 1s autosave then WROTE it (in the\n // playground: the stale re-seeded baseline over the adapter's newer record —\n // the destructive half of the EC-461 loss family). Decision extracted pure in\n // `slug-auto-derive.ts`; the latch keeps derivation live after the first\n // divergence so title edits that return to the initial value still land.\n const initialDerivedRef = useRef(derived)\n const deriveLatchRef = useRef(false)\n useEffect(() => {\n const decision = slugAutoDeriveDecision({\n derived,\n current,\n initialDerived: initialDerivedRef.current,\n latchOpen: deriveLatchRef.current,\n manuallyEdited,\n readOnly,\n })\n if (decision.openLatch) deriveLatchRef.current = true\n if (decision.write) onChangeRef.current(derived)\n }, [derived, manuallyEdited, readOnly, current])\n\n // The composed path parts (routable collections with a document editor only).\n const siblings = draft ? source.documents() : []\n // Draft-derived (routes + locale only, no `frontendUrl`) — the composed path is a\n // read-only preview that updates as you type, mirroring the detail editor's draft\n // URL. The header's published-gated \"View live\" stays the sole open-live action,\n // so the draft/live distinction is preserved (an unpublished slug never links out).\n const parts: SlugPathParts | undefined =\n draft && routable\n ? resolveSlugPath({ routes, localeConfig }, source.schema, draft, { siblings, locale })\n : undefined\n // The classified context segments (0.0.42, round 3) — the same `resolveUrlSegments`\n // the header URL row uses, so the slug prefix and the header path attribute each\n // segment identically. Everything before this document's own `current` slug is the\n // context prefix; its LAST segment is the immediate parent shown in the compact pill.\n const contextSegments: UrlSegment[] =\n draft && routable\n ? resolveUrlSegments({ routes, localeConfig }, source.schema, draft, { siblings, locale }).filter(\n (s) => s.kind !== 'current',\n )\n : []\n const lastContext = contextSegments[contextSegments.length - 1]\n\n // Default (sync) uniqueness — the first colliding sibling's title, or null.\n const defaultCollisionTitle = useMemo<string | null>(() => {\n if (slugConfig?.unique || !draft) return null\n const trimmed = current.trim()\n if (trimmed === '') return null\n const hit = findSlugCollision(trimmed, draft, source.documents(), {\n collection: source.schema,\n locale,\n localeConfig,\n })\n return hit ? source.titleOf({ collection: source.collectionId, id: hit.id }) : null\n }, [current, draft, slugConfig, locale, localeConfig, source])\n\n // Custom (possibly async) uniqueness hook — race-guarded.\n const [asyncTaken, setAsyncTaken] = useState(false)\n useEffect(() => {\n const unique = slugConfig?.unique\n if (!unique || !draft) {\n setAsyncTaken(false)\n return\n }\n const trimmed = current.trim()\n if (trimmed === '') {\n setAsyncTaken(false)\n return\n }\n let cancelled = false\n Promise.resolve(unique(trimmed, { document: draft, locale, siblings: source.documents() }))\n .then((ok) => {\n if (!cancelled) setAsyncTaken(ok === false)\n })\n .catch(() => {\n if (!cancelled) setAsyncTaken(false)\n })\n return () => {\n cancelled = true\n }\n }, [current, slugConfig, draft, locale, source])\n\n const collisionMessage = slugConfig?.unique\n ? asyncTaken\n ? translate('cms.field.slug.takenGeneric')\n : undefined\n : defaultCollisionTitle\n ? translate('cms.field.slug.taken', { title: defaultCollisionTitle })\n : undefined\n\n function handleInput(next: string) {\n onChange(next || undefined)\n // Clearing re-enables auto-derive; any non-empty entry is a manual override.\n setManuallyEdited(next.trim() !== '')\n }\n\n function regenerate() {\n setManuallyEdited(false)\n const next = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n onChange(next || undefined)\n }\n\n // No document editor (a picker), or a name-based auto-upgrade on a non-routable\n // collection: keep the historical plain input, no slug chrome (no regression).\n if (!editor || (!explicit && !routable)) {\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n\n const input = (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n placeholder={derived || undefined}\n onChange={(e) => handleInput(e.target.value)}\n className={cn(parts ? 'h-7 min-w-[10ch] flex-1 bg-background font-mono text-xs' : 'flex-1')}\n />\n )\n const regenerateButton = !readOnly ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={regenerate}\n aria-label={translate('cms.field.slug.regenerate')}\n title={translate('cms.field.slug.regenerate')}\n >\n <RotateCw />\n </Button>\n ) : null\n\n // The compact, ellipsized read-only prefix (0.0.39 \"hybrid split\", round-3 clickable):\n // only the LAST context segment (`…/produkte/`) so a deep path can't overflow the\n // narrow Details sidebar — but that shown segment is now CLICKABLE with the same\n // navigation semantics as the header URL row (an ancestor DOCUMENT links to its\n // editor; a static route literal stays plain). The full composed path is the tooltip.\n const prefixTitle =\n parts?.path ??\n (contextSegments.length > 0 ? `/${contextSegments.map((s) => s.text).join('/')}/` : '/')\n\n return (\n <Stack gap=\"2\">\n {parts ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-composed-path\">\n <span\n className=\"inline-flex min-w-0 shrink-0 items-center rounded bg-muted/40 px-1.5 py-1 font-mono text-xs text-muted-foreground ring-1 ring-inset ring-border\"\n title={prefixTitle}\n data-testid=\"slug-prefix\"\n >\n {contextSegments.length === 0 ? (\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n ) : (\n <>\n <span aria-hidden className=\"text-muted-foreground/50\">\n {contextSegments.length > 1 ? '…/' : '/'}\n </span>\n {lastContext ? (\n <DocumentUrlSegment\n segment={lastContext}\n projectId={editor?.projectId}\n collectionId={source.collectionId}\n />\n ) : null}\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n </>\n )}\n </span>\n {input}\n {regenerateButton}\n </Row>\n ) : (\n <Row gap=\"1\" align=\"center\">\n {input}\n {regenerateButton}\n </Row>\n )}\n\n {collisionMessage ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-collision\">\n <AlertTriangle className=\"size-3.5 shrink-0 text-warning\" aria-hidden />\n <Text size=\"xs\" tone=\"muted\">\n {collisionMessage}\n </Text>\n </Row>\n ) : null}\n </Stack>\n )\n}\n\nfunction RelationField({\n field,\n value,\n onChange,\n readOnly,\n}: {\n field: RelationFieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const [open, setOpen] = useState(false)\n const refs = toRefArray(value)\n const projectId = source.projectId\n\n // EC-218: for the editing document's `parent` self-relation, exclude the\n // document itself and its descendants from the picker — choosing one would make\n // the page its own ancestor (a cycle). Only applies to the parent field of a\n // hierarchical collection; ordinary relations (and other self-relations) are\n // unrestricted. validateDocument is the backstop where this context is absent.\n const excludeIds = useMemo<Set<string> | undefined>(() => {\n if (!editor || field.target !== editor.collection.id) return undefined\n if (parentRelationField(editor.collection)?.name !== field.name) return undefined\n const ids = descendantIds(editor.docRef.id, source.referenceCandidates(editor.collection.id))\n ids.add(editor.docRef.id)\n return ids\n }, [editor, field.target, field.name, source])\n\n function apply(next: DocumentRef[]) {\n onChange(field.multiple ? next : (next[0] ?? undefined))\n }\n\n return (\n <Stack gap=\"2\">\n {refs.length > 0 ? (\n <Stack gap=\"1\">\n {refs.map((ref, i) => {\n // EC-296: the relation title navigates to the referenced document (autosave\n // keeps the current edit safe). Without a projectId (no persistence, e.g.\n // fixtures) it stays plain text. EC-246c: full-width row, not a pill —\n // long titles wrap awkwardly in a pill and a narrow field crushes it.\n const title = source.titleOf(ref)\n const label = (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <Link2 className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{title}</span>\n </span>\n )\n return (\n <RowItem\n key={`${ref.id}-${i}`}\n data-testid=\"relation-value\"\n actions={\n !readOnly ? (\n <>\n {field.multiple === false ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('cms.relation.change')}\n title={translate('cms.relation.change')}\n onClick={() => setOpen(true)}\n >\n <Pencil />\n </Button>\n ) : null}\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('common.remove')}\n title={translate('common.remove')}\n className=\"hover:text-destructive\"\n onClick={() => apply(refs.filter((r) => r.id !== ref.id))}\n >\n <X />\n </Button>\n </>\n ) : undefined\n }\n >\n {projectId ? (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(ref.collection, ref.id) }}\n title={translate('cms.relation.openTitle', { title })}\n className=\"text-sm font-medium hover:text-primary hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <Text as=\"span\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n </RowItem>\n )\n })}\n </Stack>\n ) : null}\n {!readOnly && (refs.length === 0 || field.multiple) ? (\n <Row>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Plus /> {refs.length === 0 ? translate('cms.relation.pick') : translate('common.add')}\n </Button>\n </Row>\n ) : null}\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={refs}\n open={open}\n onOpenChange={setOpen}\n onChange={apply}\n excludeIds={excludeIds}\n />\n </Stack>\n )\n}\n"]}
|
|
@@ -20,7 +20,14 @@ export function resolveFieldRenderers(renderers) {
|
|
|
20
20
|
value: component,
|
|
21
21
|
})),
|
|
22
22
|
allowNew: true,
|
|
23
|
-
|
|
23
|
+
// EC-478: the rejection carries its catalog key as well as its English, so the
|
|
24
|
+
// `{reason}` half of `invalid-override` localizes with the sentence around it.
|
|
25
|
+
validate: (entry) => typeof entry.value !== 'function'
|
|
26
|
+
? {
|
|
27
|
+
message: 'the renderer is not a component',
|
|
28
|
+
key: 'customization.issue.reason.rendererNotAComponent',
|
|
29
|
+
}
|
|
30
|
+
: null,
|
|
24
31
|
});
|
|
25
32
|
return { get: (control) => resolved.get(control), issues: resolved.issues };
|
|
26
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-renderer.js","sourceRoot":"","sources":["../../../src/components/cms/field-renderer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAE9D,OAAO,EAAE,+BAA+B,EAAE,MAAM,iCAAiC,CAAA;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AA8BvD;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAA0D;IAE1D,MAAM,QAAQ,GAAG,gBAAgB,CAAsB;QACrD,KAAK,EAAE,gBAAgB;QACvB,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;YACxE,EAAE,EAAE,OAAO;YACX,KAAK,EAAE,SAAS;SACjB,CAAC,CAAC;QACH,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"field-renderer.js","sourceRoot":"","sources":["../../../src/components/cms/field-renderer.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, useMemo } from 'react'\nimport type { ReactNode } from 'react'\nimport { AlertTriangle } from 'lucide-react'\nimport { resolveOverrides } from '@elytracms/core/studio-core'\nimport type { CustomizationIssue } from '@elytracms/core/studio-core'\nimport { resolveDeploymentFieldRenderers } from '@elytracms/studio/lib/workspace'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { Input, Row, Text } from '@elytracms/studio/ui'\nimport type { CustomFieldRenderer } from '../app-views/studio-config'\n\n/**\n * EC-238 — custom field renderers, an instance of the EC-236 customization seam.\n *\n * A project registers a React component (via `defineStudio({ fieldRenderers })`)\n * keyed by CONTROL name to REPLACE the built-in document-editor control. A field\n * opts in PER-FIELD with `form: { control: '<name>' }` — so a renderer targets\n * exactly the fields that ask for it, not every field of a datatype. (`control` is\n * a presentation hint on the field; the field's `type` stays its honest datatype.\n * That split is why a colour is `type: 'text'` + `control: 'color'`, not a bogus\n * `plugin.color` type.) The contract is the exact {@link FieldControl} props seam,\n * so a project component drops in unchanged and reuses internal helpers\n * (relation/asset pickers, validation state) via the exported studio hooks\n * (`useCms`, `useOptionalDocumentEditor`). Resolution falls back to the built-in\n * control, and every failure mode — a non-component value, an unknown control on a\n * field, or a renderer that throws — surfaces a visible issue, never a silent drop\n * or a crash.\n */\n\nexport type { CustomFieldRenderer, CustomFieldRendererProps } from '../app-views/studio-config'\n\nexport interface ResolvedFieldRenderers {\n /** The custom renderer for a control name, or `undefined` → use the built-in. */\n get(control: string): CustomFieldRenderer | undefined\n /** Resolution issues (non-component); located by `id` = control name. */\n issues: CustomizationIssue[]\n}\n\n/**\n * Resolve the studio config's custom field renderers through the shared\n * customization core (EC-236): a registry keyed by control name, rejecting a\n * non-component with a visible issue and keeping the built-in. The map's keys are\n * unique by construction, so duplicates are structurally impossible.\n */\nexport function resolveFieldRenderers(\n renderers: Record<string, CustomFieldRenderer> | undefined,\n): ResolvedFieldRenderers {\n const resolved = resolveOverrides<CustomFieldRenderer>({\n point: 'fieldRenderers',\n defaults: [],\n overrides: Object.entries(renderers ?? {}).map(([control, component]) => ({\n id: control,\n value: component,\n })),\n allowNew: true,\n // EC-478: the rejection carries its catalog key as well as its English, so the\n // `{reason}` half of `invalid-override` localizes with the sentence around it.\n validate: (entry) =>\n typeof entry.value !== 'function'\n ? {\n message: 'the renderer is not a component',\n key: 'customization.issue.reason.rendererNotAComponent',\n }\n : null,\n })\n return { get: (control) => resolved.get(control), issues: resolved.issues }\n}\n\n/** The active studio's resolved field renderers (config is static per studio boot). */\nexport function useFieldRenderers(): ResolvedFieldRenderers {\n return useMemo(() => resolveFieldRenderers(resolveDeploymentFieldRenderers()), [])\n}\n\n/** A visible, inline field-renderer issue — the customization seam's \"never silent\". */\nexport function FieldRendererIssue({ message }: { message: string }) {\n return (\n <Row gap=\"1\" align=\"center\" className=\"text-amber-600 dark:text-amber-400\" title={message}>\n <AlertTriangle aria-hidden className=\"size-3.5\" />\n <Text size=\"xs\">{message}</Text>\n </Row>\n )\n}\n\n/**\n * Error boundary around a custom renderer: a renderer that throws falls back to\n * the built-in control (passed as `fallback`) with a visible `issue` above it,\n * so a broken third-party component degrades the one field, never the editor.\n */\nexport class FieldRendererBoundary extends Component<\n { fallback: ReactNode; issue: ReactNode; children: ReactNode },\n { failed: boolean }\n> {\n override state = { failed: false }\n static getDerivedStateFromError() {\n return { failed: true }\n }\n override render() {\n if (this.state.failed) {\n return (\n <>\n {this.props.issue}\n {this.props.fallback}\n </>\n )\n }\n return this.props.children\n }\n}\n\n/**\n * Example custom field renderer (EC-238 DoD): a colour control proving reuse of\n * the studio form primitives and a save round-trip. A consuming repo registers it\n * (or its own) with `defineStudio({ fieldRenderers: { color: colorFieldRenderer } })`\n * and opts a field in with `form: { control: 'color' }` — the field's datatype\n * stays `text` (a `#rrggbb` string).\n */\nexport const colorFieldRenderer: CustomFieldRenderer = ({ value, onChange, readOnly, id }) => {\n const hex = typeof value === 'string' && /^#[0-9a-f]{6}$/i.test(value) ? value : '#000000'\n return (\n <Row gap=\"2\" align=\"center\">\n <input\n id={id}\n type=\"color\"\n disabled={readOnly}\n value={hex}\n onChange={(event) => onChange(event.target.value)}\n aria-label={translate('cms.field.colour')}\n className=\"h-8 w-12 cursor-pointer rounded-md border border-input bg-background disabled:opacity-50\"\n />\n <Input\n value={typeof value === 'string' ? value : ''}\n disabled={readOnly}\n placeholder=\"#rrggbb\"\n onChange={(event) => onChange(event.target.value || undefined)}\n className=\"w-28 font-mono text-xs\"\n />\n </Row>\n )\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Badge, Button, Code, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Stack, Text, } from '@elytracms/studio/ui';
|
|
4
4
|
import { translate } from '@elytracms/studio/lib/i18n';
|
|
5
|
+
import { cmsValidationIssueMessage } from '@elytracms/studio/lib/persona/labels';
|
|
5
6
|
import { useCollectionView } from '../collection-view/collection-view-context.js';
|
|
6
7
|
/** Import collection data from JSON with validation + error reporting (brief §8.4, EC-079). */
|
|
7
8
|
export function ImportDialog({ collectionId, open, onOpenChange, }) {
|
|
@@ -31,6 +32,6 @@ export function ImportDialog({ collectionId, open, onOpenChange, }) {
|
|
|
31
32
|
if (outcome)
|
|
32
33
|
setReport(outcome);
|
|
33
34
|
}
|
|
34
|
-
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: translate('cms.import.title') }), _jsxs(DialogDescription, { children: ["Paste a JSON array of documents for ", _jsx(Code, { tone: "muted", children: collectionId }), ". Each is validated against the collection schema before import."] })] }), _jsx("textarea", { value: text, onChange: (e) => setText(e.target.value), rows: 8, placeholder: '[{ "id": "post-x", "values": { "slug": "x" }, ... }]', className: "w-full rounded-md border border-input bg-background p-2.5 font-mono text-xs text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none" }), parseError ? (_jsx(Text, { size: "sm", className: "text-destructive", children: parseError })) : null, report ? (_jsxs(Stack, { gap: "2", className: "rounded-md border border-border p-3", children: [_jsx(Badge, { variant: report.added > 0 ? 'success' : 'outline', children: translate('cms.import.imported', { count: report.added }) }), report.rejected.length > 0 ? (_jsxs(Stack, { gap: "1", children: [_jsx(Text, { size: "xs", tone: "muted", children: translate('cms.import.rejected', { count: report.rejected.length }) }), report.rejected.map((r, i) => (_jsxs(Text, { size: "xs", className: "text-destructive", children: [_jsx(Code, { tone: "muted", children: r.id }), " \u2014
|
|
35
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: translate('cms.import.title') }), _jsxs(DialogDescription, { children: ["Paste a JSON array of documents for ", _jsx(Code, { tone: "muted", children: collectionId }), ". Each is validated against the collection schema before import."] })] }), _jsx("textarea", { value: text, onChange: (e) => setText(e.target.value), rows: 8, placeholder: '[{ "id": "post-x", "values": { "slug": "x" }, ... }]', className: "w-full rounded-md border border-input bg-background p-2.5 font-mono text-xs text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none" }), parseError ? (_jsx(Text, { size: "sm", className: "text-destructive", children: parseError })) : null, report ? (_jsxs(Stack, { gap: "2", className: "rounded-md border border-border p-3", children: [_jsx(Badge, { variant: report.added > 0 ? 'success' : 'outline', children: translate('cms.import.imported', { count: report.added }) }), report.rejected.length > 0 ? (_jsxs(Stack, { gap: "1", children: [_jsx(Text, { size: "xs", tone: "muted", children: translate('cms.import.rejected', { count: report.rejected.length }) }), report.rejected.map((r, i) => (_jsxs(Text, { size: "xs", className: "text-destructive", children: [_jsx(Code, { tone: "muted", children: r.id }), " \u2014", ' ', r.issues[0] ? cmsValidationIssueMessage(r.issues[0]) : undefined] }, `${r.id}-${i}`)))] })) : null] })) : null, _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: translate('common.close') }), _jsx(Button, { onClick: runImport, disabled: !text.trim(), children: translate('cms.import.confirm') })] })] }) }));
|
|
35
36
|
}
|
|
36
37
|
//# sourceMappingURL=import-export.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-export.js","sourceRoot":"","sources":["../../../src/components/cms/import-export.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"import-export.js","sourceRoot":"","sources":["../../../src/components/cms/import-export.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from 'react'\nimport {\n Badge,\n Button,\n Code,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { cmsValidationIssueMessage } from '@elytracms/studio/lib/persona/labels'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport type { ImportReport } from './cms-store'\n\n/** Import collection data from JSON with validation + error reporting (brief §8.4, EC-079). */\nexport function ImportDialog({\n collectionId,\n open,\n onOpenChange,\n}: {\n collectionId: string\n open: boolean\n onOpenChange: (open: boolean) => void\n}) {\n const source = useCollectionView()\n const [text, setText] = useState('')\n const [report, setReport] = useState<ImportReport | null>(null)\n const [parseError, setParseError] = useState<string | null>(null)\n\n useEffect(() => {\n if (open) {\n setText('')\n setReport(null)\n setParseError(null)\n }\n }, [open])\n\n function runImport() {\n setParseError(null)\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n setParseError(translate('cms.import.invalidJson'))\n return\n }\n const items = Array.isArray(parsed) ? parsed : [parsed]\n const outcome = source.imports?.importDocuments(items)\n if (outcome) setReport(outcome)\n }\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-w-lg\">\n <DialogHeader>\n <DialogTitle>{translate('cms.import.title')}</DialogTitle>\n <DialogDescription>\n Paste a JSON array of documents for <Code tone=\"muted\">{collectionId}</Code>. Each is\n validated against the collection schema before import.\n </DialogDescription>\n </DialogHeader>\n\n <textarea\n value={text}\n onChange={(e) => setText(e.target.value)}\n rows={8}\n placeholder='[{ \"id\": \"post-x\", \"values\": { \"slug\": \"x\" }, ... }]'\n className=\"w-full rounded-md border border-input bg-background p-2.5 font-mono text-xs text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none\"\n />\n\n {parseError ? (\n <Text size=\"sm\" className=\"text-destructive\">\n {parseError}\n </Text>\n ) : null}\n\n {report ? (\n <Stack gap=\"2\" className=\"rounded-md border border-border p-3\">\n <Badge variant={report.added > 0 ? 'success' : 'outline'}>\n {translate('cms.import.imported', { count: report.added })}\n </Badge>\n {report.rejected.length > 0 ? (\n <Stack gap=\"1\">\n <Text size=\"xs\" tone=\"muted\">\n {translate('cms.import.rejected', { count: report.rejected.length })}\n </Text>\n {report.rejected.map((r, i) => (\n <Text key={`${r.id}-${i}`} size=\"xs\" className=\"text-destructive\">\n <Code tone=\"muted\">{r.id}</Code> —{' '}\n {r.issues[0] ? cmsValidationIssueMessage(r.issues[0]) : undefined}\n </Text>\n ))}\n </Stack>\n ) : null}\n </Stack>\n ) : null}\n\n <DialogFooter>\n <Button variant=\"ghost\" onClick={() => onOpenChange(false)}>\n {translate('common.close')}\n </Button>\n <Button onClick={runImport} disabled={!text.trim()}>\n {translate('cms.import.confirm')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n"]}
|
|
@@ -14,8 +14,10 @@ import type { CmsValidationIssue, CollectionDef } from '@elytracms/core/cms-core
|
|
|
14
14
|
* names the deepest resolvable field's localized label, never a raw leaf token
|
|
15
15
|
* when a def resolves. Card copy is localized studio-side: the title via
|
|
16
16
|
* `cmsIssueLabel` (catalog-routed), the body via the `issueBodyDescriptor`
|
|
17
|
-
* template where one exists
|
|
18
|
-
*
|
|
17
|
+
* template where one exists — it is PERSONA copy, naming the field by its localized
|
|
18
|
+
* label rather than its raw name, so it keeps precedence — else the issue's own
|
|
19
|
+
* message, localized through `cmsValidationIssueMessage` (EC-487) and degrading to
|
|
20
|
+
* the producer's English only for an issue that carries no catalog key.
|
|
19
21
|
*
|
|
20
22
|
* Persona boundary (EC-192): rows show the plain-language `cmsIssueLabel`; the raw
|
|
21
23
|
* `code` rides along in `title=` for engineers, never as visible copy.
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { CircleAlert, CircleCheck, TriangleAlert } from 'lucide-react';
|
|
3
3
|
import { Button, Row, Stack, Text } from '@elytracms/studio/ui';
|
|
4
4
|
import { cn } from '@elytracms/studio/lib/utils';
|
|
5
|
-
import { cmsIssueLabel } from '@elytracms/studio/lib/persona/labels';
|
|
5
|
+
import { cmsIssueLabel, cmsValidationIssueMessage } from '@elytracms/studio/lib/persona/labels';
|
|
6
6
|
import { translate } from '@elytracms/studio/lib/i18n';
|
|
7
7
|
import { fieldLabel } from './cms-labels.js';
|
|
8
8
|
import { issueBodyDescriptor, issueJumpTarget } from './issue-copy.js';
|
|
@@ -21,8 +21,10 @@ import { issueBodyDescriptor, issueJumpTarget } from './issue-copy.js';
|
|
|
21
21
|
* names the deepest resolvable field's localized label, never a raw leaf token
|
|
22
22
|
* when a def resolves. Card copy is localized studio-side: the title via
|
|
23
23
|
* `cmsIssueLabel` (catalog-routed), the body via the `issueBodyDescriptor`
|
|
24
|
-
* template where one exists
|
|
25
|
-
*
|
|
24
|
+
* template where one exists — it is PERSONA copy, naming the field by its localized
|
|
25
|
+
* label rather than its raw name, so it keeps precedence — else the issue's own
|
|
26
|
+
* message, localized through `cmsValidationIssueMessage` (EC-487) and degrading to
|
|
27
|
+
* the producer's English only for an issue that carries no catalog key.
|
|
26
28
|
*
|
|
27
29
|
* Persona boundary (EC-192): rows show the plain-language `cmsIssueLabel`; the raw
|
|
28
30
|
* `code` rides along in `title=` for engineers, never as visible copy.
|
|
@@ -47,6 +49,6 @@ function IssueRow({ issue, collection, onJumpToField, }) {
|
|
|
47
49
|
: '';
|
|
48
50
|
const body = issueBodyDescriptor(issue, fieldName);
|
|
49
51
|
const Icon = isError ? CircleAlert : TriangleAlert;
|
|
50
|
-
return (_jsxs(Stack, { gap: "1", className: cn('rounded-md border px-2.5 py-2', isError ? 'border-destructive/30 bg-destructive/5' : 'border-warning/30 bg-warning/5'), children: [_jsxs(Row, { gap: "2", align: "start", children: [_jsx(Icon, { className: cn('mt-0.5 size-3.5 shrink-0', isError ? 'text-destructive' : 'text-warning'), "aria-hidden": true }), _jsxs(Stack, { gap: "1", className: "min-w-0", children: [_jsx(Text, { size: "xs", weight: "semibold", title: issue.code, children: cmsIssueLabel(issue.code) }), _jsx(Text, { size: "xs", tone: "muted", children: body !== null ? translate(body.key, body.vars) : issue
|
|
52
|
+
return (_jsxs(Stack, { gap: "1", className: cn('rounded-md border px-2.5 py-2', isError ? 'border-destructive/30 bg-destructive/5' : 'border-warning/30 bg-warning/5'), children: [_jsxs(Row, { gap: "2", align: "start", children: [_jsx(Icon, { className: cn('mt-0.5 size-3.5 shrink-0', isError ? 'text-destructive' : 'text-warning'), "aria-hidden": true }), _jsxs(Stack, { gap: "1", className: "min-w-0", children: [_jsx(Text, { size: "xs", weight: "semibold", title: issue.code, children: cmsIssueLabel(issue.code) }), _jsx(Text, { size: "xs", tone: "muted", children: body !== null ? translate(body.key, body.vars) : cmsValidationIssueMessage(issue) })] })] }), jump !== null ? (_jsx(Row, { className: "pl-[1.375rem]", children: _jsx(Button, { size: "sm", variant: "link", className: "h-auto p-0 text-xs", onClick: () => onJumpToField(jump.path, jump.locale), children: translate('cms.issues.goToField', { field: fieldName }) }) })) : null] }));
|
|
51
53
|
}
|
|
52
54
|
//# sourceMappingURL=issues-pane.js.map
|