@takuhon/ui 1.0.0 → 1.3.0

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.
@@ -349,6 +349,10 @@ declare const EN: {
349
349
  readonly 'field.settings.enableJsonLd': "Emit Schema.org JSON-LD";
350
350
  readonly 'field.settings.enableApi': "Expose the public read API";
351
351
  readonly 'field.settings.enableAnalytics': "Enable first-party analytics";
352
+ readonly 'field.settings.contact': "Contact form";
353
+ readonly 'field.contactSettings.enabled': "Enable contact form";
354
+ readonly 'field.contactSettings.turnstileSiteKey': "Turnstile site key (public)";
355
+ readonly 'field.contactSettings.subjectPrefix': "Email subject prefix";
352
356
  readonly 'field.settings.publicVisibility': "Public sections";
353
357
  readonly 'field.publicVisibility.links': "Links";
354
358
  readonly 'field.publicVisibility.careers': "Experience";
@@ -268,6 +268,10 @@ var EN = {
268
268
  "field.settings.enableJsonLd": "Emit Schema.org JSON-LD",
269
269
  "field.settings.enableApi": "Expose the public read API",
270
270
  "field.settings.enableAnalytics": "Enable first-party analytics",
271
+ "field.settings.contact": "Contact form",
272
+ "field.contactSettings.enabled": "Enable contact form",
273
+ "field.contactSettings.turnstileSiteKey": "Turnstile site key (public)",
274
+ "field.contactSettings.subjectPrefix": "Email subject prefix",
271
275
  "field.settings.publicVisibility": "Public sections",
272
276
  "field.publicVisibility.links": "Links",
273
277
  "field.publicVisibility.careers": "Experience",
@@ -1303,6 +1307,17 @@ var SECTION_REGISTRY = {
1303
1307
  "settings.activity.github": { label: "GitHub" },
1304
1308
  "settings.activity.wakatime": { label: "WakaTime" },
1305
1309
  "settings.publicVisibility": { render: renderVisibilityMatrix },
1310
+ // Contact form (1.1.0) — labelled "Contact form" so its group legend does not
1311
+ // collide with the profile "Contact" section. Only public config lives here;
1312
+ // the Turnstile secret and recipient are environment configuration.
1313
+ "settings.contact": { label: getAdminLabel("field.settings.contact") },
1314
+ "settings.contact.enabled": { label: getAdminLabel("field.contactSettings.enabled") },
1315
+ "settings.contact.turnstileSiteKey": {
1316
+ label: getAdminLabel("field.contactSettings.turnstileSiteKey")
1317
+ },
1318
+ "settings.contact.subjectPrefix": {
1319
+ label: getAdminLabel("field.contactSettings.subjectPrefix")
1320
+ },
1306
1321
  // Cross-section reference selectors (decision C): dropdowns of sibling-section
1307
1322
  // ids. courses / testScores / recommendations point at education / careers.
1308
1323
  "courses.relatedEducationId": {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/admin/index.ts","../../src/admin/errors.ts","../../src/admin/primitives/Field.tsx","../../src/admin/primitives/TextField.tsx","../../src/admin/primitives/TextAreaField.tsx","../../src/admin/primitives/SelectField.tsx","../../src/admin/primitives/CheckboxField.tsx","../../src/admin/primitives/ImageField.tsx","../../src/admin/admin-labels.ts","../../src/admin/primitives/GravatarField.tsx","../../src/admin/primitives/LocaleTabs.tsx","../../src/admin/primitives/Repeater.tsx","../../src/admin/ids.ts","../../src/admin/localized.ts","../../src/admin/schema-form/field-classification.ts","../../src/admin/schema-form/field-registry.ts","../../src/admin/schema-form/SchemaForm.tsx","../../src/admin/schema-form/section-registry.tsx","../../src/admin/schema-form/custom-fields.tsx","../../src/admin/RawJsonEditor.tsx","../../src/admin/AdminEditor.tsx"],"sourcesContent":["/**\n * @takuhon/ui/admin — React form components for the takuhon admin editor.\n *\n * These are the building blocks behind the Cloudflare admin form UI (spec\n * §14.1 Phase 5). They are presentational and transport-agnostic: each is a\n * controlled component that takes a value plus `onChange`, with field errors\n * supplied as a {@link FieldErrorIndex} so server (RFC 7807) and client\n * (`@takuhon/core` `validate`) failures map to the same fields. Co-located CSS\n * Modules are emitted to `dist/admin/` and bundled by the consumer.\n *\n * Importing this entry also pulls in the shared design tokens, so the admin\n * components are themed standalone without depending on the profile UI entry.\n */\n\nimport '../styles/tokens.css';\n\nexport {\n canonicalPointer,\n collectErrorsUnder,\n errorsAt,\n hasErrorsUnder,\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\n\nexport { Field, type FieldProps, type FieldControlProps } from './primitives/Field.js';\nexport { TextField, type TextFieldProps } from './primitives/TextField.js';\nexport { TextAreaField, type TextAreaFieldProps } from './primitives/TextAreaField.js';\nexport { SelectField, type SelectFieldProps, type SelectOption } from './primitives/SelectField.js';\nexport { CheckboxField, type CheckboxFieldProps } from './primitives/CheckboxField.js';\nexport {\n ImageField,\n type ImageFieldProps,\n type AssetUploadResult,\n type UploadAsset,\n} from './primitives/ImageField.js';\nexport { GravatarField, type GravatarFieldProps } from './primitives/GravatarField.js';\nexport { LocaleTabs, type LocaleTabsProps } from './primitives/LocaleTabs.js';\nexport { Repeater, type RepeaterProps } from './primitives/Repeater.js';\n\nexport { getAdminLabel, type AdminLabelKey } from './admin-labels.js';\n\n// The schema-driven form engine renders every section straight from the JSON\n// Schema; the former per-section forms (ProfileForm, LinksForm, …) are gone.\nexport { SchemaForm, type SchemaFormProps } from './schema-form/SchemaForm.js';\nexport {\n sectionFieldKind,\n classifyNode,\n type FieldKind,\n type SchemaNode,\n} from './schema-form/field-classification.js';\nexport {\n EMPTY_REGISTRY,\n humanize,\n hintAt,\n type FieldHint,\n type FieldRegistry,\n type CustomFieldContext,\n} from './schema-form/field-registry.js';\nexport {\n ADMIN_SECTIONS,\n SECTION_REGISTRY,\n type AdminSection,\n} from './schema-form/section-registry.js';\n\nexport { RawJsonEditor, type RawJsonEditorProps } from './RawJsonEditor.js';\nexport { AdminEditor, type AdminEditorProps, type AdminSaveOutcome } from './AdminEditor.js';\n","/**\n * Field-error plumbing shared by the admin form components.\n *\n * Validation failures reach the editor in two shapes that mean the same thing:\n *\n * - `@takuhon/core`'s {@link ValidationError}, produced by a client-side\n * `validate()` call, carries an RFC 6901 `pointer` such as\n * `\"/profile/displayName/en\"`.\n * - The server's RFC 7807 response (`api.md §5`) carries the same location as a\n * `path` with a leading `#` fragment marker, e.g. `\"#/profile/displayName/en\"`.\n *\n * Both are normalized to a single canonical pointer so a field can look up its\n * own errors regardless of where they came from.\n */\nimport type { ValidationError } from '@takuhon/core';\n\n/** A field error in either the core (`pointer`) or RFC 7807 wire (`path`) shape. */\nexport interface FieldErrorLike {\n pointer?: string;\n path?: string;\n message: string;\n}\n\n/**\n * Canonical RFC 6901 pointer: no leading `#`, a leading `/` for any non-root\n * location, and `\"\"` for the document root. Idempotent.\n */\nexport function canonicalPointer(raw: string): string {\n let pointer = raw.trim();\n if (pointer.startsWith('#')) pointer = pointer.slice(1);\n if (pointer !== '' && !pointer.startsWith('/')) pointer = `/${pointer}`;\n return pointer;\n}\n\n/** Maps a canonical pointer to the messages reported at that exact location. */\nexport type FieldErrorIndex = ReadonlyMap<string, readonly string[]>;\n\n/** Group a flat error list by canonical pointer, preserving message order. */\nexport function indexErrors(errors: readonly FieldErrorLike[]): FieldErrorIndex {\n const index = new Map<string, string[]>();\n for (const error of errors) {\n const key = canonicalPointer(error.pointer ?? error.path ?? '');\n const existing = index.get(key);\n if (existing) existing.push(error.message);\n else index.set(key, [error.message]);\n }\n return index;\n}\n\n/** Convenience over {@link indexErrors} for a core `validate()` failure list. */\nexport function indexValidationErrors(errors: readonly ValidationError[]): FieldErrorIndex {\n return indexErrors(errors);\n}\n\n/** Messages reported at exactly `pointer` (empty array when none). */\nexport function errorsAt(index: FieldErrorIndex, pointer: string): readonly string[] {\n return index.get(canonicalPointer(pointer)) ?? [];\n}\n\n/**\n * Whether any error sits at or below `prefix` — used to badge a section or a\n * repeater item that contains an invalid field deeper in the tree.\n */\nexport function hasErrorsUnder(index: FieldErrorIndex, prefix: string): boolean {\n const base = canonicalPointer(prefix);\n for (const key of index.keys()) {\n if (key === base || key.startsWith(`${base}/`)) return true;\n }\n return false;\n}\n\n/**\n * All messages at or below `prefix`, in pointer order. Used by aggregate\n * controls (a comma-separated list edited as one field) so item-level failures\n * reported at `${prefix}/${itemIndex}` still surface on the single input.\n */\nexport function collectErrorsUnder(index: FieldErrorIndex, prefix: string): string[] {\n const base = canonicalPointer(prefix);\n const messages: string[] = [];\n for (const [key, list] of index) {\n if (key === base || key.startsWith(`${base}/`)) messages.push(...list);\n }\n return messages;\n}\n\n/** An empty index, handy as a default prop. */\nexport const NO_FIELD_ERRORS: FieldErrorIndex = new Map();\n","import { useId } from 'react';\n\nimport styles from './Field.module.css';\n\n/** Identifiers a {@link Field} hands to the control it wraps. */\nexport interface FieldControlProps {\n /** `id` for the control, paired with the rendered `<label htmlFor>`. */\n controlId: string;\n /** `aria-describedby` value linking the control to its hint/error text. */\n describedBy: string | undefined;\n /** Whether the control should advertise `aria-invalid`. */\n invalid: boolean;\n}\n\nexport interface FieldProps {\n /** Visible label text. */\n label: string;\n /** Validation messages to render beneath the control. */\n errors?: readonly string[];\n /** Optional helper text shown between the label and the control. */\n hint?: string;\n /** Marks the field visually and via `aria-required` on the control. */\n required?: boolean;\n /** Render the control, wired with the supplied accessibility ids. */\n children: (props: FieldControlProps) => React.ReactNode;\n}\n\n/**\n * Layout + accessibility wrapper for a single form control. Owns the `id`\n * wiring so the label, hint, error list, and control stay associated for\n * screen readers (WCAG 2.1 AA, spec §8.5). Presentational only — it holds no\n * value state; the wrapped control is controlled by its parent.\n */\nexport function Field({ label, errors, hint, required, children }: FieldProps): React.JSX.Element {\n const controlId = useId();\n const hintId = useId();\n const errorId = useId();\n const hasErrors = (errors?.length ?? 0) > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <div className={styles.field}>\n <label className={styles.label} htmlFor={controlId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </label>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n {children({ controlId, describedBy, invalid: hasErrors })}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {errors!.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n /**\n * HTML input type. Defaults to `'text'`; `'url'` for link/avatar URLs,\n * `'month'` for `YearMonth` values (a native month picker emits `YYYY-MM`).\n */\n type?: 'text' | 'url' | 'email' | 'month';\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n}\n\n/** A labelled single-line text input wired for accessibility via {@link Field}. */\nexport function TextField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n type = 'text',\n inputMode,\n}: TextFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <input\n id={controlId}\n className={styles.control}\n type={type}\n value={value}\n placeholder={placeholder}\n inputMode={inputMode}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextAreaFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n rows?: number;\n}\n\n/** A labelled multi-line text input wired for accessibility via {@link Field}. */\nexport function TextAreaField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n rows = 4,\n}: TextAreaFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <textarea\n id={controlId}\n className={`${styles.control} ${styles.textarea}`}\n value={value}\n rows={rows}\n placeholder={placeholder}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectFieldProps {\n label: string;\n value: string;\n options: readonly SelectOption[];\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n}\n\n/** A labelled `<select>` wired for accessibility via {@link Field}. */\nexport function SelectField({\n label,\n value,\n options,\n onChange,\n errors,\n hint,\n required,\n}: SelectFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <select\n id={controlId}\n className={styles.control}\n value={value}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n </Field>\n );\n}\n","import { useId } from 'react';\n\nimport styles from './controls.module.css';\n\nexport interface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n}\n\n/**\n * A labelled checkbox. Laid out checkbox-first (distinct from the stacked\n * {@link Field} controls), with the label associated via `htmlFor`.\n */\nexport function CheckboxField({ label, checked, onChange }: CheckboxFieldProps): React.JSX.Element {\n const id = useId();\n return (\n <div className={styles.checkboxRow}>\n <input\n id={id}\n className={styles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={(event) => {\n onChange(event.target.checked);\n }}\n />\n <label className={styles.checkboxLabel} htmlFor={id}>\n {label}\n </label>\n </div>\n );\n}\n","import { useId, useRef, useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './ImageField.module.css';\nimport controls from './controls.module.css';\n\n/** Outcome of an asset upload, returned by {@link UploadAsset}. */\nexport type AssetUploadResult =\n | { status: 'uploaded'; url: string; publicUrl: string }\n | { status: 'error'; message?: string };\n\n/**\n * Upload one image file and resolve where it now lives. Supplied by the host's\n * transport layer (it carries the admin token / origin); the UI stays\n * transport-agnostic.\n */\nexport type UploadAsset = (file: File) => Promise<AssetUploadResult>;\n\n/** `accept` attribute matching the MIME types the server accepts (security.md §4.1). */\nconst ACCEPT = 'image/jpeg,image/png,image/webp,image/gif';\n\nexport interface ImageFieldProps {\n label: string;\n /** Current image URL stored in the document. */\n value: string;\n onChange: (url: string) => void;\n errors?: readonly string[];\n hint?: string;\n /**\n * When provided, a file-upload control is rendered alongside the URL input;\n * a successful upload sets the URL to the returned (relative) path. When\n * omitted, the field is URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\n/**\n * Avatar / image field: a URL input plus, when {@link ImageFieldProps.uploadAsset}\n * is supplied, a file picker that uploads the chosen image and writes the\n * returned URL back into the field. The relative `url` (not the absolute\n * `publicUrl`) is stored so the reference stays valid across origins.\n *\n * No `<img>` preview is rendered: the admin CSP is `img-src 'self' blob:`, so a\n * preview of an arbitrary external URL would be blocked — the URL input is the\n * portable, CSP-safe surface, and the public preview shows the real image.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n errors,\n hint,\n uploadAsset,\n}: ImageFieldProps): React.JSX.Element {\n const fileId = useId();\n const statusId = useId();\n const fileRef = useRef<HTMLInputElement>(null);\n const [busy, setBusy] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const handleFile = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const file = event.target.files?.[0];\n if (!file || uploadAsset === undefined) return;\n setBusy(true);\n setUploadError(null);\n uploadAsset(file)\n .then((result) => {\n if (result.status === 'uploaded') {\n onChange(result.url);\n } else {\n setUploadError(result.message ?? getAdminLabel('status.uploadError'));\n }\n })\n .catch(() => {\n setUploadError(getAdminLabel('status.uploadError'));\n })\n .finally(() => {\n setBusy(false);\n // Clear the picker so re-selecting the same file fires `change` again.\n if (fileRef.current) fileRef.current.value = '';\n });\n };\n\n return (\n <Field label={label} errors={errors} hint={hint}>\n {({ controlId, describedBy, invalid }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"url\"\n value={value}\n aria-invalid={invalid || undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n {uploadAsset !== undefined ? (\n <div className={styles.uploadRow}>\n <label className={styles.uploadLabel} htmlFor={fileId}>\n {getAdminLabel('field.avatarUpload')}\n </label>\n <input\n id={fileId}\n ref={fileRef}\n type=\"file\"\n accept={ACCEPT}\n disabled={busy}\n aria-describedby={statusId}\n onChange={handleFile}\n />\n <span className={styles.uploadStatus} id={statusId} role=\"status\" aria-live=\"polite\">\n {busy ? getAdminLabel('status.uploading') : ''}\n </span>\n {uploadError !== null ? (\n <span className={styles.uploadError} role=\"alert\">\n {uploadError}\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </Field>\n );\n}\n","/**\n * UI strings for the admin editor.\n *\n * The admin surface is operator-only, so a single English dictionary ships\n * today; the lookup mirrors `getUILabel` (exact locale → base subtag →\n * English) so locales can be added later without touching call sites. Keys are\n * derived from the English dictionary, so every key is guaranteed to resolve.\n */\nimport type { LocaleTag } from '@takuhon/core';\n\nconst EN = {\n 'app.title': 'takuhon admin',\n 'toolbar.label': 'Editor actions',\n 'mode.label': 'Editing mode',\n 'mode.form': 'Form',\n 'mode.advanced': 'Advanced (JSON)',\n\n 'action.save': 'Save',\n 'action.reload': 'Reload',\n 'action.export': 'Export',\n 'action.import': 'Import',\n 'action.add': 'Add',\n 'action.remove': 'Remove',\n 'action.moveUp': 'Move up',\n 'action.moveDown': 'Move down',\n\n 'status.saving': 'Saving…',\n 'status.saved': 'Saved.',\n 'status.loading': 'Loading…',\n 'status.conflict':\n 'The profile changed on the server since it was loaded. Reload, then reapply the edits.',\n 'status.invalid': 'Some fields need attention before saving.',\n 'status.fixSummary': 'Please fix the following:',\n 'status.error': 'Something went wrong. Please try again.',\n 'status.imported': 'Imported. Review the fields, then save to apply.',\n 'status.importInvalid': 'The imported file is not a valid takuhon document.',\n 'status.uploading': 'Uploading…',\n 'status.uploadError': 'Upload failed. Please try again.',\n\n 'section.profile': 'Profile',\n 'section.about': 'About',\n 'section.links': 'Links',\n 'section.careers': 'Experience',\n 'section.projects': 'Projects',\n 'section.skills': 'Skills',\n 'section.settings': 'Settings',\n 'section.education': 'Education',\n 'section.certifications': 'Certifications',\n 'section.publications': 'Publications',\n 'section.honors': 'Honors & awards',\n 'section.volunteering': 'Volunteering',\n 'section.memberships': 'Memberships',\n 'section.languages': 'Languages',\n 'section.courses': 'Courses',\n 'section.patents': 'Patents',\n 'section.testScores': 'Test scores',\n 'section.recommendations': 'Recommendations',\n 'section.contact': 'Contact',\n 'section.meta': 'Metadata',\n\n 'field.displayName': 'Display name',\n 'field.tagline': 'Tagline',\n 'field.bio': 'Bio',\n 'field.avatarUrl': 'Avatar URL',\n 'field.avatarUpload': 'Upload image',\n 'field.avatarAlt': 'Avatar alternative text',\n 'field.gravatarEmail': 'Gravatar email',\n 'field.gravatarApply': 'Use Gravatar',\n 'field.location.country': 'Country',\n 'field.location.region': 'Region',\n 'field.location.locality': 'Locality',\n 'field.location.display': 'Location (display)',\n\n 'field.link.type': 'Type',\n 'field.link.url': 'URL',\n 'field.link.label': 'Label',\n 'field.link.iconUrl': 'Icon URL',\n 'field.link.featured': 'Featured',\n\n 'field.career.organization': 'Organization',\n 'field.career.role': 'Role',\n 'field.career.description': 'Description',\n 'field.career.startDate': 'Start',\n 'field.career.endDate': 'End',\n 'field.career.isCurrent': 'Current position',\n 'field.career.url': 'URL',\n\n 'field.project.title': 'Title',\n 'field.project.description': 'Description',\n 'field.project.url': 'URL',\n 'field.project.tags': 'Tags',\n 'field.project.highlighted': 'Highlighted',\n 'field.project.startDate': 'Start',\n 'field.project.endDate': 'End',\n\n 'field.skill.label': 'Label',\n 'field.skill.category': 'Category',\n\n 'field.settings.defaultLocale': 'Default locale',\n 'field.settings.fallbackLocale': 'Fallback locale',\n 'field.settings.availableLocales': 'Available locales',\n 'field.settings.theme': 'Theme',\n 'field.settings.showPoweredBy': 'Show the \"Powered by takuhon\" footer',\n 'field.settings.enableJsonLd': 'Emit Schema.org JSON-LD',\n 'field.settings.enableApi': 'Expose the public read API',\n 'field.settings.enableAnalytics': 'Enable first-party analytics',\n\n 'field.settings.publicVisibility': 'Public sections',\n 'field.publicVisibility.links': 'Links',\n 'field.publicVisibility.careers': 'Experience',\n 'field.publicVisibility.projects': 'Projects',\n 'field.publicVisibility.skills': 'Skills',\n 'field.publicVisibility.certifications': 'Certifications',\n 'field.publicVisibility.memberships': 'Memberships',\n 'field.publicVisibility.volunteering': 'Volunteering',\n 'field.publicVisibility.honors': 'Honors & awards',\n 'field.publicVisibility.education': 'Education',\n 'field.publicVisibility.publications': 'Publications',\n 'field.publicVisibility.languages': 'Languages',\n 'field.publicVisibility.courses': 'Courses',\n 'field.publicVisibility.patents': 'Patents',\n 'field.publicVisibility.testScores': 'Test scores',\n 'field.publicVisibility.recommendations': 'Recommendations',\n 'field.publicVisibility.contact': 'Contact',\n\n 'item.link': 'Link',\n 'item.career': 'Position',\n 'item.project': 'Project',\n 'item.skill': 'Skill',\n\n 'empty.links': 'No links yet.',\n 'empty.careers': 'No positions yet.',\n 'empty.projects': 'No projects yet.',\n 'empty.skills': 'No skills yet.',\n\n 'hint.avatarNoUpload': 'Paste an image URL. Uploading image files is not available yet.',\n 'hint.avatarUpload': 'Paste an image URL, or upload a JPEG, PNG, WebP, or GIF.',\n 'hint.gravatar':\n 'Enter an email to generate a Gravatar avatar URL. The email is not saved — only the resulting URL is stored.',\n 'hint.month': 'Format: YYYY-MM (e.g. 2024-03).',\n 'hint.country': 'ISO 3166-1 alpha-2 code, e.g. US.',\n 'hint.tags': 'Comma-separated.',\n 'hint.locales': 'Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.',\n 'hint.publicVisibility':\n 'Unchecked sections are hidden from every public surface (page, API, JSON-LD). All sections are public by default.',\n 'advanced.hint': 'Edit the entire document as JSON. Edits apply only while the JSON is valid.',\n 'advanced.invalid': 'The JSON is not a valid takuhon document:',\n\n 'option.none': '(none)',\n} as const;\n\n/** Every label key understood by {@link getAdminLabel}. */\nexport type AdminLabelKey = keyof typeof EN;\n\nconst DICTIONARIES: Partial<Record<LocaleTag, Partial<Record<AdminLabelKey, string>>>> = {\n en: EN,\n};\n\n/**\n * Resolve an admin label for a locale, falling back to the base language\n * subtag and then English. English is always present, so the return is always\n * a string.\n */\nexport function getAdminLabel(key: AdminLabelKey, locale: LocaleTag = 'en'): string {\n const exact = DICTIONARIES[locale]?.[key];\n if (exact !== undefined) return exact;\n const base = locale.split('-')[0];\n const baseMatch = base ? DICTIONARIES[base]?.[key] : undefined;\n return baseMatch ?? EN[key];\n}\n","import { gravatarUrl } from '@takuhon/core';\nimport { useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './GravatarField.module.css';\nimport controls from './controls.module.css';\n\nexport interface GravatarFieldProps {\n /** Called with the generated Gravatar URL when the owner applies an email. */\n onApply: (url: string) => void;\n}\n\n/**\n * \"Use Gravatar\" control: an email input plus a button that turns the email into\n * a Gravatar avatar URL via core's pure {@link gravatarUrl}. This is the third\n * way to set an avatar, alongside pasting a URL and uploading an image.\n *\n * The email is local-only — it is never written to the document or sent\n * anywhere. Only the generated URL is handed to {@link GravatarFieldProps.onApply}\n * (which the parent writes into `avatar.url`); the email input is cleared once\n * applied, so nothing about the address lingers in the form.\n */\nexport function GravatarField({ onApply }: GravatarFieldProps): React.JSX.Element {\n const [email, setEmail] = useState('');\n const trimmed = email.trim();\n\n const apply = (): void => {\n if (trimmed === '') return;\n onApply(gravatarUrl(trimmed));\n setEmail('');\n };\n\n return (\n <Field label={getAdminLabel('field.gravatarEmail')} hint={getAdminLabel('hint.gravatar')}>\n {({ controlId, describedBy }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"email\"\n value={email}\n autoComplete=\"off\"\n aria-describedby={describedBy}\n onChange={(event) => {\n setEmail(event.target.value);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply();\n }\n }}\n />\n <div className={styles.actionRow}>\n <button\n type=\"button\"\n className={styles.applyButton}\n disabled={trimmed === ''}\n onClick={apply}\n >\n {getAdminLabel('field.gravatarApply')}\n </button>\n </div>\n </>\n )}\n </Field>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\nimport { useId, useRef, useState } from 'react';\n\nimport { errorsAt, hasErrorsUnder, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\n\nimport styles from './LocaleTabs.module.css';\n\nexport interface LocaleTabsProps {\n /** Group label, e.g. `\"Display name\"`. */\n label: string;\n /** Current localized value (BCP-47 tag → string), or undefined when empty. */\n value: Record<LocaleTag, string> | undefined;\n /** Locales offered as tabs (typically `settings.availableLocales`). */\n locales: readonly LocaleTag[];\n /**\n * Receives the next localized record. Empty strings are pruned, and a record\n * that becomes empty is reported as `undefined` so the field is omitted\n * rather than emitted as `{}` (which fails the schema's `minProperties`).\n */\n onChange: (next: Record<LocaleTag, string> | undefined) => void;\n /** Render a `<textarea>` instead of an `<input>` for body-length text. */\n multiline?: boolean;\n required?: boolean;\n hint?: string;\n /** Full error index; per-locale errors are looked up at `${pointer}/${locale}`. */\n errors?: FieldErrorIndex;\n /** Base RFC 6901 pointer to this localized field, e.g. `/profile/displayName`. */\n pointer?: string;\n /** Render a friendlier tab label than the raw locale tag. */\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/**\n * Edits a localized string map (`LocalizedTitle` / `LocalizedBody`) behind one\n * tab per locale (spec §14.2 \"多言語タブ\"). Implements the WAI-ARIA Tabs\n * pattern — roving tabindex, arrow/Home/End navigation, a single shared\n * `tabpanel` — so it stays keyboard-operable and screen-reader-correct\n * (WCAG 2.1 AA, spec §8.5).\n */\nexport function LocaleTabs({\n label,\n value,\n locales,\n onChange,\n multiline = false,\n required,\n hint,\n errors = NO_FIELD_ERRORS,\n pointer,\n formatLocale,\n}: LocaleTabsProps): React.JSX.Element {\n const baseId = useId();\n const hintId = useId();\n const errorId = useId();\n const [active, setActive] = useState<LocaleTag>(() => locales[0] ?? '');\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const labelId = `${baseId}-label`;\n\n if (locales.length === 0) {\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n </span>\n <p className={styles.hint}>No locales are configured yet; add one under Settings.</p>\n </div>\n );\n }\n\n // Reconcile the active tab against the current locale list so editing\n // `availableLocales` elsewhere never strands the selection on a stale tag.\n const activeLocale = locales.includes(active) ? active : locales[0]!;\n const text = value?.[activeLocale] ?? '';\n // Errors on the field itself (`required`, `minProperties`,\n // `propertyNames`) land on the base pointer, not on a locale key, so surface\n // both — otherwise a missing-value failure would be invisible.\n const baseErrors = pointer ? errorsAt(errors, pointer) : [];\n const localeErrors = pointer ? errorsAt(errors, `${pointer}/${activeLocale}`) : [];\n const shownErrors = [...baseErrors, ...localeErrors];\n const hasErrors = shownErrors.length > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n const setText = (next: string): void => {\n const record: Record<string, string> = { ...(value ?? {}) };\n if (next === '') delete record[activeLocale];\n else record[activeLocale] = next;\n onChange(Object.keys(record).length === 0 ? undefined : record);\n };\n\n const onTabKeyDown = (event: React.KeyboardEvent): void => {\n const current = locales.indexOf(activeLocale);\n let nextIndex: number;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = (current + 1) % locales.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = (current - 1 + locales.length) % locales.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = locales.length - 1;\n break;\n default:\n return;\n }\n event.preventDefault();\n const nextLocale = locales[nextIndex];\n if (nextLocale !== undefined) {\n setActive(nextLocale);\n tabRefs.current[nextLocale]?.focus();\n }\n };\n\n const controlName = `${label} (${format(activeLocale)})`;\n\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </span>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n <div className={styles.tablist} role=\"tablist\" aria-label={label}>\n {locales.map((locale) => {\n const selected = locale === activeLocale;\n const tabHasErrors = pointer ? hasErrorsUnder(errors, `${pointer}/${locale}`) : false;\n return (\n <button\n key={locale}\n ref={(element) => {\n tabRefs.current[locale] = element;\n }}\n type=\"button\"\n role=\"tab\"\n id={`${baseId}-tab-${locale}`}\n aria-selected={selected}\n aria-controls={`${baseId}-panel`}\n tabIndex={selected ? 0 : -1}\n className={`${styles.tab} ${selected ? styles.tabActive : ''}`}\n onClick={() => {\n setActive(locale);\n }}\n onKeyDown={onTabKeyDown}\n >\n {format(locale)}\n {tabHasErrors ? (\n <>\n <span className={styles.tabError} aria-hidden=\"true\">\n {' '}\n ●\n </span>\n <span className={styles.srOnly}> (has errors)</span>\n </>\n ) : null}\n </button>\n );\n })}\n </div>\n <div\n role=\"tabpanel\"\n id={`${baseId}-panel`}\n aria-labelledby={`${baseId}-tab-${activeLocale}`}\n className={styles.panel}\n >\n {multiline ? (\n <textarea\n className={`${styles.control} ${styles.textarea}`}\n value={text}\n rows={4}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n ) : (\n <input\n className={styles.control}\n type=\"text\"\n value={text}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n )}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {shownErrors.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n </div>\n );\n}\n","import styles from './Repeater.module.css';\n\nexport interface RepeaterProps<T> {\n /** Group caption rendered as the fieldset legend, e.g. `\"Links\"`. */\n legend: string;\n items: readonly T[];\n /** Receives the next array after an add / remove / reorder / item edit. */\n onChange: (next: T[]) => void;\n /** Render one item's fields; `update` replaces that item in place. */\n renderItem: (item: T, update: (next: T) => void, index: number) => React.ReactNode;\n /** Factory for the entry appended by the Add button. */\n createItem: () => T;\n /** Stable React key per item. Defaults to the index. */\n keyOf?: (item: T, index: number) => string;\n /** Human label for an item, used in the item caption and button names. */\n itemLabel: (item: T, index: number) => string;\n addLabel?: string;\n removeLabel?: string;\n moveUpLabel?: string;\n moveDownLabel?: string;\n /** Shown when there are no items yet. */\n emptyHint?: string;\n}\n\n/**\n * Add / remove / reorder editor for a repeating array field (spec §14.2\n * \"リピーター\"). Reordering uses keyboard-operable Move up / Move down buttons\n * rather than drag-and-drop so the control meets WCAG 2.1 AA (spec §8.5)\n * without a pointer.\n */\nexport function Repeater<T>({\n legend,\n items,\n onChange,\n renderItem,\n createItem,\n keyOf,\n itemLabel,\n addLabel = 'Add',\n removeLabel = 'Remove',\n moveUpLabel = 'Move up',\n moveDownLabel = 'Move down',\n emptyHint,\n}: RepeaterProps<T>): React.JSX.Element {\n const key = keyOf ?? ((_item: T, index: number) => String(index));\n\n const update = (index: number, next: T): void => {\n const copy = items.slice();\n copy[index] = next;\n onChange(copy);\n };\n\n const remove = (index: number): void => {\n onChange(items.filter((_item, i) => i !== index));\n };\n\n const move = (from: number, to: number): void => {\n if (to < 0 || to >= items.length) return;\n const copy = items.slice();\n const [moved] = copy.splice(from, 1);\n if (moved === undefined) return;\n copy.splice(to, 0, moved);\n onChange(copy);\n };\n\n return (\n <fieldset className={styles.fieldset}>\n <legend className={styles.legend}>{legend}</legend>\n {items.length === 0 && emptyHint ? <p className={styles.empty}>{emptyHint}</p> : null}\n <ol className={styles.list}>\n {items.map((item, index) => {\n const caption = itemLabel(item, index);\n return (\n <li key={key(item, index)} className={styles.item}>\n <div role=\"group\" aria-label={caption}>\n <div className={styles.itemHeader}>\n <span className={styles.itemCaption}>{caption}</span>\n <div className={styles.itemActions}>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveUpLabel}: ${caption}`}\n disabled={index === 0}\n onClick={() => {\n move(index, index - 1);\n }}\n >\n ↑\n </button>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveDownLabel}: ${caption}`}\n disabled={index === items.length - 1}\n onClick={() => {\n move(index, index + 1);\n }}\n >\n ↓\n </button>\n <button\n type=\"button\"\n className={styles.removeButton}\n aria-label={`${removeLabel}: ${caption}`}\n onClick={() => {\n remove(index);\n }}\n >\n {removeLabel}\n </button>\n </div>\n </div>\n <div className={styles.itemBody}>\n {renderItem(\n item,\n (next) => {\n update(index, next);\n },\n index,\n )}\n </div>\n </div>\n </li>\n );\n })}\n </ol>\n <button\n type=\"button\"\n className={styles.addButton}\n onClick={() => {\n onChange([...items, createItem()]);\n }}\n >\n {addLabel}\n </button>\n </fieldset>\n );\n}\n","/**\n * Build a unique slug like `link-1` that is not already in `taken`. The prefix\n * is lowercased and stripped to `[a-z0-9-]` (falling back to `item`) so the\n * result always matches the `Slug` pattern `^[a-z0-9][a-z0-9-]*$`.\n * Deterministic given the existing ids, so it needs no random source.\n */\nexport function makeId(prefix: string, taken: Iterable<string>): string {\n const safe = prefix.toLowerCase().replace(/[^a-z0-9-]/g, '') || 'item';\n const used = new Set(taken);\n let n = 1;\n while (used.has(`${safe}-${String(n)}`)) n += 1;\n return `${safe}-${String(n)}`;\n}\n","import type { LocaleTag } from '@takuhon/core';\n\n/**\n * First non-empty localized value, preferring the order of `locales` and\n * falling back to any present value. Used for repeater item captions where a\n * single human-readable string is needed regardless of the active locale.\n */\nexport function firstLocalized(\n record: Record<LocaleTag, string> | undefined,\n locales: readonly LocaleTag[],\n): string {\n if (!record) return '';\n for (const locale of locales) {\n const value = record[locale];\n if (value) return value;\n }\n return Object.values(record).find((value) => value !== '') ?? '';\n}\n","/**\n * Schema-driven field classification for the admin editor.\n *\n * Maps a node of the canonical takuhon JSON Schema (2020-12) to a\n * {@link FieldKind} — the widget the admin form should render for it. This is\n * the pure-logic foundation of the schema-driven form engine (design:\n * `admin-form-schema-driven-design.md`). It resolves local `$ref`s against\n * `$defs` and unwraps nullable `anyOf` unions, so the renderer never hand-wires\n * fields per section. No React here; the classifier is fully unit-testable.\n *\n * Presentation concerns the schema cannot express (widget overrides, ordering,\n * help text, cross-section reference selectors, image/Gravatar widgets) live in\n * a separate field-spec registry, not in the data schema (design decision A1).\n */\n\n/**\n * Minimal structural view of a JSON Schema 2020-12 node — only the keywords the\n * classifier reads. The canonical schema (`@takuhon/core`'s `schema`) is cast to\n * this for traversal.\n */\nexport interface SchemaNode {\n $ref?: string;\n $defs?: Record<string, SchemaNode>;\n type?: string | readonly string[];\n format?: string;\n enum?: readonly unknown[];\n properties?: Record<string, SchemaNode>;\n required?: readonly string[];\n items?: SchemaNode;\n anyOf?: readonly SchemaNode[];\n maxLength?: number;\n minimum?: number;\n description?: string;\n default?: unknown;\n}\n\n/** The widget the admin form should render for a classified schema node. */\nexport type FieldKind =\n | { widget: 'text'; maxLength?: number }\n | { widget: 'url' }\n | { widget: 'email' }\n | { widget: 'month' }\n | { widget: 'date' }\n | { widget: 'datetime' }\n | { widget: 'integer'; minimum?: number }\n | { widget: 'checkbox'; default?: boolean }\n | { widget: 'select'; options: readonly string[] }\n | { widget: 'localeTag' }\n | { widget: 'localizedTitle' }\n | { widget: 'localizedBody' }\n | { widget: 'slug' }\n | { widget: 'array'; item: FieldKind }\n | { widget: 'object'; fields: readonly FieldEntry[] }\n | { widget: 'unsupported' };\n\n/** A named property of an object schema: its optionality and classified kind. */\nexport interface FieldEntry {\n name: string;\n /** Listed in the object's `required` array. */\n required: boolean;\n /** The schema permits an explicit `null` (e.g. `anyOf: [X, { type: 'null' }]`). */\n nullable: boolean;\n kind: FieldKind;\n}\n\n/** Result of following one `$ref` and unwrapping a nullable `anyOf` union. */\nexport interface Resolved {\n node: SchemaNode;\n /** `$defs` name the node resolved from, after following one local `$ref`. */\n ref?: string;\n nullable: boolean;\n}\n\nconst REF_PREFIX = '#/$defs/';\n\n/** Name of the `$defs` entry a node's `$ref` targets, or `undefined`. */\nexport function refName(node: SchemaNode): string | undefined {\n const ref = node.$ref;\n if (typeof ref !== 'string' || !ref.startsWith(REF_PREFIX)) return undefined;\n return ref.slice(REF_PREFIX.length);\n}\n\n/**\n * Follow a single local `$ref` and unwrap a nullable union\n * (`anyOf: [X, { type: 'null' }]` → `X` with `nullable: true`). Idempotent for\n * already-concrete nodes; a missing `$ref` target leaves the node unchanged.\n */\nexport function deref(root: SchemaNode, node: SchemaNode): Resolved {\n let current = node;\n let nullable = false;\n\n const variants = current.anyOf;\n if (variants) {\n const nonNull = variants.filter((variant) => variant.type !== 'null');\n const [only] = nonNull;\n if (only && nonNull.length === 1 && nonNull.length < variants.length) {\n nullable = true;\n current = only;\n }\n }\n\n const name = refName(current);\n if (name === undefined) return { node: current, nullable };\n const target = root.$defs?.[name];\n if (!target) return { node: current, nullable };\n return { node: target, ref: name, nullable };\n}\n\n// Well-known scalar `$defs` whose intended widget is not inferable from `type`\n// alone (pattern-only strings) or carries domain meaning worth a dedicated UI.\nconst REF_WIDGET: Readonly<Record<string, FieldKind>> = {\n LocalizedTitle: { widget: 'localizedTitle' },\n LocalizedBody: { widget: 'localizedBody' },\n YearMonth: { widget: 'month' },\n Slug: { widget: 'slug' },\n LocaleTag: { widget: 'localeTag' },\n};\n\n/** Classify a (possibly `$ref`/nullable) schema node into the widget to render. */\nexport function classifyNode(root: SchemaNode, node: SchemaNode): FieldKind {\n const { node: resolved, ref } = deref(root, node);\n\n if (ref !== undefined) {\n const known = REF_WIDGET[ref];\n if (known) return known;\n }\n\n if (Array.isArray(resolved.enum)) {\n return { widget: 'select', options: resolved.enum.map((value) => String(value)) };\n }\n\n const type = typeof resolved.type === 'string' ? resolved.type : undefined;\n\n if (type === 'string') {\n switch (resolved.format) {\n case 'email':\n return { widget: 'email' };\n case 'uri':\n return { widget: 'url' };\n case 'date':\n return { widget: 'date' };\n case 'date-time':\n return { widget: 'datetime' };\n default:\n return resolved.maxLength === undefined\n ? { widget: 'text' }\n : { widget: 'text', maxLength: resolved.maxLength };\n }\n }\n if (type === 'boolean') {\n // Carry the schema `default` so the checkbox can reflect it: a field with a\n // default (e.g. settings flags default true) shows that state when absent\n // and stores its value explicitly, while a default-less boolean stays\n // sparse (unchecked when absent, dropped when false).\n return typeof resolved.default === 'boolean'\n ? { widget: 'checkbox', default: resolved.default }\n : { widget: 'checkbox' };\n }\n if (type === 'integer' || type === 'number') {\n return resolved.minimum === undefined\n ? { widget: 'integer' }\n : { widget: 'integer', minimum: resolved.minimum };\n }\n if (type === 'array') {\n const item: FieldKind = resolved.items\n ? classifyNode(root, resolved.items)\n : { widget: 'unsupported' };\n return { widget: 'array', item };\n }\n if (type === 'object') {\n return { widget: 'object', fields: objectEntries(root, resolved) };\n }\n return { widget: 'unsupported' };\n}\n\n/** Classified properties of an object schema, in declaration order. */\nexport function objectEntries(root: SchemaNode, objectSchema: SchemaNode): FieldEntry[] {\n const properties = objectSchema.properties ?? {};\n const required = new Set(objectSchema.required ?? []);\n return Object.entries(properties).map(([name, propNode]) => ({\n name,\n required: required.has(name),\n nullable: deref(root, propNode).nullable,\n kind: classifyNode(root, propNode),\n }));\n}\n\n/** Classify a top-level section (e.g. `'education'`, `'contact'`) by name. */\nexport function sectionFieldKind(root: SchemaNode, section: string): FieldKind {\n const node = root.properties?.[section];\n if (!node) return { widget: 'unsupported' };\n return classifyNode(root, node);\n}\n","/**\n * Field-spec registry — the UI-hint layer the data schema deliberately does not\n * carry (design decision A1). Keyed by a section-relative dot path *without*\n * array indices (e.g. `education.institution`, `meta.createdAt`), it overrides\n * or augments the schema-derived classification with presentation concerns:\n * labels, help text, hiding auto-managed fields, forcing a widget.\n *\n * Keeping these out of `takuhon.schema.json` leaves the data contract pure\n * (consumers / validators see no UI noise) and means this track changes no\n * `schemaVersion`.\n */\n\nimport type { LocaleTag } from '@takuhon/core';\n\nimport type { FieldErrorIndex } from '../errors.js';\nimport type { UploadAsset } from '../primitives/ImageField.js';\n\nimport type { FieldKind } from './field-classification.js';\n\n/**\n * Everything a custom field renderer needs. The engine builds this as it walks,\n * so a bespoke widget (avatar, comma-separated list, visibility matrix) plugs in\n * without re-deriving its pointer/path or re-threading locales and errors. This\n * is the escape hatch for the handful of fields a generic widget cannot capture\n * (design §8 \"generic default + targeted craft\").\n */\nexport interface CustomFieldContext {\n /** Current value at this path. */\n value: unknown;\n /** Write the next value for this field back into the document. */\n onChange: (next: unknown) => void;\n /** RFC 6901 pointer (with array indices) for error lookup. */\n pointer: string;\n /** Registry path (no array indices). */\n path: string;\n /** Resolved label (registry override or humanized field name). */\n label: string;\n /** Listed in the parent object's `required`. */\n required: boolean;\n locales: readonly LocaleTag[];\n errors: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n /** Avatar upload, threaded from the host; absent means URL-only. */\n uploadAsset?: UploadAsset;\n /**\n * The whole document (root value), so a field can read sibling sections —\n * e.g. a reference selector listing `careers[]` / `education[]` ids. Typed\n * `unknown` to keep the engine schema-generic; renderers narrow it.\n */\n document?: unknown;\n}\n\n/** Presentation overrides for a single field, looked up by its schema path. */\nexport interface FieldHint {\n /** Replace the humanized field name. */\n label?: string;\n /** Help text shown under the control. */\n hint?: string;\n /** Omit from the form (the value is still preserved in the document). */\n hidden?: boolean;\n /** Render this widget instead of the schema-derived one. */\n widget?: FieldKind['widget'];\n /** Force multiline for a localized/text field. */\n multiline?: boolean;\n /**\n * Render a bespoke control for this field instead of the schema-derived\n * widget. Used for the few fields no generic widget captures (avatar,\n * comma-separated lists, the public-visibility matrix).\n */\n render?: (ctx: CustomFieldContext) => React.ReactNode;\n}\n\n/** Schema-path → hint. Paths use dots and never include array indices. */\nexport type FieldRegistry = Readonly<Record<string, FieldHint>>;\n\nexport const EMPTY_REGISTRY: FieldRegistry = {};\n\n/**\n * Acronyms that read poorly when title-cased: a humanized `url` should be `URL`,\n * not `Url`, and `credentialId` should end in `ID`, not `id`. Matched per word\n * (after camelCase splitting), so only a whole segment is uppercased. Extend as\n * the schema grows; the registry can still override any label outright.\n */\nconst ACRONYMS = new Set(['url', 'id', 'doi']);\n\n/**\n * Humanize a property name for a default label: `fieldOfStudy` → `Field of\n * study`, `credentialId` → `Credential ID`, `url` → `URL`. Known acronyms stay\n * uppercased. The registry overrides this where a better label is needed.\n */\nexport function humanize(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .toLowerCase()\n .split(' ');\n return words\n .map((word, index) =>\n ACRONYMS.has(word)\n ? word.toUpperCase()\n : index === 0\n ? word.charAt(0).toUpperCase() + word.slice(1)\n : word,\n )\n .join(' ');\n}\n\n/** The hint at `path`, or an empty hint when none is registered. */\nexport function hintAt(registry: FieldRegistry, path: string): FieldHint {\n return registry[path] ?? {};\n}\n","/**\n * Schema-driven form engine.\n *\n * Renders an editable form for any takuhon section straight from its\n * {@link FieldKind} (see `field-classification.ts`), using the existing admin\n * primitives. The RFC 6901 `pointer` (with array indices, for error lookup) and\n * the registry `path` (without indices, for UI hints) are derived automatically\n * as the engine walks — so no section hand-wires field plumbing or pointer\n * strings. Presentation overrides come from the {@link FieldRegistry}\n * (decision A1); the data schema stays UI-free.\n *\n * Values are treated as `unknown` and narrowed per kind — the document has been\n * (or will be) validated against the schema, so each branch's cast is sound.\n */\n\nimport type { LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { errorsAt, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { type UploadAsset } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { SelectField, type SelectOption } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport { type FieldEntry, type FieldKind } from './field-classification.js';\nimport {\n EMPTY_REGISTRY,\n hintAt,\n humanize,\n type CustomFieldContext,\n type FieldRegistry,\n} from './field-registry.js';\n\nexport interface SchemaFormProps {\n /** Classified shape of the section (from `sectionFieldKind`). */\n kind: FieldKind;\n /** Current value for the section. */\n value: unknown;\n /** Receives the next value on any edit. */\n onChange: (next: unknown) => void;\n /** RFC 6901 pointer to this value, e.g. `/education`. */\n pointer: string;\n /** Registry path (no array indices). Defaults to the pointer sans leading slash. */\n path?: string;\n /** Heading for the section / object. */\n label: string;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n registry?: FieldRegistry;\n formatLocale?: (locale: LocaleTag) => string;\n /** Avatar upload, threaded to the avatar field's custom renderer. */\n uploadAsset?: UploadAsset;\n /** Whole document, so reference fields can list sibling-section ids. */\n document?: unknown;\n}\n\ninterface RenderCtx {\n pointer: string;\n path: string;\n label: string;\n /** Help text shown under the control (registry hint), if any. */\n hint?: string;\n required: boolean;\n multiline: boolean;\n locales: readonly LocaleTag[];\n errors: FieldErrorIndex;\n registry: FieldRegistry;\n formatLocale?: (locale: LocaleTag) => string;\n uploadAsset?: UploadAsset;\n document?: unknown;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\n\nfunction asLocalized(value: unknown): Record<LocaleTag, string> | undefined {\n return value && typeof value === 'object' ? (value as Record<LocaleTag, string>) : undefined;\n}\n\nfunction asString(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\n/** Set (or, with `undefined`, clear) one key, preserving the existing pattern of\n * optional fields holding `undefined` rather than being deleted. */\nfunction withKey(\n obj: Record<string, unknown>,\n name: string,\n next: unknown,\n): Record<string, unknown> {\n return { ...obj, [name]: next };\n}\n\nfunction idOf(item: unknown): string | undefined {\n const id = asRecord(item).id;\n return typeof id === 'string' ? id : undefined;\n}\n\nfunction lastSegment(path: string): string {\n const parts = path.split('.');\n return parts[parts.length - 1] ?? path;\n}\n\n/** A blank value seeded with the kind's required fields (ids auto-generated). */\nfunction blankValue(kind: FieldKind, takenIds: readonly string[], path: string): unknown {\n switch (kind.widget) {\n case 'object': {\n const obj: Record<string, unknown> = {};\n for (const field of kind.fields) {\n if (!field.required) continue;\n obj[field.name] =\n field.kind.widget === 'slug'\n ? makeId(lastSegment(path), takenIds)\n : blankValue(field.kind, [], `${path}.${field.name}`);\n }\n return obj;\n }\n case 'checkbox':\n return false;\n case 'integer':\n return 0;\n case 'localizedTitle':\n case 'localizedBody':\n return {};\n case 'select':\n return kind.options[0] ?? '';\n case 'array':\n return [];\n default:\n return '';\n }\n}\n\n/** A human caption for a repeater item: first localized title, else first text. */\nfunction captionOf(item: unknown, itemKind: FieldKind, locales: readonly LocaleTag[]): string {\n if (itemKind.widget !== 'object') return asString(item);\n const obj = asRecord(item);\n for (const field of itemKind.fields) {\n if (field.kind.widget === 'localizedTitle') {\n const caption = firstLocalized(asLocalized(obj[field.name]), locales);\n if (caption) return caption;\n }\n }\n for (const field of itemKind.fields) {\n if (field.kind.widget === 'text' || field.kind.widget === 'select') {\n const value = asString(obj[field.name]);\n if (value) return value;\n }\n }\n return '';\n}\n\nfunction renderScalar(\n kind: FieldKind,\n value: unknown,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const errors = errorsAt(ctx.errors, ctx.pointer);\n switch (kind.widget) {\n case 'localizedTitle':\n case 'localizedBody':\n return (\n <LocaleTabs\n label={ctx.label}\n value={asLocalized(value)}\n locales={ctx.locales}\n onChange={(next) => {\n onChange(next);\n }}\n multiline={kind.widget === 'localizedBody' || ctx.multiline}\n required={ctx.required}\n pointer={ctx.pointer}\n errors={ctx.errors}\n formatLocale={ctx.formatLocale}\n />\n );\n case 'checkbox': {\n // A boolean with a schema default reflects that default when absent and is\n // stored explicitly (so `false` persists). A default-less boolean stays\n // sparse: unchecked when absent, dropped from the document when false.\n const hasDefault = kind.default !== undefined;\n const checked = value === undefined ? (kind.default ?? false) : value === true;\n return (\n <CheckboxField\n label={ctx.label}\n checked={checked}\n onChange={(next) => {\n onChange(hasDefault ? next : next || undefined);\n }}\n />\n );\n }\n case 'select':\n case 'localeTag': {\n // An optional locale select offers an explicit \"(none)\" so it can be\n // cleared; a required one (e.g. defaultLocale) does not.\n const localeOptions: readonly SelectOption[] = ctx.locales.map((locale) => ({\n value: locale,\n label: ctx.formatLocale ? ctx.formatLocale(locale) : locale,\n }));\n const options: readonly SelectOption[] =\n kind.widget === 'select'\n ? kind.options.map((option) => ({ value: option, label: option }))\n : ctx.required\n ? localeOptions\n : [{ value: '', label: getAdminLabel('option.none') }, ...localeOptions];\n return (\n <SelectField\n label={ctx.label}\n value={asString(value)}\n options={options}\n onChange={(next) => {\n onChange(next || undefined);\n }}\n required={ctx.required}\n errors={errors}\n />\n );\n }\n case 'integer':\n return (\n <TextField\n label={ctx.label}\n type=\"text\"\n inputMode=\"numeric\"\n value={typeof value === 'number' ? String(value) : ''}\n onChange={(next) => {\n onChange(next === '' ? undefined : Number(next));\n }}\n required={ctx.required}\n hint={ctx.hint}\n errors={errors}\n />\n );\n default: {\n // text / url / email / month / date / datetime / slug → a text-like input.\n // TextField supports text|url|email|month; date/datetime/slug fall to text.\n const type =\n kind.widget === 'url'\n ? 'url'\n : kind.widget === 'email'\n ? 'email'\n : kind.widget === 'month'\n ? 'month'\n : 'text';\n // Year-month fields advertise the `YYYY-MM` format by default, the way the\n // bespoke career/project forms did, so every section stays consistent. A\n // registry hint still wins where one is set.\n const hint = ctx.hint ?? (kind.widget === 'month' ? getAdminLabel('hint.month') : undefined);\n return (\n <TextField\n label={ctx.label}\n type={type}\n value={asString(value)}\n onChange={(next) => {\n onChange(next || undefined);\n }}\n required={ctx.required}\n hint={hint}\n errors={errors}\n />\n );\n }\n }\n}\n\nfunction renderEntry(\n entry: FieldEntry,\n obj: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const path = ctx.path ? `${ctx.path}.${entry.name}` : entry.name;\n const hint = hintAt(ctx.registry, path);\n if (hint.hidden) return null;\n const childCtx: RenderCtx = {\n ...ctx,\n pointer: `${ctx.pointer}/${entry.name}`,\n path,\n label: hint.label ?? humanize(entry.name),\n hint: hint.hint,\n required: entry.required,\n multiline: hint.multiline ?? false,\n };\n const update = (next: unknown): void => {\n onChange(withKey(obj, entry.name, next));\n };\n if (hint.render) {\n const customCtx: CustomFieldContext = {\n value: obj[entry.name],\n onChange: update,\n pointer: childCtx.pointer,\n path: childCtx.path,\n label: childCtx.label,\n required: childCtx.required,\n locales: childCtx.locales,\n errors: childCtx.errors,\n formatLocale: childCtx.formatLocale,\n uploadAsset: childCtx.uploadAsset,\n document: childCtx.document,\n };\n return <div key={entry.name}>{hint.render(customCtx)}</div>;\n }\n return (\n <div key={entry.name}>\n {entry.kind.widget === 'object' ? (\n // Nested objects (location, the activity providers, meta.privacy) become\n // their own labelled fieldset, so same-named children (github.username\n // vs wakatime.username) stay distinguishable.\n <fieldset>\n <legend>{childCtx.label}</legend>\n {renderObjectFields(entry.kind, asRecord(obj[entry.name]), update, childCtx)}\n </fieldset>\n ) : entry.kind.widget === 'array' ? (\n renderArray(entry.kind, obj[entry.name], update, childCtx)\n ) : (\n renderScalar(entry.kind, obj[entry.name], update, childCtx)\n )}\n </div>\n );\n}\n\nfunction renderObjectFields(\n kind: Extract<FieldKind, { widget: 'object' }>,\n obj: Record<string, unknown>,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const update = (next: Record<string, unknown>): void => {\n onChange(next);\n };\n return kind.fields.map((entry) => renderEntry(entry, obj, update, ctx));\n}\n\nfunction renderArray(\n kind: Extract<FieldKind, { widget: 'array' }>,\n value: unknown,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const items: readonly unknown[] = Array.isArray(value) ? (value as readonly unknown[]) : [];\n const itemKind = kind.item;\n const takenIds = items.map(idOf).filter((id): id is string => id !== undefined);\n return (\n <Repeater<unknown>\n legend={ctx.label}\n items={items}\n onChange={(next) => {\n onChange(next);\n }}\n keyOf={(item, index) => idOf(item) ?? String(index)}\n itemLabel={(item, index) =>\n captionOf(item, itemKind, ctx.locales) || `${ctx.label} ${String(index + 1)}`\n }\n createItem={() => blankValue(itemKind, takenIds, ctx.path)}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n renderItem={(item, update, index) => {\n const itemCtx: RenderCtx = { ...ctx, pointer: `${ctx.pointer}/${String(index)}` };\n return itemKind.widget === 'object'\n ? renderObjectFields(itemKind, asRecord(item), update, itemCtx)\n : renderScalar(itemKind, item, update, itemCtx);\n }}\n />\n );\n}\n\n/**\n * Render a section's form from its schema-derived {@link FieldKind}. Array\n * sections become a {@link Repeater}; object sections a labelled fieldset;\n * scalars map to the matching primitive.\n */\nexport function SchemaForm(props: SchemaFormProps): React.JSX.Element {\n const ctx: RenderCtx = {\n pointer: props.pointer,\n path: props.path ?? props.pointer.replace(/^\\//, '').replace(/\\//g, '.'),\n label: props.label,\n required: true,\n multiline: false,\n locales: props.locales,\n errors: props.errors ?? NO_FIELD_ERRORS,\n registry: props.registry ?? EMPTY_REGISTRY,\n formatLocale: props.formatLocale,\n uploadAsset: props.uploadAsset,\n document: props.document,\n };\n\n if (props.kind.widget === 'array') {\n return <>{renderArray(props.kind, props.value, props.onChange, ctx)}</>;\n }\n if (props.kind.widget === 'object') {\n return (\n <fieldset>\n <legend>{props.label}</legend>\n {renderObjectFields(props.kind, asRecord(props.value), props.onChange, ctx)}\n </fieldset>\n );\n }\n return <>{renderScalar(props.kind, props.value, props.onChange, ctx)}</>;\n}\n","/**\n * The admin editor's single source of truth for which sections to render and how.\n *\n * {@link ADMIN_SECTIONS} lists every top-level section in display order; the\n * {@link SchemaForm} engine renders each one from the schema. {@link SECTION_REGISTRY}\n * is the UI-hint layer (decision A1): bespoke renderers for the few fields a\n * generic widget cannot capture (avatar, comma-separated lists, the visibility\n * matrix), plus curated labels and help text. The data schema stays UI-free.\n */\n\nimport { type Takuhon } from '@takuhon/core';\n\nimport { getAdminLabel, type AdminLabelKey } from '../admin-labels.js';\n\nimport {\n csvListRenderer,\n referenceSelect,\n renderAvatar,\n renderVisibilityMatrix,\n} from './custom-fields.js';\nimport { type FieldRegistry } from './field-registry.js';\n\nexport interface AdminSection {\n key: keyof Takuhon;\n label: AdminLabelKey;\n}\n\n/**\n * All editable sections, in display order. The first six were once bespoke\n * forms; they now share the schema-driven engine with the rest, so every section\n * is a form (spec §14.2 Phase 5, no more raw-JSON-only sections).\n */\nexport const ADMIN_SECTIONS: readonly AdminSection[] = [\n { key: 'profile', label: 'section.profile' },\n { key: 'links', label: 'section.links' },\n { key: 'careers', label: 'section.careers' },\n { key: 'projects', label: 'section.projects' },\n { key: 'skills', label: 'section.skills' },\n { key: 'settings', label: 'section.settings' },\n { key: 'education', label: 'section.education' },\n { key: 'certifications', label: 'section.certifications' },\n { key: 'publications', label: 'section.publications' },\n { key: 'honors', label: 'section.honors' },\n { key: 'volunteering', label: 'section.volunteering' },\n { key: 'memberships', label: 'section.memberships' },\n { key: 'languages', label: 'section.languages' },\n { key: 'courses', label: 'section.courses' },\n { key: 'patents', label: 'section.patents' },\n { key: 'testScores', label: 'section.testScores' },\n { key: 'recommendations', label: 'section.recommendations' },\n { key: 'contact', label: 'section.contact' },\n { key: 'meta', label: 'section.meta' },\n] as const satisfies readonly AdminSection[];\n\n/**\n * UI hints keyed by section-relative dot path (no array indices). Covers the\n * bespoke widgets (avatar, comma-separated lists, visibility matrix, and\n * cross-section reference selectors), curated labels for fields whose humanized\n * name reads poorly, help text, and the auto-managed meta fields that stay\n * hidden.\n */\nexport const SECTION_REGISTRY: FieldRegistry = {\n // Profile — avatar is the URL/upload/Gravatar trio.\n 'profile.avatar': { render: renderAvatar },\n 'profile.location.country': { hint: getAdminLabel('hint.country') },\n 'profile.location.display': { label: getAdminLabel('field.location.display') },\n\n // Links.\n 'links.url': { label: getAdminLabel('field.link.url') },\n 'links.iconUrl': { label: getAdminLabel('field.link.iconUrl') },\n\n // Careers.\n 'careers.startDate': {\n label: getAdminLabel('field.career.startDate'),\n hint: getAdminLabel('hint.month'),\n },\n 'careers.endDate': {\n label: getAdminLabel('field.career.endDate'),\n hint: getAdminLabel('hint.month'),\n },\n 'careers.isCurrent': { label: getAdminLabel('field.career.isCurrent') },\n 'careers.url': { label: getAdminLabel('field.career.url') },\n\n // Projects — tags are a comma-separated list; relatedCareerId is a reference.\n 'projects.tags': { render: csvListRenderer({ hint: 'hint.tags', emptyToUndefined: true }) },\n 'projects.relatedCareerId': {\n render: referenceSelect({ section: 'careers', captionField: 'organization' }),\n },\n 'projects.url': { label: getAdminLabel('field.project.url') },\n 'projects.startDate': { hint: getAdminLabel('hint.month') },\n 'projects.endDate': { hint: getAdminLabel('hint.month') },\n\n // Settings — locales are comma-separated, visibility is the inverted matrix.\n 'settings.availableLocales': {\n render: csvListRenderer({ hint: 'hint.locales', emptyToUndefined: false }),\n },\n 'settings.theme': { label: getAdminLabel('field.settings.theme') },\n 'settings.showPoweredBy': { label: getAdminLabel('field.settings.showPoweredBy') },\n 'settings.enableJsonLd': { label: getAdminLabel('field.settings.enableJsonLd') },\n 'settings.enableApi': { label: getAdminLabel('field.settings.enableApi') },\n 'settings.enableAnalytics': { label: getAdminLabel('field.settings.enableAnalytics') },\n 'settings.activity.github': { label: 'GitHub' },\n 'settings.activity.wakatime': { label: 'WakaTime' },\n 'settings.publicVisibility': { render: renderVisibilityMatrix },\n\n // Cross-section reference selectors (decision C): dropdowns of sibling-section\n // ids. courses / testScores / recommendations point at education / careers.\n 'courses.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n 'testScores.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n 'recommendations.relatedCareerId': {\n render: referenceSelect({ section: 'careers', captionField: 'organization' }),\n },\n 'recommendations.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n\n // Languages — disambiguate from the profile's \"Display name\".\n 'languages.displayName': { label: 'Language name' },\n\n // Metadata — auto-managed, never hand-edited.\n 'meta.createdAt': { hidden: true },\n 'meta.updatedAt': { hidden: true },\n 'meta.generator': { hidden: true },\n};\n","/**\n * Bespoke field renderers for the schema-driven form — the handful of fields a\n * generic schema-derived widget cannot capture (design §8). Each is plugged in\n * through the {@link FieldRegistry}'s `render` hook (decision A1), keyed by\n * schema path, so the engine stays generic and the data schema stays UI-free.\n *\n * These reproduce, one-for-one, the behavior the former hand-written section\n * forms had: the avatar's URL/upload/Gravatar trio, comma-separated lists, and\n * the inverted-and-sparse public-visibility matrix.\n */\n\nimport type { LocaleTag, PublicVisibility } from '@takuhon/core';\n\nimport { getAdminLabel, type AdminLabelKey } from '../admin-labels.js';\nimport { collectErrorsUnder, errorsAt } from '../errors.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { GravatarField } from '../primitives/GravatarField.js';\nimport { ImageField } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { SelectField, type SelectOption } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './custom-fields.module.css';\nimport type { CustomFieldContext } from './field-registry.js';\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\n\nfunction asLocalized(value: unknown): Record<LocaleTag, string> | undefined {\n return value && typeof value === 'object' ? (value as Record<LocaleTag, string>) : undefined;\n}\n\nfunction isEmptyRecord(record: Record<LocaleTag, string> | undefined): boolean {\n return !record || Object.keys(record).length === 0;\n}\n\nfunction asString(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction idOf(item: unknown): string {\n const id = asRecord(item).id;\n return typeof id === 'string' ? id : '';\n}\n\n/**\n * Avatar: a URL input (with optional file upload), a \"Use Gravatar\" control, and\n * localized alt text. The avatar object is created only once a URL or alt text\n * exists and dropped back to `undefined` when both are empty — matching the\n * former ProfileForm exactly.\n */\nexport function renderAvatar(ctx: CustomFieldContext): React.ReactNode {\n const avatar = asRecord(ctx.value);\n const url = typeof avatar.url === 'string' ? avatar.url : '';\n\n const updateAvatar = (patch: { url?: string; alt?: Record<LocaleTag, string> }): void => {\n const merged: Record<string, unknown> = { url: '', ...avatar, ...patch };\n const keep = merged.url !== '' || !isEmptyRecord(asLocalized(merged.alt));\n ctx.onChange(keep ? merged : undefined);\n };\n\n return (\n <>\n <ImageField\n label={getAdminLabel('field.avatarUrl')}\n value={url}\n onChange={(next) => {\n updateAvatar({ url: next });\n }}\n hint={getAdminLabel(ctx.uploadAsset ? 'hint.avatarUpload' : 'hint.avatarNoUpload')}\n errors={errorsAt(ctx.errors, `${ctx.pointer}/url`)}\n uploadAsset={ctx.uploadAsset}\n />\n <GravatarField\n onApply={(next) => {\n updateAvatar({ url: next });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.avatarAlt')}\n value={asLocalized(avatar.alt)}\n locales={ctx.locales}\n onChange={(next) => {\n updateAvatar({ alt: next });\n }}\n pointer={`${ctx.pointer}/alt`}\n errors={ctx.errors}\n formatLocale={ctx.formatLocale}\n />\n </>\n );\n}\n\n/** Split a comma-separated input into trimmed, non-empty entries. */\nfunction parseCsv(input: string): string[] {\n return input\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '');\n}\n\n/**\n * A comma-separated list editor for short string arrays (tags, locales) — a\n * single text input rather than a repeater, matching the former forms. `hint`\n * names the help text; `emptyToUndefined` drops the key when the list is empty\n * (optional arrays) versus keeping `[]` (required arrays).\n */\nexport function csvListRenderer(options: {\n hint: AdminLabelKey;\n emptyToUndefined: boolean;\n}): (ctx: CustomFieldContext) => React.ReactNode {\n return function renderCsvList(ctx: CustomFieldContext): React.ReactNode {\n const items = Array.isArray(ctx.value) ? (ctx.value as readonly unknown[]) : [];\n const text = items.filter((item): item is string => typeof item === 'string').join(', ');\n return (\n <TextField\n label={ctx.label}\n value={text}\n onChange={(input) => {\n const next = parseCsv(input);\n ctx.onChange(options.emptyToUndefined && next.length === 0 ? undefined : next);\n }}\n required={ctx.required}\n hint={getAdminLabel(options.hint)}\n errors={collectErrorsUnder(ctx.errors, ctx.pointer)}\n />\n );\n };\n}\n\n/**\n * Content sections the owner can hide via `settings.publicVisibility`. The order\n * mirrors the public page; `profile` is intentionally absent because the\n * identity is always public (spec §6.2).\n */\nconst VISIBILITY_SECTIONS: { key: keyof PublicVisibility; label: AdminLabelKey }[] = [\n { key: 'links', label: 'field.publicVisibility.links' },\n { key: 'careers', label: 'field.publicVisibility.careers' },\n { key: 'projects', label: 'field.publicVisibility.projects' },\n { key: 'skills', label: 'field.publicVisibility.skills' },\n { key: 'certifications', label: 'field.publicVisibility.certifications' },\n { key: 'memberships', label: 'field.publicVisibility.memberships' },\n { key: 'volunteering', label: 'field.publicVisibility.volunteering' },\n { key: 'honors', label: 'field.publicVisibility.honors' },\n { key: 'education', label: 'field.publicVisibility.education' },\n { key: 'publications', label: 'field.publicVisibility.publications' },\n { key: 'languages', label: 'field.publicVisibility.languages' },\n { key: 'courses', label: 'field.publicVisibility.courses' },\n { key: 'patents', label: 'field.publicVisibility.patents' },\n { key: 'testScores', label: 'field.publicVisibility.testScores' },\n { key: 'recommendations', label: 'field.publicVisibility.recommendations' },\n { key: 'contact', label: 'field.publicVisibility.contact' },\n];\n\n/**\n * The public-visibility matrix: a checkbox per content section, checked = public.\n * Stored sparsely — only hidden sections (`false`) are kept, and the whole block\n * is dropped once every section is visible again, so the default (all-visible)\n * stays absent. This inversion is why a generic boolean checkbox cannot stand in.\n */\nexport function renderVisibilityMatrix(ctx: CustomFieldContext): React.ReactNode {\n const visibility = asRecord(ctx.value) as Partial<Record<keyof PublicVisibility, boolean>>;\n\n const setVisibility = (key: keyof PublicVisibility, visible: boolean): void => {\n const next: Partial<Record<keyof PublicVisibility, boolean>> = { ...visibility };\n if (visible) {\n delete next[key];\n } else {\n next[key] = false;\n }\n ctx.onChange(Object.keys(next).length > 0 ? next : undefined);\n };\n\n return (\n <>\n <h3 className={styles.subheading}>{getAdminLabel('field.settings.publicVisibility')}</h3>\n <p className={styles.hint}>{getAdminLabel('hint.publicVisibility')}</p>\n {VISIBILITY_SECTIONS.map(({ key, label }) => (\n <CheckboxField\n key={key}\n label={getAdminLabel(label)}\n checked={visibility[key] ?? true}\n onChange={(visible) => {\n setVisibility(key, visible);\n }}\n />\n ))}\n </>\n );\n}\n\n/**\n * A cross-section reference selector (decision C): a dropdown of a sibling\n * section's items (e.g. `projects.relatedCareerId` → `careers[]`), each option\n * labelled by the item's caption and id. The stored value is the referenced\n * `id`. An optional reference offers \"(none)\"; a value with no matching item\n * (a dangling reference) is preserved as its own option rather than silently\n * dropped, so a stale id stays visible until the owner fixes it.\n */\nexport function referenceSelect(spec: {\n /** Sibling section to draw candidates from, e.g. `'careers'`. */\n section: string;\n /** Localized field used as the option caption, e.g. `'organization'`. */\n captionField: string;\n}): (ctx: CustomFieldContext) => React.ReactNode {\n return function renderReferenceSelect(ctx: CustomFieldContext): React.ReactNode {\n const value = asString(ctx.value);\n const items = (() => {\n const list = asRecord(ctx.document)[spec.section];\n return Array.isArray(list) ? (list as readonly unknown[]) : [];\n })();\n\n const candidates: SelectOption[] = items\n .map((item) => {\n const id = idOf(item);\n const caption = firstLocalized(asLocalized(asRecord(item)[spec.captionField]), ctx.locales);\n return { value: id, label: caption ? `${caption} (${id})` : id };\n })\n .filter((option) => option.value !== '');\n\n const danglingId = value !== '' && !candidates.some((option) => option.value === value);\n const options: SelectOption[] = [\n ...(ctx.required ? [] : [{ value: '', label: getAdminLabel('option.none') }]),\n ...candidates,\n // Keep an unrecognized current value selectable so it is never dropped.\n ...(danglingId ? [{ value, label: value }] : []),\n ];\n\n return (\n <SelectField\n label={ctx.label}\n value={value}\n options={options}\n onChange={(next) => {\n ctx.onChange(next || undefined);\n }}\n required={ctx.required}\n errors={errorsAt(ctx.errors, ctx.pointer)}\n />\n );\n };\n}\n","import { validate, type Takuhon } from '@takuhon/core';\nimport { useId, useState } from 'react';\n\nimport styles from './RawJsonEditor.module.css';\nimport { getAdminLabel } from './admin-labels.js';\n\nexport interface RawJsonEditorProps {\n value: Takuhon;\n /** Called with the parsed document whenever the text is valid JSON + schema. */\n onChange: (next: Takuhon) => void;\n}\n\nconst MAX_SHOWN_PROBLEMS = 50;\n\n/**\n * Advanced editing surface: the entire document as JSON text. Edits commit to\n * the draft only when the text parses and passes schema validation, so the\n * structured form view it shares state with never sees a malformed document.\n * This is also the only way to edit sections without a dedicated form (spec\n * §14.1 Phase 5 — JSON editor retained as the advanced mode).\n */\nexport function RawJsonEditor({ value, onChange }: RawJsonEditorProps): React.JSX.Element {\n const [text, setText] = useState(() => JSON.stringify(value, null, 2));\n const [problems, setProblems] = useState<readonly string[]>([]);\n const labelId = useId();\n const errorId = useId();\n\n const apply = (next: string): void => {\n setText(next);\n let parsed: unknown;\n try {\n parsed = JSON.parse(next);\n } catch (error) {\n setProblems([error instanceof Error ? error.message : 'Invalid JSON.']);\n return;\n }\n const result = validate(parsed);\n if (!result.ok) {\n setProblems(\n result.errors\n .slice(0, MAX_SHOWN_PROBLEMS)\n .map((error) => `${error.pointer || '/'}: ${error.message}`),\n );\n return;\n }\n setProblems([]);\n onChange(result.data);\n };\n\n const hasProblems = problems.length > 0;\n\n return (\n <section className={styles.wrapper} aria-labelledby={labelId}>\n <h2 className={styles.heading} id={labelId}>\n {getAdminLabel('mode.advanced')}\n </h2>\n <p className={styles.hint}>{getAdminLabel('advanced.hint')}</p>\n <textarea\n className={styles.textarea}\n value={text}\n spellCheck={false}\n aria-label={getAdminLabel('mode.advanced')}\n aria-invalid={hasProblems || undefined}\n aria-describedby={hasProblems ? errorId : undefined}\n onChange={(event) => {\n apply(event.target.value);\n }}\n />\n {hasProblems ? (\n <div className={styles.problems} id={errorId} role=\"alert\">\n <p className={styles.problemsTitle}>{getAdminLabel('advanced.invalid')}</p>\n <ul>\n {problems.map((problem, i) => (\n <li key={i}>{problem}</li>\n ))}\n </ul>\n </div>\n ) : null}\n </section>\n );\n}\n","import { schema, validate, type LocaleTag, type Takuhon } from '@takuhon/core';\nimport { useEffect, useRef, useState } from 'react';\n\nimport styles from './AdminEditor.module.css';\nimport { RawJsonEditor } from './RawJsonEditor.js';\nimport { getAdminLabel } from './admin-labels.js';\nimport {\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\nimport { type UploadAsset } from './primitives/ImageField.js';\nimport { SchemaForm } from './schema-form/SchemaForm.js';\nimport { sectionFieldKind, type SchemaNode } from './schema-form/field-classification.js';\nimport { ADMIN_SECTIONS, SECTION_REGISTRY } from './schema-form/section-registry.js';\n\n/** Result of a save attempt, reported by the host's transport layer. */\nexport type AdminSaveOutcome =\n | { status: 'saved'; version?: string }\n | { status: 'conflict' }\n | { status: 'invalid'; errors: readonly FieldErrorLike[] }\n | { status: 'error'; message?: string };\n\nexport interface AdminEditorProps {\n /** Document to edit, typically loaded from `GET /api/admin/export`. */\n initialDocument: Takuhon;\n /** Persist the document. The editor validates client-side first. */\n onSave: (document: Takuhon) => Promise<AdminSaveOutcome>;\n /** Re-fetch the stored document, replacing the working draft. */\n onReload?: () => Promise<Takuhon>;\n /** Download / hand off the current draft (Export button). */\n onExport?: (document: Takuhon) => void;\n /**\n * Provide a document to load (Import button). Returns raw parsed JSON, which\n * the editor validates; `undefined` cancels. Validation lives here so an\n * invalid file cannot break the draft invariant.\n */\n onImport?: () => Promise<unknown>;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file (host-supplied; carries the admin token). When\n * provided, the profile form's avatar field offers a file picker; otherwise\n * the avatar stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\ntype Mode = 'form' | 'advanced';\ntype Tone = 'info' | 'success' | 'error';\ninterface Status {\n tone: Tone;\n message: string;\n}\n\nconst schemaRoot = schema as unknown as SchemaNode;\n\nfunction setSection(doc: Takuhon, key: keyof Takuhon, value: unknown): Takuhon {\n return { ...doc, [key]: value };\n}\n\n/**\n * Top-level admin editor: holds the working draft, switches between the field\n * forms and the raw-JSON advanced mode, and runs client-side validation before\n * delegating persistence to the host via `onSave` (transport-agnostic). Server\n * (RFC 7807) and client (`validate`) errors map to the same fields.\n */\nexport function AdminEditor({\n initialDocument,\n onSave,\n onReload,\n onExport,\n onImport,\n formatLocale,\n uploadAsset,\n}: AdminEditorProps): React.JSX.Element {\n const [draft, setDraft] = useState<Takuhon>(initialDocument);\n const [mode, setMode] = useState<Mode>('form');\n const [errors, setErrors] = useState<FieldErrorIndex>(NO_FIELD_ERRORS);\n const [status, setStatus] = useState<Status | null>(null);\n const [busy, setBusy] = useState(false);\n // Bumped whenever the document is replaced wholesale (reload / import) to\n // remount the raw-JSON editor so its text re-seeds from the new draft.\n const [loadGen, setLoadGen] = useState(0);\n // Identifies the latest user intent. A save reads it after awaiting `onSave`\n // and discards its outcome if an edit (which bumps the counter) landed\n // meanwhile — preventing a stale \"Saved.\" or stale server errors.\n const intentRef = useRef(0);\n // When a save fails validation, move focus to the error summary so keyboard\n // and screen-reader users land on the list of problems (the GOV.UK error\n // summary pattern). Set just before the failing `setErrors`; consumed by the\n // effect once the summary has rendered.\n const summaryRef = useRef<HTMLHeadingElement>(null);\n const focusSummaryRef = useRef(false);\n\n const locales = draft.settings.availableLocales;\n\n useEffect(() => {\n if (focusSummaryRef.current && summaryRef.current) {\n summaryRef.current.focus();\n }\n focusSummaryRef.current = false;\n }, [errors]);\n\n // Any edit clears the previous validation snapshot so resolved errors do not\n // linger while the operator works through them, and invalidates any in-flight\n // save outcome.\n const updateDraft = (next: Takuhon): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(null);\n };\n\n const loadDocument = (next: Takuhon, message: Status | null): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(message);\n setLoadGen((generation) => generation + 1);\n };\n\n const handleSave = async (): Promise<void> => {\n const result = validate(draft);\n if (!result.ok) {\n focusSummaryRef.current = true;\n setErrors(indexValidationErrors(result.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n return;\n }\n setErrors(NO_FIELD_ERRORS);\n intentRef.current += 1;\n const intent = intentRef.current;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.saving') });\n try {\n const outcome = await onSave(result.data);\n if (intent !== intentRef.current) return; // an edit landed mid-save; ignore\n switch (outcome.status) {\n case 'saved':\n setStatus({ tone: 'success', message: getAdminLabel('status.saved') });\n break;\n case 'conflict':\n setStatus({ tone: 'error', message: getAdminLabel('status.conflict') });\n break;\n case 'invalid':\n focusSummaryRef.current = true;\n setErrors(indexErrors(outcome.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n break;\n case 'error':\n setStatus({ tone: 'error', message: outcome.message ?? getAdminLabel('status.error') });\n break;\n }\n } catch {\n if (intent === intentRef.current) {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handleReload = async (): Promise<void> => {\n if (!onReload) return;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.loading') });\n try {\n const next = await onReload();\n loadDocument(next, null);\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n } finally {\n setBusy(false);\n }\n };\n\n const handleImport = async (): Promise<void> => {\n if (!onImport) return;\n try {\n const raw = await onImport();\n if (raw === undefined) return;\n const result = validate(raw);\n if (!result.ok) {\n setStatus({ tone: 'error', message: getAdminLabel('status.importInvalid') });\n return;\n }\n loadDocument(result.data, {\n tone: 'info',\n message: getAdminLabel('status.imported'),\n });\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n };\n\n // Flattened error list for the summary. This is the safety net that surfaces\n // failures in sections without a dedicated form (e.g. meta, education): their\n // pointers would otherwise map to no visible field.\n const errorEntries = [...errors].flatMap(([pointer, messages]) =>\n messages.map((message) => ({ pointer, message })),\n );\n\n return (\n <div className={styles.editor}>\n <div className={styles.toolbar} role=\"toolbar\" aria-label={getAdminLabel('toolbar.label')}>\n <div className={styles.modes} role=\"group\" aria-label={getAdminLabel('mode.label')}>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'form' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'form'}\n onClick={() => {\n setMode('form');\n }}\n >\n {getAdminLabel('mode.form')}\n </button>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'advanced' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'advanced'}\n onClick={() => {\n setMode('advanced');\n }}\n >\n {getAdminLabel('mode.advanced')}\n </button>\n </div>\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.primary}\n disabled={busy}\n onClick={() => {\n void handleSave();\n }}\n >\n {getAdminLabel('action.save')}\n </button>\n {onReload ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleReload();\n }}\n >\n {getAdminLabel('action.reload')}\n </button>\n ) : null}\n {onExport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n onClick={() => {\n onExport(draft);\n }}\n >\n {getAdminLabel('action.export')}\n </button>\n ) : null}\n {onImport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleImport();\n }}\n >\n {getAdminLabel('action.import')}\n </button>\n ) : null}\n </div>\n </div>\n\n <p className={styles.status} role=\"status\" aria-live=\"polite\" data-tone={status?.tone}>\n {status?.message ?? ''}\n </p>\n\n {errorEntries.length > 0 ? (\n <section className={styles.summary} aria-labelledby=\"admin-error-summary\">\n <h2\n className={styles.summaryHeading}\n id=\"admin-error-summary\"\n tabIndex={-1}\n ref={summaryRef}\n >\n {getAdminLabel('status.fixSummary')}\n </h2>\n <ul>\n {errorEntries.map((entry, i) => (\n <li key={i}>\n {entry.pointer === ''\n ? entry.message\n : `${entry.pointer.replace(/^\\//, '')}: ${entry.message}`}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n {mode === 'form' ? (\n <div className={styles.sections}>\n {ADMIN_SECTIONS.map(({ key, label }) => (\n <SchemaForm\n key={key}\n kind={sectionFieldKind(schemaRoot, key)}\n value={draft[key]}\n onChange={(next) => {\n updateDraft(setSection(draft, key, next));\n }}\n pointer={`/${key}`}\n label={getAdminLabel(label)}\n locales={locales}\n errors={errors}\n registry={SECTION_REGISTRY}\n formatLocale={formatLocale}\n uploadAsset={uploadAsset}\n document={draft}\n />\n ))}\n </div>\n ) : (\n <RawJsonEditor key={loadGen} value={draft} onChange={updateDraft} />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["styles","jsx","styles","jsx","styles","jsx","useId","styles","jsx","jsxs","useId","styles","jsx","jsxs","useId","useState","styles","controls","Fragment","jsx","jsxs","useState","useId","useRef","useState","styles","Fragment","jsx","jsxs","useId","useState","useRef","styles","jsx","jsxs","Fragment","jsx","jsxs","styles","Fragment","jsx","jsxs","asRecord","asLocalized","asString","idOf","useId","useState","styles","jsx","jsxs","useState","useId","styles","validate","useRef","useState","styles","jsx","jsxs","useState","useRef","validate","styles"]}
1
+ {"version":3,"sources":["../../src/admin/index.ts","../../src/admin/errors.ts","../../src/admin/primitives/Field.tsx","../../src/admin/primitives/TextField.tsx","../../src/admin/primitives/TextAreaField.tsx","../../src/admin/primitives/SelectField.tsx","../../src/admin/primitives/CheckboxField.tsx","../../src/admin/primitives/ImageField.tsx","../../src/admin/admin-labels.ts","../../src/admin/primitives/GravatarField.tsx","../../src/admin/primitives/LocaleTabs.tsx","../../src/admin/primitives/Repeater.tsx","../../src/admin/ids.ts","../../src/admin/localized.ts","../../src/admin/schema-form/field-classification.ts","../../src/admin/schema-form/field-registry.ts","../../src/admin/schema-form/SchemaForm.tsx","../../src/admin/schema-form/section-registry.tsx","../../src/admin/schema-form/custom-fields.tsx","../../src/admin/RawJsonEditor.tsx","../../src/admin/AdminEditor.tsx"],"sourcesContent":["/**\n * @takuhon/ui/admin — React form components for the takuhon admin editor.\n *\n * These are the building blocks behind the Cloudflare admin form UI (spec\n * §14.1 Phase 5). They are presentational and transport-agnostic: each is a\n * controlled component that takes a value plus `onChange`, with field errors\n * supplied as a {@link FieldErrorIndex} so server (RFC 7807) and client\n * (`@takuhon/core` `validate`) failures map to the same fields. Co-located CSS\n * Modules are emitted to `dist/admin/` and bundled by the consumer.\n *\n * Importing this entry also pulls in the shared design tokens, so the admin\n * components are themed standalone without depending on the profile UI entry.\n */\n\nimport '../styles/tokens.css';\n\nexport {\n canonicalPointer,\n collectErrorsUnder,\n errorsAt,\n hasErrorsUnder,\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\n\nexport { Field, type FieldProps, type FieldControlProps } from './primitives/Field.js';\nexport { TextField, type TextFieldProps } from './primitives/TextField.js';\nexport { TextAreaField, type TextAreaFieldProps } from './primitives/TextAreaField.js';\nexport { SelectField, type SelectFieldProps, type SelectOption } from './primitives/SelectField.js';\nexport { CheckboxField, type CheckboxFieldProps } from './primitives/CheckboxField.js';\nexport {\n ImageField,\n type ImageFieldProps,\n type AssetUploadResult,\n type UploadAsset,\n} from './primitives/ImageField.js';\nexport { GravatarField, type GravatarFieldProps } from './primitives/GravatarField.js';\nexport { LocaleTabs, type LocaleTabsProps } from './primitives/LocaleTabs.js';\nexport { Repeater, type RepeaterProps } from './primitives/Repeater.js';\n\nexport { getAdminLabel, type AdminLabelKey } from './admin-labels.js';\n\n// The schema-driven form engine renders every section straight from the JSON\n// Schema; the former per-section forms (ProfileForm, LinksForm, …) are gone.\nexport { SchemaForm, type SchemaFormProps } from './schema-form/SchemaForm.js';\nexport {\n sectionFieldKind,\n classifyNode,\n type FieldKind,\n type SchemaNode,\n} from './schema-form/field-classification.js';\nexport {\n EMPTY_REGISTRY,\n humanize,\n hintAt,\n type FieldHint,\n type FieldRegistry,\n type CustomFieldContext,\n} from './schema-form/field-registry.js';\nexport {\n ADMIN_SECTIONS,\n SECTION_REGISTRY,\n type AdminSection,\n} from './schema-form/section-registry.js';\n\nexport { RawJsonEditor, type RawJsonEditorProps } from './RawJsonEditor.js';\nexport { AdminEditor, type AdminEditorProps, type AdminSaveOutcome } from './AdminEditor.js';\n","/**\n * Field-error plumbing shared by the admin form components.\n *\n * Validation failures reach the editor in two shapes that mean the same thing:\n *\n * - `@takuhon/core`'s {@link ValidationError}, produced by a client-side\n * `validate()` call, carries an RFC 6901 `pointer` such as\n * `\"/profile/displayName/en\"`.\n * - The server's RFC 7807 response (`api.md §5`) carries the same location as a\n * `path` with a leading `#` fragment marker, e.g. `\"#/profile/displayName/en\"`.\n *\n * Both are normalized to a single canonical pointer so a field can look up its\n * own errors regardless of where they came from.\n */\nimport type { ValidationError } from '@takuhon/core';\n\n/** A field error in either the core (`pointer`) or RFC 7807 wire (`path`) shape. */\nexport interface FieldErrorLike {\n pointer?: string;\n path?: string;\n message: string;\n}\n\n/**\n * Canonical RFC 6901 pointer: no leading `#`, a leading `/` for any non-root\n * location, and `\"\"` for the document root. Idempotent.\n */\nexport function canonicalPointer(raw: string): string {\n let pointer = raw.trim();\n if (pointer.startsWith('#')) pointer = pointer.slice(1);\n if (pointer !== '' && !pointer.startsWith('/')) pointer = `/${pointer}`;\n return pointer;\n}\n\n/** Maps a canonical pointer to the messages reported at that exact location. */\nexport type FieldErrorIndex = ReadonlyMap<string, readonly string[]>;\n\n/** Group a flat error list by canonical pointer, preserving message order. */\nexport function indexErrors(errors: readonly FieldErrorLike[]): FieldErrorIndex {\n const index = new Map<string, string[]>();\n for (const error of errors) {\n const key = canonicalPointer(error.pointer ?? error.path ?? '');\n const existing = index.get(key);\n if (existing) existing.push(error.message);\n else index.set(key, [error.message]);\n }\n return index;\n}\n\n/** Convenience over {@link indexErrors} for a core `validate()` failure list. */\nexport function indexValidationErrors(errors: readonly ValidationError[]): FieldErrorIndex {\n return indexErrors(errors);\n}\n\n/** Messages reported at exactly `pointer` (empty array when none). */\nexport function errorsAt(index: FieldErrorIndex, pointer: string): readonly string[] {\n return index.get(canonicalPointer(pointer)) ?? [];\n}\n\n/**\n * Whether any error sits at or below `prefix` — used to badge a section or a\n * repeater item that contains an invalid field deeper in the tree.\n */\nexport function hasErrorsUnder(index: FieldErrorIndex, prefix: string): boolean {\n const base = canonicalPointer(prefix);\n for (const key of index.keys()) {\n if (key === base || key.startsWith(`${base}/`)) return true;\n }\n return false;\n}\n\n/**\n * All messages at or below `prefix`, in pointer order. Used by aggregate\n * controls (a comma-separated list edited as one field) so item-level failures\n * reported at `${prefix}/${itemIndex}` still surface on the single input.\n */\nexport function collectErrorsUnder(index: FieldErrorIndex, prefix: string): string[] {\n const base = canonicalPointer(prefix);\n const messages: string[] = [];\n for (const [key, list] of index) {\n if (key === base || key.startsWith(`${base}/`)) messages.push(...list);\n }\n return messages;\n}\n\n/** An empty index, handy as a default prop. */\nexport const NO_FIELD_ERRORS: FieldErrorIndex = new Map();\n","import { useId } from 'react';\n\nimport styles from './Field.module.css';\n\n/** Identifiers a {@link Field} hands to the control it wraps. */\nexport interface FieldControlProps {\n /** `id` for the control, paired with the rendered `<label htmlFor>`. */\n controlId: string;\n /** `aria-describedby` value linking the control to its hint/error text. */\n describedBy: string | undefined;\n /** Whether the control should advertise `aria-invalid`. */\n invalid: boolean;\n}\n\nexport interface FieldProps {\n /** Visible label text. */\n label: string;\n /** Validation messages to render beneath the control. */\n errors?: readonly string[];\n /** Optional helper text shown between the label and the control. */\n hint?: string;\n /** Marks the field visually and via `aria-required` on the control. */\n required?: boolean;\n /** Render the control, wired with the supplied accessibility ids. */\n children: (props: FieldControlProps) => React.ReactNode;\n}\n\n/**\n * Layout + accessibility wrapper for a single form control. Owns the `id`\n * wiring so the label, hint, error list, and control stay associated for\n * screen readers (WCAG 2.1 AA, spec §8.5). Presentational only — it holds no\n * value state; the wrapped control is controlled by its parent.\n */\nexport function Field({ label, errors, hint, required, children }: FieldProps): React.JSX.Element {\n const controlId = useId();\n const hintId = useId();\n const errorId = useId();\n const hasErrors = (errors?.length ?? 0) > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n return (\n <div className={styles.field}>\n <label className={styles.label} htmlFor={controlId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </label>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n {children({ controlId, describedBy, invalid: hasErrors })}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {errors!.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n /**\n * HTML input type. Defaults to `'text'`; `'url'` for link/avatar URLs,\n * `'month'` for `YearMonth` values (a native month picker emits `YYYY-MM`).\n */\n type?: 'text' | 'url' | 'email' | 'month';\n inputMode?: React.HTMLAttributes<HTMLInputElement>['inputMode'];\n}\n\n/** A labelled single-line text input wired for accessibility via {@link Field}. */\nexport function TextField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n type = 'text',\n inputMode,\n}: TextFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <input\n id={controlId}\n className={styles.control}\n type={type}\n value={value}\n placeholder={placeholder}\n inputMode={inputMode}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface TextAreaFieldProps {\n label: string;\n value: string;\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n placeholder?: string;\n rows?: number;\n}\n\n/** A labelled multi-line text input wired for accessibility via {@link Field}. */\nexport function TextAreaField({\n label,\n value,\n onChange,\n errors,\n hint,\n required,\n placeholder,\n rows = 4,\n}: TextAreaFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <textarea\n id={controlId}\n className={`${styles.control} ${styles.textarea}`}\n value={value}\n rows={rows}\n placeholder={placeholder}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n )}\n </Field>\n );\n}\n","import { Field } from './Field.js';\nimport styles from './controls.module.css';\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectFieldProps {\n label: string;\n value: string;\n options: readonly SelectOption[];\n onChange: (value: string) => void;\n errors?: readonly string[];\n hint?: string;\n required?: boolean;\n}\n\n/** A labelled `<select>` wired for accessibility via {@link Field}. */\nexport function SelectField({\n label,\n value,\n options,\n onChange,\n errors,\n hint,\n required,\n}: SelectFieldProps): React.JSX.Element {\n return (\n <Field label={label} errors={errors} hint={hint} required={required}>\n {({ controlId, describedBy, invalid }) => (\n <select\n id={controlId}\n className={styles.control}\n value={value}\n aria-invalid={invalid || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n >\n {options.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n )}\n </Field>\n );\n}\n","import { useId } from 'react';\n\nimport styles from './controls.module.css';\n\nexport interface CheckboxFieldProps {\n label: string;\n checked: boolean;\n onChange: (checked: boolean) => void;\n}\n\n/**\n * A labelled checkbox. Laid out checkbox-first (distinct from the stacked\n * {@link Field} controls), with the label associated via `htmlFor`.\n */\nexport function CheckboxField({ label, checked, onChange }: CheckboxFieldProps): React.JSX.Element {\n const id = useId();\n return (\n <div className={styles.checkboxRow}>\n <input\n id={id}\n className={styles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={(event) => {\n onChange(event.target.checked);\n }}\n />\n <label className={styles.checkboxLabel} htmlFor={id}>\n {label}\n </label>\n </div>\n );\n}\n","import { useId, useRef, useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './ImageField.module.css';\nimport controls from './controls.module.css';\n\n/** Outcome of an asset upload, returned by {@link UploadAsset}. */\nexport type AssetUploadResult =\n | { status: 'uploaded'; url: string; publicUrl: string }\n | { status: 'error'; message?: string };\n\n/**\n * Upload one image file and resolve where it now lives. Supplied by the host's\n * transport layer (it carries the admin token / origin); the UI stays\n * transport-agnostic.\n */\nexport type UploadAsset = (file: File) => Promise<AssetUploadResult>;\n\n/** `accept` attribute matching the MIME types the server accepts (security.md §4.1). */\nconst ACCEPT = 'image/jpeg,image/png,image/webp,image/gif';\n\nexport interface ImageFieldProps {\n label: string;\n /** Current image URL stored in the document. */\n value: string;\n onChange: (url: string) => void;\n errors?: readonly string[];\n hint?: string;\n /**\n * When provided, a file-upload control is rendered alongside the URL input;\n * a successful upload sets the URL to the returned (relative) path. When\n * omitted, the field is URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\n/**\n * Avatar / image field: a URL input plus, when {@link ImageFieldProps.uploadAsset}\n * is supplied, a file picker that uploads the chosen image and writes the\n * returned URL back into the field. The relative `url` (not the absolute\n * `publicUrl`) is stored so the reference stays valid across origins.\n *\n * No `<img>` preview is rendered: the admin CSP is `img-src 'self' blob:`, so a\n * preview of an arbitrary external URL would be blocked — the URL input is the\n * portable, CSP-safe surface, and the public preview shows the real image.\n */\nexport function ImageField({\n label,\n value,\n onChange,\n errors,\n hint,\n uploadAsset,\n}: ImageFieldProps): React.JSX.Element {\n const fileId = useId();\n const statusId = useId();\n const fileRef = useRef<HTMLInputElement>(null);\n const [busy, setBusy] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const handleFile = (event: React.ChangeEvent<HTMLInputElement>): void => {\n const file = event.target.files?.[0];\n if (!file || uploadAsset === undefined) return;\n setBusy(true);\n setUploadError(null);\n uploadAsset(file)\n .then((result) => {\n if (result.status === 'uploaded') {\n onChange(result.url);\n } else {\n setUploadError(result.message ?? getAdminLabel('status.uploadError'));\n }\n })\n .catch(() => {\n setUploadError(getAdminLabel('status.uploadError'));\n })\n .finally(() => {\n setBusy(false);\n // Clear the picker so re-selecting the same file fires `change` again.\n if (fileRef.current) fileRef.current.value = '';\n });\n };\n\n return (\n <Field label={label} errors={errors} hint={hint}>\n {({ controlId, describedBy, invalid }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"url\"\n value={value}\n aria-invalid={invalid || undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n onChange(event.target.value);\n }}\n />\n {uploadAsset !== undefined ? (\n <div className={styles.uploadRow}>\n <label className={styles.uploadLabel} htmlFor={fileId}>\n {getAdminLabel('field.avatarUpload')}\n </label>\n <input\n id={fileId}\n ref={fileRef}\n type=\"file\"\n accept={ACCEPT}\n disabled={busy}\n aria-describedby={statusId}\n onChange={handleFile}\n />\n <span className={styles.uploadStatus} id={statusId} role=\"status\" aria-live=\"polite\">\n {busy ? getAdminLabel('status.uploading') : ''}\n </span>\n {uploadError !== null ? (\n <span className={styles.uploadError} role=\"alert\">\n {uploadError}\n </span>\n ) : null}\n </div>\n ) : null}\n </>\n )}\n </Field>\n );\n}\n","/**\n * UI strings for the admin editor.\n *\n * The admin surface is operator-only, so a single English dictionary ships\n * today; the lookup mirrors `getUILabel` (exact locale → base subtag →\n * English) so locales can be added later without touching call sites. Keys are\n * derived from the English dictionary, so every key is guaranteed to resolve.\n */\nimport type { LocaleTag } from '@takuhon/core';\n\nconst EN = {\n 'app.title': 'takuhon admin',\n 'toolbar.label': 'Editor actions',\n 'mode.label': 'Editing mode',\n 'mode.form': 'Form',\n 'mode.advanced': 'Advanced (JSON)',\n\n 'action.save': 'Save',\n 'action.reload': 'Reload',\n 'action.export': 'Export',\n 'action.import': 'Import',\n 'action.add': 'Add',\n 'action.remove': 'Remove',\n 'action.moveUp': 'Move up',\n 'action.moveDown': 'Move down',\n\n 'status.saving': 'Saving…',\n 'status.saved': 'Saved.',\n 'status.loading': 'Loading…',\n 'status.conflict':\n 'The profile changed on the server since it was loaded. Reload, then reapply the edits.',\n 'status.invalid': 'Some fields need attention before saving.',\n 'status.fixSummary': 'Please fix the following:',\n 'status.error': 'Something went wrong. Please try again.',\n 'status.imported': 'Imported. Review the fields, then save to apply.',\n 'status.importInvalid': 'The imported file is not a valid takuhon document.',\n 'status.uploading': 'Uploading…',\n 'status.uploadError': 'Upload failed. Please try again.',\n\n 'section.profile': 'Profile',\n 'section.about': 'About',\n 'section.links': 'Links',\n 'section.careers': 'Experience',\n 'section.projects': 'Projects',\n 'section.skills': 'Skills',\n 'section.settings': 'Settings',\n 'section.education': 'Education',\n 'section.certifications': 'Certifications',\n 'section.publications': 'Publications',\n 'section.honors': 'Honors & awards',\n 'section.volunteering': 'Volunteering',\n 'section.memberships': 'Memberships',\n 'section.languages': 'Languages',\n 'section.courses': 'Courses',\n 'section.patents': 'Patents',\n 'section.testScores': 'Test scores',\n 'section.recommendations': 'Recommendations',\n 'section.contact': 'Contact',\n 'section.meta': 'Metadata',\n\n 'field.displayName': 'Display name',\n 'field.tagline': 'Tagline',\n 'field.bio': 'Bio',\n 'field.avatarUrl': 'Avatar URL',\n 'field.avatarUpload': 'Upload image',\n 'field.avatarAlt': 'Avatar alternative text',\n 'field.gravatarEmail': 'Gravatar email',\n 'field.gravatarApply': 'Use Gravatar',\n 'field.location.country': 'Country',\n 'field.location.region': 'Region',\n 'field.location.locality': 'Locality',\n 'field.location.display': 'Location (display)',\n\n 'field.link.type': 'Type',\n 'field.link.url': 'URL',\n 'field.link.label': 'Label',\n 'field.link.iconUrl': 'Icon URL',\n 'field.link.featured': 'Featured',\n\n 'field.career.organization': 'Organization',\n 'field.career.role': 'Role',\n 'field.career.description': 'Description',\n 'field.career.startDate': 'Start',\n 'field.career.endDate': 'End',\n 'field.career.isCurrent': 'Current position',\n 'field.career.url': 'URL',\n\n 'field.project.title': 'Title',\n 'field.project.description': 'Description',\n 'field.project.url': 'URL',\n 'field.project.tags': 'Tags',\n 'field.project.highlighted': 'Highlighted',\n 'field.project.startDate': 'Start',\n 'field.project.endDate': 'End',\n\n 'field.skill.label': 'Label',\n 'field.skill.category': 'Category',\n\n 'field.settings.defaultLocale': 'Default locale',\n 'field.settings.fallbackLocale': 'Fallback locale',\n 'field.settings.availableLocales': 'Available locales',\n 'field.settings.theme': 'Theme',\n 'field.settings.showPoweredBy': 'Show the \"Powered by takuhon\" footer',\n 'field.settings.enableJsonLd': 'Emit Schema.org JSON-LD',\n 'field.settings.enableApi': 'Expose the public read API',\n 'field.settings.enableAnalytics': 'Enable first-party analytics',\n 'field.settings.contact': 'Contact form',\n 'field.contactSettings.enabled': 'Enable contact form',\n 'field.contactSettings.turnstileSiteKey': 'Turnstile site key (public)',\n 'field.contactSettings.subjectPrefix': 'Email subject prefix',\n\n 'field.settings.publicVisibility': 'Public sections',\n 'field.publicVisibility.links': 'Links',\n 'field.publicVisibility.careers': 'Experience',\n 'field.publicVisibility.projects': 'Projects',\n 'field.publicVisibility.skills': 'Skills',\n 'field.publicVisibility.certifications': 'Certifications',\n 'field.publicVisibility.memberships': 'Memberships',\n 'field.publicVisibility.volunteering': 'Volunteering',\n 'field.publicVisibility.honors': 'Honors & awards',\n 'field.publicVisibility.education': 'Education',\n 'field.publicVisibility.publications': 'Publications',\n 'field.publicVisibility.languages': 'Languages',\n 'field.publicVisibility.courses': 'Courses',\n 'field.publicVisibility.patents': 'Patents',\n 'field.publicVisibility.testScores': 'Test scores',\n 'field.publicVisibility.recommendations': 'Recommendations',\n 'field.publicVisibility.contact': 'Contact',\n\n 'item.link': 'Link',\n 'item.career': 'Position',\n 'item.project': 'Project',\n 'item.skill': 'Skill',\n\n 'empty.links': 'No links yet.',\n 'empty.careers': 'No positions yet.',\n 'empty.projects': 'No projects yet.',\n 'empty.skills': 'No skills yet.',\n\n 'hint.avatarNoUpload': 'Paste an image URL. Uploading image files is not available yet.',\n 'hint.avatarUpload': 'Paste an image URL, or upload a JPEG, PNG, WebP, or GIF.',\n 'hint.gravatar':\n 'Enter an email to generate a Gravatar avatar URL. The email is not saved — only the resulting URL is stored.',\n 'hint.month': 'Format: YYYY-MM (e.g. 2024-03).',\n 'hint.country': 'ISO 3166-1 alpha-2 code, e.g. US.',\n 'hint.tags': 'Comma-separated.',\n 'hint.locales': 'Comma-separated BCP-47 tags, e.g. en, ja. Drives the language tabs above.',\n 'hint.publicVisibility':\n 'Unchecked sections are hidden from every public surface (page, API, JSON-LD). All sections are public by default.',\n 'advanced.hint': 'Edit the entire document as JSON. Edits apply only while the JSON is valid.',\n 'advanced.invalid': 'The JSON is not a valid takuhon document:',\n\n 'option.none': '(none)',\n} as const;\n\n/** Every label key understood by {@link getAdminLabel}. */\nexport type AdminLabelKey = keyof typeof EN;\n\nconst DICTIONARIES: Partial<Record<LocaleTag, Partial<Record<AdminLabelKey, string>>>> = {\n en: EN,\n};\n\n/**\n * Resolve an admin label for a locale, falling back to the base language\n * subtag and then English. English is always present, so the return is always\n * a string.\n */\nexport function getAdminLabel(key: AdminLabelKey, locale: LocaleTag = 'en'): string {\n const exact = DICTIONARIES[locale]?.[key];\n if (exact !== undefined) return exact;\n const base = locale.split('-')[0];\n const baseMatch = base ? DICTIONARIES[base]?.[key] : undefined;\n return baseMatch ?? EN[key];\n}\n","import { gravatarUrl } from '@takuhon/core';\nimport { useState } from 'react';\n\nimport { getAdminLabel } from '../admin-labels.js';\n\nimport { Field } from './Field.js';\nimport styles from './GravatarField.module.css';\nimport controls from './controls.module.css';\n\nexport interface GravatarFieldProps {\n /** Called with the generated Gravatar URL when the owner applies an email. */\n onApply: (url: string) => void;\n}\n\n/**\n * \"Use Gravatar\" control: an email input plus a button that turns the email into\n * a Gravatar avatar URL via core's pure {@link gravatarUrl}. This is the third\n * way to set an avatar, alongside pasting a URL and uploading an image.\n *\n * The email is local-only — it is never written to the document or sent\n * anywhere. Only the generated URL is handed to {@link GravatarFieldProps.onApply}\n * (which the parent writes into `avatar.url`); the email input is cleared once\n * applied, so nothing about the address lingers in the form.\n */\nexport function GravatarField({ onApply }: GravatarFieldProps): React.JSX.Element {\n const [email, setEmail] = useState('');\n const trimmed = email.trim();\n\n const apply = (): void => {\n if (trimmed === '') return;\n onApply(gravatarUrl(trimmed));\n setEmail('');\n };\n\n return (\n <Field label={getAdminLabel('field.gravatarEmail')} hint={getAdminLabel('hint.gravatar')}>\n {({ controlId, describedBy }) => (\n <>\n <input\n id={controlId}\n className={controls.control}\n type=\"email\"\n value={email}\n autoComplete=\"off\"\n aria-describedby={describedBy}\n onChange={(event) => {\n setEmail(event.target.value);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n apply();\n }\n }}\n />\n <div className={styles.actionRow}>\n <button\n type=\"button\"\n className={styles.applyButton}\n disabled={trimmed === ''}\n onClick={apply}\n >\n {getAdminLabel('field.gravatarApply')}\n </button>\n </div>\n </>\n )}\n </Field>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\nimport { useId, useRef, useState } from 'react';\n\nimport { errorsAt, hasErrorsUnder, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\n\nimport styles from './LocaleTabs.module.css';\n\nexport interface LocaleTabsProps {\n /** Group label, e.g. `\"Display name\"`. */\n label: string;\n /** Current localized value (BCP-47 tag → string), or undefined when empty. */\n value: Record<LocaleTag, string> | undefined;\n /** Locales offered as tabs (typically `settings.availableLocales`). */\n locales: readonly LocaleTag[];\n /**\n * Receives the next localized record. Empty strings are pruned, and a record\n * that becomes empty is reported as `undefined` so the field is omitted\n * rather than emitted as `{}` (which fails the schema's `minProperties`).\n */\n onChange: (next: Record<LocaleTag, string> | undefined) => void;\n /** Render a `<textarea>` instead of an `<input>` for body-length text. */\n multiline?: boolean;\n required?: boolean;\n hint?: string;\n /** Full error index; per-locale errors are looked up at `${pointer}/${locale}`. */\n errors?: FieldErrorIndex;\n /** Base RFC 6901 pointer to this localized field, e.g. `/profile/displayName`. */\n pointer?: string;\n /** Render a friendlier tab label than the raw locale tag. */\n formatLocale?: (locale: LocaleTag) => string;\n}\n\n/**\n * Edits a localized string map (`LocalizedTitle` / `LocalizedBody`) behind one\n * tab per locale (spec §14.2 \"多言語タブ\"). Implements the WAI-ARIA Tabs\n * pattern — roving tabindex, arrow/Home/End navigation, a single shared\n * `tabpanel` — so it stays keyboard-operable and screen-reader-correct\n * (WCAG 2.1 AA, spec §8.5).\n */\nexport function LocaleTabs({\n label,\n value,\n locales,\n onChange,\n multiline = false,\n required,\n hint,\n errors = NO_FIELD_ERRORS,\n pointer,\n formatLocale,\n}: LocaleTabsProps): React.JSX.Element {\n const baseId = useId();\n const hintId = useId();\n const errorId = useId();\n const [active, setActive] = useState<LocaleTag>(() => locales[0] ?? '');\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n const labelId = `${baseId}-label`;\n\n if (locales.length === 0) {\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n </span>\n <p className={styles.hint}>No locales are configured yet; add one under Settings.</p>\n </div>\n );\n }\n\n // Reconcile the active tab against the current locale list so editing\n // `availableLocales` elsewhere never strands the selection on a stale tag.\n const activeLocale = locales.includes(active) ? active : locales[0]!;\n const text = value?.[activeLocale] ?? '';\n // Errors on the field itself (`required`, `minProperties`,\n // `propertyNames`) land on the base pointer, not on a locale key, so surface\n // both — otherwise a missing-value failure would be invisible.\n const baseErrors = pointer ? errorsAt(errors, pointer) : [];\n const localeErrors = pointer ? errorsAt(errors, `${pointer}/${activeLocale}`) : [];\n const shownErrors = [...baseErrors, ...localeErrors];\n const hasErrors = shownErrors.length > 0;\n const describedBy =\n [hint ? hintId : undefined, hasErrors ? errorId : undefined].filter(Boolean).join(' ') ||\n undefined;\n\n const setText = (next: string): void => {\n const record: Record<string, string> = { ...(value ?? {}) };\n if (next === '') delete record[activeLocale];\n else record[activeLocale] = next;\n onChange(Object.keys(record).length === 0 ? undefined : record);\n };\n\n const onTabKeyDown = (event: React.KeyboardEvent): void => {\n const current = locales.indexOf(activeLocale);\n let nextIndex: number;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowDown':\n nextIndex = (current + 1) % locales.length;\n break;\n case 'ArrowLeft':\n case 'ArrowUp':\n nextIndex = (current - 1 + locales.length) % locales.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = locales.length - 1;\n break;\n default:\n return;\n }\n event.preventDefault();\n const nextLocale = locales[nextIndex];\n if (nextLocale !== undefined) {\n setActive(nextLocale);\n tabRefs.current[nextLocale]?.focus();\n }\n };\n\n const controlName = `${label} (${format(activeLocale)})`;\n\n return (\n <div className={styles.group} role=\"group\" aria-labelledby={labelId}>\n <span className={styles.groupLabel} id={labelId}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </span>\n {hint ? (\n <p className={styles.hint} id={hintId}>\n {hint}\n </p>\n ) : null}\n <div className={styles.tablist} role=\"tablist\" aria-label={label}>\n {locales.map((locale) => {\n const selected = locale === activeLocale;\n const tabHasErrors = pointer ? hasErrorsUnder(errors, `${pointer}/${locale}`) : false;\n return (\n <button\n key={locale}\n ref={(element) => {\n tabRefs.current[locale] = element;\n }}\n type=\"button\"\n role=\"tab\"\n id={`${baseId}-tab-${locale}`}\n aria-selected={selected}\n aria-controls={`${baseId}-panel`}\n tabIndex={selected ? 0 : -1}\n className={`${styles.tab} ${selected ? styles.tabActive : ''}`}\n onClick={() => {\n setActive(locale);\n }}\n onKeyDown={onTabKeyDown}\n >\n {format(locale)}\n {tabHasErrors ? (\n <>\n <span className={styles.tabError} aria-hidden=\"true\">\n {' '}\n ●\n </span>\n <span className={styles.srOnly}> (has errors)</span>\n </>\n ) : null}\n </button>\n );\n })}\n </div>\n <div\n role=\"tabpanel\"\n id={`${baseId}-panel`}\n aria-labelledby={`${baseId}-tab-${activeLocale}`}\n className={styles.panel}\n >\n {multiline ? (\n <textarea\n className={`${styles.control} ${styles.textarea}`}\n value={text}\n rows={4}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n ) : (\n <input\n className={styles.control}\n type=\"text\"\n value={text}\n aria-label={controlName}\n aria-invalid={hasErrors || undefined}\n aria-required={required ? true : undefined}\n aria-describedby={describedBy}\n onChange={(event) => {\n setText(event.target.value);\n }}\n />\n )}\n {hasErrors ? (\n <ul className={styles.errors} id={errorId}>\n {shownErrors.map((message, i) => (\n <li key={i}>{message}</li>\n ))}\n </ul>\n ) : null}\n </div>\n </div>\n );\n}\n","import styles from './Repeater.module.css';\n\nexport interface RepeaterProps<T> {\n /** Group caption rendered as the fieldset legend, e.g. `\"Links\"`. */\n legend: string;\n items: readonly T[];\n /** Receives the next array after an add / remove / reorder / item edit. */\n onChange: (next: T[]) => void;\n /** Render one item's fields; `update` replaces that item in place. */\n renderItem: (item: T, update: (next: T) => void, index: number) => React.ReactNode;\n /** Factory for the entry appended by the Add button. */\n createItem: () => T;\n /** Stable React key per item. Defaults to the index. */\n keyOf?: (item: T, index: number) => string;\n /** Human label for an item, used in the item caption and button names. */\n itemLabel: (item: T, index: number) => string;\n addLabel?: string;\n removeLabel?: string;\n moveUpLabel?: string;\n moveDownLabel?: string;\n /** Shown when there are no items yet. */\n emptyHint?: string;\n}\n\n/**\n * Add / remove / reorder editor for a repeating array field (spec §14.2\n * \"リピーター\"). Reordering uses keyboard-operable Move up / Move down buttons\n * rather than drag-and-drop so the control meets WCAG 2.1 AA (spec §8.5)\n * without a pointer.\n */\nexport function Repeater<T>({\n legend,\n items,\n onChange,\n renderItem,\n createItem,\n keyOf,\n itemLabel,\n addLabel = 'Add',\n removeLabel = 'Remove',\n moveUpLabel = 'Move up',\n moveDownLabel = 'Move down',\n emptyHint,\n}: RepeaterProps<T>): React.JSX.Element {\n const key = keyOf ?? ((_item: T, index: number) => String(index));\n\n const update = (index: number, next: T): void => {\n const copy = items.slice();\n copy[index] = next;\n onChange(copy);\n };\n\n const remove = (index: number): void => {\n onChange(items.filter((_item, i) => i !== index));\n };\n\n const move = (from: number, to: number): void => {\n if (to < 0 || to >= items.length) return;\n const copy = items.slice();\n const [moved] = copy.splice(from, 1);\n if (moved === undefined) return;\n copy.splice(to, 0, moved);\n onChange(copy);\n };\n\n return (\n <fieldset className={styles.fieldset}>\n <legend className={styles.legend}>{legend}</legend>\n {items.length === 0 && emptyHint ? <p className={styles.empty}>{emptyHint}</p> : null}\n <ol className={styles.list}>\n {items.map((item, index) => {\n const caption = itemLabel(item, index);\n return (\n <li key={key(item, index)} className={styles.item}>\n <div role=\"group\" aria-label={caption}>\n <div className={styles.itemHeader}>\n <span className={styles.itemCaption}>{caption}</span>\n <div className={styles.itemActions}>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveUpLabel}: ${caption}`}\n disabled={index === 0}\n onClick={() => {\n move(index, index - 1);\n }}\n >\n ↑\n </button>\n <button\n type=\"button\"\n className={styles.iconButton}\n aria-label={`${moveDownLabel}: ${caption}`}\n disabled={index === items.length - 1}\n onClick={() => {\n move(index, index + 1);\n }}\n >\n ↓\n </button>\n <button\n type=\"button\"\n className={styles.removeButton}\n aria-label={`${removeLabel}: ${caption}`}\n onClick={() => {\n remove(index);\n }}\n >\n {removeLabel}\n </button>\n </div>\n </div>\n <div className={styles.itemBody}>\n {renderItem(\n item,\n (next) => {\n update(index, next);\n },\n index,\n )}\n </div>\n </div>\n </li>\n );\n })}\n </ol>\n <button\n type=\"button\"\n className={styles.addButton}\n onClick={() => {\n onChange([...items, createItem()]);\n }}\n >\n {addLabel}\n </button>\n </fieldset>\n );\n}\n","/**\n * Build a unique slug like `link-1` that is not already in `taken`. The prefix\n * is lowercased and stripped to `[a-z0-9-]` (falling back to `item`) so the\n * result always matches the `Slug` pattern `^[a-z0-9][a-z0-9-]*$`.\n * Deterministic given the existing ids, so it needs no random source.\n */\nexport function makeId(prefix: string, taken: Iterable<string>): string {\n const safe = prefix.toLowerCase().replace(/[^a-z0-9-]/g, '') || 'item';\n const used = new Set(taken);\n let n = 1;\n while (used.has(`${safe}-${String(n)}`)) n += 1;\n return `${safe}-${String(n)}`;\n}\n","import type { LocaleTag } from '@takuhon/core';\n\n/**\n * First non-empty localized value, preferring the order of `locales` and\n * falling back to any present value. Used for repeater item captions where a\n * single human-readable string is needed regardless of the active locale.\n */\nexport function firstLocalized(\n record: Record<LocaleTag, string> | undefined,\n locales: readonly LocaleTag[],\n): string {\n if (!record) return '';\n for (const locale of locales) {\n const value = record[locale];\n if (value) return value;\n }\n return Object.values(record).find((value) => value !== '') ?? '';\n}\n","/**\n * Schema-driven field classification for the admin editor.\n *\n * Maps a node of the canonical takuhon JSON Schema (2020-12) to a\n * {@link FieldKind} — the widget the admin form should render for it. This is\n * the pure-logic foundation of the schema-driven form engine (design:\n * `admin-form-schema-driven-design.md`). It resolves local `$ref`s against\n * `$defs` and unwraps nullable `anyOf` unions, so the renderer never hand-wires\n * fields per section. No React here; the classifier is fully unit-testable.\n *\n * Presentation concerns the schema cannot express (widget overrides, ordering,\n * help text, cross-section reference selectors, image/Gravatar widgets) live in\n * a separate field-spec registry, not in the data schema (design decision A1).\n */\n\n/**\n * Minimal structural view of a JSON Schema 2020-12 node — only the keywords the\n * classifier reads. The canonical schema (`@takuhon/core`'s `schema`) is cast to\n * this for traversal.\n */\nexport interface SchemaNode {\n $ref?: string;\n $defs?: Record<string, SchemaNode>;\n type?: string | readonly string[];\n format?: string;\n enum?: readonly unknown[];\n properties?: Record<string, SchemaNode>;\n required?: readonly string[];\n items?: SchemaNode;\n anyOf?: readonly SchemaNode[];\n maxLength?: number;\n minimum?: number;\n description?: string;\n default?: unknown;\n}\n\n/** The widget the admin form should render for a classified schema node. */\nexport type FieldKind =\n | { widget: 'text'; maxLength?: number }\n | { widget: 'url' }\n | { widget: 'email' }\n | { widget: 'month' }\n | { widget: 'date' }\n | { widget: 'datetime' }\n | { widget: 'integer'; minimum?: number }\n | { widget: 'checkbox'; default?: boolean }\n | { widget: 'select'; options: readonly string[] }\n | { widget: 'localeTag' }\n | { widget: 'localizedTitle' }\n | { widget: 'localizedBody' }\n | { widget: 'slug' }\n | { widget: 'array'; item: FieldKind }\n | { widget: 'object'; fields: readonly FieldEntry[] }\n | { widget: 'unsupported' };\n\n/** A named property of an object schema: its optionality and classified kind. */\nexport interface FieldEntry {\n name: string;\n /** Listed in the object's `required` array. */\n required: boolean;\n /** The schema permits an explicit `null` (e.g. `anyOf: [X, { type: 'null' }]`). */\n nullable: boolean;\n kind: FieldKind;\n}\n\n/** Result of following one `$ref` and unwrapping a nullable `anyOf` union. */\nexport interface Resolved {\n node: SchemaNode;\n /** `$defs` name the node resolved from, after following one local `$ref`. */\n ref?: string;\n nullable: boolean;\n}\n\nconst REF_PREFIX = '#/$defs/';\n\n/** Name of the `$defs` entry a node's `$ref` targets, or `undefined`. */\nexport function refName(node: SchemaNode): string | undefined {\n const ref = node.$ref;\n if (typeof ref !== 'string' || !ref.startsWith(REF_PREFIX)) return undefined;\n return ref.slice(REF_PREFIX.length);\n}\n\n/**\n * Follow a single local `$ref` and unwrap a nullable union\n * (`anyOf: [X, { type: 'null' }]` → `X` with `nullable: true`). Idempotent for\n * already-concrete nodes; a missing `$ref` target leaves the node unchanged.\n */\nexport function deref(root: SchemaNode, node: SchemaNode): Resolved {\n let current = node;\n let nullable = false;\n\n const variants = current.anyOf;\n if (variants) {\n const nonNull = variants.filter((variant) => variant.type !== 'null');\n const [only] = nonNull;\n if (only && nonNull.length === 1 && nonNull.length < variants.length) {\n nullable = true;\n current = only;\n }\n }\n\n const name = refName(current);\n if (name === undefined) return { node: current, nullable };\n const target = root.$defs?.[name];\n if (!target) return { node: current, nullable };\n return { node: target, ref: name, nullable };\n}\n\n// Well-known scalar `$defs` whose intended widget is not inferable from `type`\n// alone (pattern-only strings) or carries domain meaning worth a dedicated UI.\nconst REF_WIDGET: Readonly<Record<string, FieldKind>> = {\n LocalizedTitle: { widget: 'localizedTitle' },\n LocalizedBody: { widget: 'localizedBody' },\n YearMonth: { widget: 'month' },\n Slug: { widget: 'slug' },\n LocaleTag: { widget: 'localeTag' },\n};\n\n/** Classify a (possibly `$ref`/nullable) schema node into the widget to render. */\nexport function classifyNode(root: SchemaNode, node: SchemaNode): FieldKind {\n const { node: resolved, ref } = deref(root, node);\n\n if (ref !== undefined) {\n const known = REF_WIDGET[ref];\n if (known) return known;\n }\n\n if (Array.isArray(resolved.enum)) {\n return { widget: 'select', options: resolved.enum.map((value) => String(value)) };\n }\n\n const type = typeof resolved.type === 'string' ? resolved.type : undefined;\n\n if (type === 'string') {\n switch (resolved.format) {\n case 'email':\n return { widget: 'email' };\n case 'uri':\n return { widget: 'url' };\n case 'date':\n return { widget: 'date' };\n case 'date-time':\n return { widget: 'datetime' };\n default:\n return resolved.maxLength === undefined\n ? { widget: 'text' }\n : { widget: 'text', maxLength: resolved.maxLength };\n }\n }\n if (type === 'boolean') {\n // Carry the schema `default` so the checkbox can reflect it: a field with a\n // default (e.g. settings flags default true) shows that state when absent\n // and stores its value explicitly, while a default-less boolean stays\n // sparse (unchecked when absent, dropped when false).\n return typeof resolved.default === 'boolean'\n ? { widget: 'checkbox', default: resolved.default }\n : { widget: 'checkbox' };\n }\n if (type === 'integer' || type === 'number') {\n return resolved.minimum === undefined\n ? { widget: 'integer' }\n : { widget: 'integer', minimum: resolved.minimum };\n }\n if (type === 'array') {\n const item: FieldKind = resolved.items\n ? classifyNode(root, resolved.items)\n : { widget: 'unsupported' };\n return { widget: 'array', item };\n }\n if (type === 'object') {\n return { widget: 'object', fields: objectEntries(root, resolved) };\n }\n return { widget: 'unsupported' };\n}\n\n/** Classified properties of an object schema, in declaration order. */\nexport function objectEntries(root: SchemaNode, objectSchema: SchemaNode): FieldEntry[] {\n const properties = objectSchema.properties ?? {};\n const required = new Set(objectSchema.required ?? []);\n return Object.entries(properties).map(([name, propNode]) => ({\n name,\n required: required.has(name),\n nullable: deref(root, propNode).nullable,\n kind: classifyNode(root, propNode),\n }));\n}\n\n/** Classify a top-level section (e.g. `'education'`, `'contact'`) by name. */\nexport function sectionFieldKind(root: SchemaNode, section: string): FieldKind {\n const node = root.properties?.[section];\n if (!node) return { widget: 'unsupported' };\n return classifyNode(root, node);\n}\n","/**\n * Field-spec registry — the UI-hint layer the data schema deliberately does not\n * carry (design decision A1). Keyed by a section-relative dot path *without*\n * array indices (e.g. `education.institution`, `meta.createdAt`), it overrides\n * or augments the schema-derived classification with presentation concerns:\n * labels, help text, hiding auto-managed fields, forcing a widget.\n *\n * Keeping these out of `takuhon.schema.json` leaves the data contract pure\n * (consumers / validators see no UI noise) and means this track changes no\n * `schemaVersion`.\n */\n\nimport type { LocaleTag } from '@takuhon/core';\n\nimport type { FieldErrorIndex } from '../errors.js';\nimport type { UploadAsset } from '../primitives/ImageField.js';\n\nimport type { FieldKind } from './field-classification.js';\n\n/**\n * Everything a custom field renderer needs. The engine builds this as it walks,\n * so a bespoke widget (avatar, comma-separated list, visibility matrix) plugs in\n * without re-deriving its pointer/path or re-threading locales and errors. This\n * is the escape hatch for the handful of fields a generic widget cannot capture\n * (design §8 \"generic default + targeted craft\").\n */\nexport interface CustomFieldContext {\n /** Current value at this path. */\n value: unknown;\n /** Write the next value for this field back into the document. */\n onChange: (next: unknown) => void;\n /** RFC 6901 pointer (with array indices) for error lookup. */\n pointer: string;\n /** Registry path (no array indices). */\n path: string;\n /** Resolved label (registry override or humanized field name). */\n label: string;\n /** Listed in the parent object's `required`. */\n required: boolean;\n locales: readonly LocaleTag[];\n errors: FieldErrorIndex;\n formatLocale?: (locale: LocaleTag) => string;\n /** Avatar upload, threaded from the host; absent means URL-only. */\n uploadAsset?: UploadAsset;\n /**\n * The whole document (root value), so a field can read sibling sections —\n * e.g. a reference selector listing `careers[]` / `education[]` ids. Typed\n * `unknown` to keep the engine schema-generic; renderers narrow it.\n */\n document?: unknown;\n}\n\n/** Presentation overrides for a single field, looked up by its schema path. */\nexport interface FieldHint {\n /** Replace the humanized field name. */\n label?: string;\n /** Help text shown under the control. */\n hint?: string;\n /** Omit from the form (the value is still preserved in the document). */\n hidden?: boolean;\n /** Render this widget instead of the schema-derived one. */\n widget?: FieldKind['widget'];\n /** Force multiline for a localized/text field. */\n multiline?: boolean;\n /**\n * Render a bespoke control for this field instead of the schema-derived\n * widget. Used for the few fields no generic widget captures (avatar,\n * comma-separated lists, the public-visibility matrix).\n */\n render?: (ctx: CustomFieldContext) => React.ReactNode;\n}\n\n/** Schema-path → hint. Paths use dots and never include array indices. */\nexport type FieldRegistry = Readonly<Record<string, FieldHint>>;\n\nexport const EMPTY_REGISTRY: FieldRegistry = {};\n\n/**\n * Acronyms that read poorly when title-cased: a humanized `url` should be `URL`,\n * not `Url`, and `credentialId` should end in `ID`, not `id`. Matched per word\n * (after camelCase splitting), so only a whole segment is uppercased. Extend as\n * the schema grows; the registry can still override any label outright.\n */\nconst ACRONYMS = new Set(['url', 'id', 'doi']);\n\n/**\n * Humanize a property name for a default label: `fieldOfStudy` → `Field of\n * study`, `credentialId` → `Credential ID`, `url` → `URL`. Known acronyms stay\n * uppercased. The registry overrides this where a better label is needed.\n */\nexport function humanize(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .toLowerCase()\n .split(' ');\n return words\n .map((word, index) =>\n ACRONYMS.has(word)\n ? word.toUpperCase()\n : index === 0\n ? word.charAt(0).toUpperCase() + word.slice(1)\n : word,\n )\n .join(' ');\n}\n\n/** The hint at `path`, or an empty hint when none is registered. */\nexport function hintAt(registry: FieldRegistry, path: string): FieldHint {\n return registry[path] ?? {};\n}\n","/**\n * Schema-driven form engine.\n *\n * Renders an editable form for any takuhon section straight from its\n * {@link FieldKind} (see `field-classification.ts`), using the existing admin\n * primitives. The RFC 6901 `pointer` (with array indices, for error lookup) and\n * the registry `path` (without indices, for UI hints) are derived automatically\n * as the engine walks — so no section hand-wires field plumbing or pointer\n * strings. Presentation overrides come from the {@link FieldRegistry}\n * (decision A1); the data schema stays UI-free.\n *\n * Values are treated as `unknown` and narrowed per kind — the document has been\n * (or will be) validated against the schema, so each branch's cast is sound.\n */\n\nimport type { LocaleTag } from '@takuhon/core';\n\nimport { getAdminLabel } from '../admin-labels.js';\nimport { errorsAt, NO_FIELD_ERRORS, type FieldErrorIndex } from '../errors.js';\nimport { makeId } from '../ids.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { type UploadAsset } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { Repeater } from '../primitives/Repeater.js';\nimport { SelectField, type SelectOption } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport { type FieldEntry, type FieldKind } from './field-classification.js';\nimport {\n EMPTY_REGISTRY,\n hintAt,\n humanize,\n type CustomFieldContext,\n type FieldRegistry,\n} from './field-registry.js';\n\nexport interface SchemaFormProps {\n /** Classified shape of the section (from `sectionFieldKind`). */\n kind: FieldKind;\n /** Current value for the section. */\n value: unknown;\n /** Receives the next value on any edit. */\n onChange: (next: unknown) => void;\n /** RFC 6901 pointer to this value, e.g. `/education`. */\n pointer: string;\n /** Registry path (no array indices). Defaults to the pointer sans leading slash. */\n path?: string;\n /** Heading for the section / object. */\n label: string;\n locales: readonly LocaleTag[];\n errors?: FieldErrorIndex;\n registry?: FieldRegistry;\n formatLocale?: (locale: LocaleTag) => string;\n /** Avatar upload, threaded to the avatar field's custom renderer. */\n uploadAsset?: UploadAsset;\n /** Whole document, so reference fields can list sibling-section ids. */\n document?: unknown;\n}\n\ninterface RenderCtx {\n pointer: string;\n path: string;\n label: string;\n /** Help text shown under the control (registry hint), if any. */\n hint?: string;\n required: boolean;\n multiline: boolean;\n locales: readonly LocaleTag[];\n errors: FieldErrorIndex;\n registry: FieldRegistry;\n formatLocale?: (locale: LocaleTag) => string;\n uploadAsset?: UploadAsset;\n document?: unknown;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\n\nfunction asLocalized(value: unknown): Record<LocaleTag, string> | undefined {\n return value && typeof value === 'object' ? (value as Record<LocaleTag, string>) : undefined;\n}\n\nfunction asString(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\n/** Set (or, with `undefined`, clear) one key, preserving the existing pattern of\n * optional fields holding `undefined` rather than being deleted. */\nfunction withKey(\n obj: Record<string, unknown>,\n name: string,\n next: unknown,\n): Record<string, unknown> {\n return { ...obj, [name]: next };\n}\n\nfunction idOf(item: unknown): string | undefined {\n const id = asRecord(item).id;\n return typeof id === 'string' ? id : undefined;\n}\n\nfunction lastSegment(path: string): string {\n const parts = path.split('.');\n return parts[parts.length - 1] ?? path;\n}\n\n/** A blank value seeded with the kind's required fields (ids auto-generated). */\nfunction blankValue(kind: FieldKind, takenIds: readonly string[], path: string): unknown {\n switch (kind.widget) {\n case 'object': {\n const obj: Record<string, unknown> = {};\n for (const field of kind.fields) {\n if (!field.required) continue;\n obj[field.name] =\n field.kind.widget === 'slug'\n ? makeId(lastSegment(path), takenIds)\n : blankValue(field.kind, [], `${path}.${field.name}`);\n }\n return obj;\n }\n case 'checkbox':\n return false;\n case 'integer':\n return 0;\n case 'localizedTitle':\n case 'localizedBody':\n return {};\n case 'select':\n return kind.options[0] ?? '';\n case 'array':\n return [];\n default:\n return '';\n }\n}\n\n/** A human caption for a repeater item: first localized title, else first text. */\nfunction captionOf(item: unknown, itemKind: FieldKind, locales: readonly LocaleTag[]): string {\n if (itemKind.widget !== 'object') return asString(item);\n const obj = asRecord(item);\n for (const field of itemKind.fields) {\n if (field.kind.widget === 'localizedTitle') {\n const caption = firstLocalized(asLocalized(obj[field.name]), locales);\n if (caption) return caption;\n }\n }\n for (const field of itemKind.fields) {\n if (field.kind.widget === 'text' || field.kind.widget === 'select') {\n const value = asString(obj[field.name]);\n if (value) return value;\n }\n }\n return '';\n}\n\nfunction renderScalar(\n kind: FieldKind,\n value: unknown,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const errors = errorsAt(ctx.errors, ctx.pointer);\n switch (kind.widget) {\n case 'localizedTitle':\n case 'localizedBody':\n return (\n <LocaleTabs\n label={ctx.label}\n value={asLocalized(value)}\n locales={ctx.locales}\n onChange={(next) => {\n onChange(next);\n }}\n multiline={kind.widget === 'localizedBody' || ctx.multiline}\n required={ctx.required}\n pointer={ctx.pointer}\n errors={ctx.errors}\n formatLocale={ctx.formatLocale}\n />\n );\n case 'checkbox': {\n // A boolean with a schema default reflects that default when absent and is\n // stored explicitly (so `false` persists). A default-less boolean stays\n // sparse: unchecked when absent, dropped from the document when false.\n const hasDefault = kind.default !== undefined;\n const checked = value === undefined ? (kind.default ?? false) : value === true;\n return (\n <CheckboxField\n label={ctx.label}\n checked={checked}\n onChange={(next) => {\n onChange(hasDefault ? next : next || undefined);\n }}\n />\n );\n }\n case 'select':\n case 'localeTag': {\n // An optional locale select offers an explicit \"(none)\" so it can be\n // cleared; a required one (e.g. defaultLocale) does not.\n const localeOptions: readonly SelectOption[] = ctx.locales.map((locale) => ({\n value: locale,\n label: ctx.formatLocale ? ctx.formatLocale(locale) : locale,\n }));\n const options: readonly SelectOption[] =\n kind.widget === 'select'\n ? kind.options.map((option) => ({ value: option, label: option }))\n : ctx.required\n ? localeOptions\n : [{ value: '', label: getAdminLabel('option.none') }, ...localeOptions];\n return (\n <SelectField\n label={ctx.label}\n value={asString(value)}\n options={options}\n onChange={(next) => {\n onChange(next || undefined);\n }}\n required={ctx.required}\n errors={errors}\n />\n );\n }\n case 'integer':\n return (\n <TextField\n label={ctx.label}\n type=\"text\"\n inputMode=\"numeric\"\n value={typeof value === 'number' ? String(value) : ''}\n onChange={(next) => {\n onChange(next === '' ? undefined : Number(next));\n }}\n required={ctx.required}\n hint={ctx.hint}\n errors={errors}\n />\n );\n default: {\n // text / url / email / month / date / datetime / slug → a text-like input.\n // TextField supports text|url|email|month; date/datetime/slug fall to text.\n const type =\n kind.widget === 'url'\n ? 'url'\n : kind.widget === 'email'\n ? 'email'\n : kind.widget === 'month'\n ? 'month'\n : 'text';\n // Year-month fields advertise the `YYYY-MM` format by default, the way the\n // bespoke career/project forms did, so every section stays consistent. A\n // registry hint still wins where one is set.\n const hint = ctx.hint ?? (kind.widget === 'month' ? getAdminLabel('hint.month') : undefined);\n return (\n <TextField\n label={ctx.label}\n type={type}\n value={asString(value)}\n onChange={(next) => {\n onChange(next || undefined);\n }}\n required={ctx.required}\n hint={hint}\n errors={errors}\n />\n );\n }\n }\n}\n\nfunction renderEntry(\n entry: FieldEntry,\n obj: Record<string, unknown>,\n onChange: (next: Record<string, unknown>) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const path = ctx.path ? `${ctx.path}.${entry.name}` : entry.name;\n const hint = hintAt(ctx.registry, path);\n if (hint.hidden) return null;\n const childCtx: RenderCtx = {\n ...ctx,\n pointer: `${ctx.pointer}/${entry.name}`,\n path,\n label: hint.label ?? humanize(entry.name),\n hint: hint.hint,\n required: entry.required,\n multiline: hint.multiline ?? false,\n };\n const update = (next: unknown): void => {\n onChange(withKey(obj, entry.name, next));\n };\n if (hint.render) {\n const customCtx: CustomFieldContext = {\n value: obj[entry.name],\n onChange: update,\n pointer: childCtx.pointer,\n path: childCtx.path,\n label: childCtx.label,\n required: childCtx.required,\n locales: childCtx.locales,\n errors: childCtx.errors,\n formatLocale: childCtx.formatLocale,\n uploadAsset: childCtx.uploadAsset,\n document: childCtx.document,\n };\n return <div key={entry.name}>{hint.render(customCtx)}</div>;\n }\n return (\n <div key={entry.name}>\n {entry.kind.widget === 'object' ? (\n // Nested objects (location, the activity providers, meta.privacy) become\n // their own labelled fieldset, so same-named children (github.username\n // vs wakatime.username) stay distinguishable.\n <fieldset>\n <legend>{childCtx.label}</legend>\n {renderObjectFields(entry.kind, asRecord(obj[entry.name]), update, childCtx)}\n </fieldset>\n ) : entry.kind.widget === 'array' ? (\n renderArray(entry.kind, obj[entry.name], update, childCtx)\n ) : (\n renderScalar(entry.kind, obj[entry.name], update, childCtx)\n )}\n </div>\n );\n}\n\nfunction renderObjectFields(\n kind: Extract<FieldKind, { widget: 'object' }>,\n obj: Record<string, unknown>,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const update = (next: Record<string, unknown>): void => {\n onChange(next);\n };\n return kind.fields.map((entry) => renderEntry(entry, obj, update, ctx));\n}\n\nfunction renderArray(\n kind: Extract<FieldKind, { widget: 'array' }>,\n value: unknown,\n onChange: (next: unknown) => void,\n ctx: RenderCtx,\n): React.ReactNode {\n const items: readonly unknown[] = Array.isArray(value) ? (value as readonly unknown[]) : [];\n const itemKind = kind.item;\n const takenIds = items.map(idOf).filter((id): id is string => id !== undefined);\n return (\n <Repeater<unknown>\n legend={ctx.label}\n items={items}\n onChange={(next) => {\n onChange(next);\n }}\n keyOf={(item, index) => idOf(item) ?? String(index)}\n itemLabel={(item, index) =>\n captionOf(item, itemKind, ctx.locales) || `${ctx.label} ${String(index + 1)}`\n }\n createItem={() => blankValue(itemKind, takenIds, ctx.path)}\n addLabel={getAdminLabel('action.add')}\n removeLabel={getAdminLabel('action.remove')}\n moveUpLabel={getAdminLabel('action.moveUp')}\n moveDownLabel={getAdminLabel('action.moveDown')}\n renderItem={(item, update, index) => {\n const itemCtx: RenderCtx = { ...ctx, pointer: `${ctx.pointer}/${String(index)}` };\n return itemKind.widget === 'object'\n ? renderObjectFields(itemKind, asRecord(item), update, itemCtx)\n : renderScalar(itemKind, item, update, itemCtx);\n }}\n />\n );\n}\n\n/**\n * Render a section's form from its schema-derived {@link FieldKind}. Array\n * sections become a {@link Repeater}; object sections a labelled fieldset;\n * scalars map to the matching primitive.\n */\nexport function SchemaForm(props: SchemaFormProps): React.JSX.Element {\n const ctx: RenderCtx = {\n pointer: props.pointer,\n path: props.path ?? props.pointer.replace(/^\\//, '').replace(/\\//g, '.'),\n label: props.label,\n required: true,\n multiline: false,\n locales: props.locales,\n errors: props.errors ?? NO_FIELD_ERRORS,\n registry: props.registry ?? EMPTY_REGISTRY,\n formatLocale: props.formatLocale,\n uploadAsset: props.uploadAsset,\n document: props.document,\n };\n\n if (props.kind.widget === 'array') {\n return <>{renderArray(props.kind, props.value, props.onChange, ctx)}</>;\n }\n if (props.kind.widget === 'object') {\n return (\n <fieldset>\n <legend>{props.label}</legend>\n {renderObjectFields(props.kind, asRecord(props.value), props.onChange, ctx)}\n </fieldset>\n );\n }\n return <>{renderScalar(props.kind, props.value, props.onChange, ctx)}</>;\n}\n","/**\n * The admin editor's single source of truth for which sections to render and how.\n *\n * {@link ADMIN_SECTIONS} lists every top-level section in display order; the\n * {@link SchemaForm} engine renders each one from the schema. {@link SECTION_REGISTRY}\n * is the UI-hint layer (decision A1): bespoke renderers for the few fields a\n * generic widget cannot capture (avatar, comma-separated lists, the visibility\n * matrix), plus curated labels and help text. The data schema stays UI-free.\n */\n\nimport { type Takuhon } from '@takuhon/core';\n\nimport { getAdminLabel, type AdminLabelKey } from '../admin-labels.js';\n\nimport {\n csvListRenderer,\n referenceSelect,\n renderAvatar,\n renderVisibilityMatrix,\n} from './custom-fields.js';\nimport { type FieldRegistry } from './field-registry.js';\n\nexport interface AdminSection {\n key: keyof Takuhon;\n label: AdminLabelKey;\n}\n\n/**\n * All editable sections, in display order. The first six were once bespoke\n * forms; they now share the schema-driven engine with the rest, so every section\n * is a form (spec §14.2 Phase 5, no more raw-JSON-only sections).\n */\nexport const ADMIN_SECTIONS: readonly AdminSection[] = [\n { key: 'profile', label: 'section.profile' },\n { key: 'links', label: 'section.links' },\n { key: 'careers', label: 'section.careers' },\n { key: 'projects', label: 'section.projects' },\n { key: 'skills', label: 'section.skills' },\n { key: 'settings', label: 'section.settings' },\n { key: 'education', label: 'section.education' },\n { key: 'certifications', label: 'section.certifications' },\n { key: 'publications', label: 'section.publications' },\n { key: 'honors', label: 'section.honors' },\n { key: 'volunteering', label: 'section.volunteering' },\n { key: 'memberships', label: 'section.memberships' },\n { key: 'languages', label: 'section.languages' },\n { key: 'courses', label: 'section.courses' },\n { key: 'patents', label: 'section.patents' },\n { key: 'testScores', label: 'section.testScores' },\n { key: 'recommendations', label: 'section.recommendations' },\n { key: 'contact', label: 'section.contact' },\n { key: 'meta', label: 'section.meta' },\n] as const satisfies readonly AdminSection[];\n\n/**\n * UI hints keyed by section-relative dot path (no array indices). Covers the\n * bespoke widgets (avatar, comma-separated lists, visibility matrix, and\n * cross-section reference selectors), curated labels for fields whose humanized\n * name reads poorly, help text, and the auto-managed meta fields that stay\n * hidden.\n */\nexport const SECTION_REGISTRY: FieldRegistry = {\n // Profile — avatar is the URL/upload/Gravatar trio.\n 'profile.avatar': { render: renderAvatar },\n 'profile.location.country': { hint: getAdminLabel('hint.country') },\n 'profile.location.display': { label: getAdminLabel('field.location.display') },\n\n // Links.\n 'links.url': { label: getAdminLabel('field.link.url') },\n 'links.iconUrl': { label: getAdminLabel('field.link.iconUrl') },\n\n // Careers.\n 'careers.startDate': {\n label: getAdminLabel('field.career.startDate'),\n hint: getAdminLabel('hint.month'),\n },\n 'careers.endDate': {\n label: getAdminLabel('field.career.endDate'),\n hint: getAdminLabel('hint.month'),\n },\n 'careers.isCurrent': { label: getAdminLabel('field.career.isCurrent') },\n 'careers.url': { label: getAdminLabel('field.career.url') },\n\n // Projects — tags are a comma-separated list; relatedCareerId is a reference.\n 'projects.tags': { render: csvListRenderer({ hint: 'hint.tags', emptyToUndefined: true }) },\n 'projects.relatedCareerId': {\n render: referenceSelect({ section: 'careers', captionField: 'organization' }),\n },\n 'projects.url': { label: getAdminLabel('field.project.url') },\n 'projects.startDate': { hint: getAdminLabel('hint.month') },\n 'projects.endDate': { hint: getAdminLabel('hint.month') },\n\n // Settings — locales are comma-separated, visibility is the inverted matrix.\n 'settings.availableLocales': {\n render: csvListRenderer({ hint: 'hint.locales', emptyToUndefined: false }),\n },\n 'settings.theme': { label: getAdminLabel('field.settings.theme') },\n 'settings.showPoweredBy': { label: getAdminLabel('field.settings.showPoweredBy') },\n 'settings.enableJsonLd': { label: getAdminLabel('field.settings.enableJsonLd') },\n 'settings.enableApi': { label: getAdminLabel('field.settings.enableApi') },\n 'settings.enableAnalytics': { label: getAdminLabel('field.settings.enableAnalytics') },\n 'settings.activity.github': { label: 'GitHub' },\n 'settings.activity.wakatime': { label: 'WakaTime' },\n 'settings.publicVisibility': { render: renderVisibilityMatrix },\n // Contact form (1.1.0) — labelled \"Contact form\" so its group legend does not\n // collide with the profile \"Contact\" section. Only public config lives here;\n // the Turnstile secret and recipient are environment configuration.\n 'settings.contact': { label: getAdminLabel('field.settings.contact') },\n 'settings.contact.enabled': { label: getAdminLabel('field.contactSettings.enabled') },\n 'settings.contact.turnstileSiteKey': {\n label: getAdminLabel('field.contactSettings.turnstileSiteKey'),\n },\n 'settings.contact.subjectPrefix': {\n label: getAdminLabel('field.contactSettings.subjectPrefix'),\n },\n\n // Cross-section reference selectors (decision C): dropdowns of sibling-section\n // ids. courses / testScores / recommendations point at education / careers.\n 'courses.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n 'testScores.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n 'recommendations.relatedCareerId': {\n render: referenceSelect({ section: 'careers', captionField: 'organization' }),\n },\n 'recommendations.relatedEducationId': {\n render: referenceSelect({ section: 'education', captionField: 'institution' }),\n },\n\n // Languages — disambiguate from the profile's \"Display name\".\n 'languages.displayName': { label: 'Language name' },\n\n // Metadata — auto-managed, never hand-edited.\n 'meta.createdAt': { hidden: true },\n 'meta.updatedAt': { hidden: true },\n 'meta.generator': { hidden: true },\n};\n","/**\n * Bespoke field renderers for the schema-driven form — the handful of fields a\n * generic schema-derived widget cannot capture (design §8). Each is plugged in\n * through the {@link FieldRegistry}'s `render` hook (decision A1), keyed by\n * schema path, so the engine stays generic and the data schema stays UI-free.\n *\n * These reproduce, one-for-one, the behavior the former hand-written section\n * forms had: the avatar's URL/upload/Gravatar trio, comma-separated lists, and\n * the inverted-and-sparse public-visibility matrix.\n */\n\nimport type { LocaleTag, PublicVisibility } from '@takuhon/core';\n\nimport { getAdminLabel, type AdminLabelKey } from '../admin-labels.js';\nimport { collectErrorsUnder, errorsAt } from '../errors.js';\nimport { firstLocalized } from '../localized.js';\nimport { CheckboxField } from '../primitives/CheckboxField.js';\nimport { GravatarField } from '../primitives/GravatarField.js';\nimport { ImageField } from '../primitives/ImageField.js';\nimport { LocaleTabs } from '../primitives/LocaleTabs.js';\nimport { SelectField, type SelectOption } from '../primitives/SelectField.js';\nimport { TextField } from '../primitives/TextField.js';\n\nimport styles from './custom-fields.module.css';\nimport type { CustomFieldContext } from './field-registry.js';\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' ? (value as Record<string, unknown>) : {};\n}\n\nfunction asLocalized(value: unknown): Record<LocaleTag, string> | undefined {\n return value && typeof value === 'object' ? (value as Record<LocaleTag, string>) : undefined;\n}\n\nfunction isEmptyRecord(record: Record<LocaleTag, string> | undefined): boolean {\n return !record || Object.keys(record).length === 0;\n}\n\nfunction asString(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction idOf(item: unknown): string {\n const id = asRecord(item).id;\n return typeof id === 'string' ? id : '';\n}\n\n/**\n * Avatar: a URL input (with optional file upload), a \"Use Gravatar\" control, and\n * localized alt text. The avatar object is created only once a URL or alt text\n * exists and dropped back to `undefined` when both are empty — matching the\n * former ProfileForm exactly.\n */\nexport function renderAvatar(ctx: CustomFieldContext): React.ReactNode {\n const avatar = asRecord(ctx.value);\n const url = typeof avatar.url === 'string' ? avatar.url : '';\n\n const updateAvatar = (patch: { url?: string; alt?: Record<LocaleTag, string> }): void => {\n const merged: Record<string, unknown> = { url: '', ...avatar, ...patch };\n const keep = merged.url !== '' || !isEmptyRecord(asLocalized(merged.alt));\n ctx.onChange(keep ? merged : undefined);\n };\n\n return (\n <>\n <ImageField\n label={getAdminLabel('field.avatarUrl')}\n value={url}\n onChange={(next) => {\n updateAvatar({ url: next });\n }}\n hint={getAdminLabel(ctx.uploadAsset ? 'hint.avatarUpload' : 'hint.avatarNoUpload')}\n errors={errorsAt(ctx.errors, `${ctx.pointer}/url`)}\n uploadAsset={ctx.uploadAsset}\n />\n <GravatarField\n onApply={(next) => {\n updateAvatar({ url: next });\n }}\n />\n <LocaleTabs\n label={getAdminLabel('field.avatarAlt')}\n value={asLocalized(avatar.alt)}\n locales={ctx.locales}\n onChange={(next) => {\n updateAvatar({ alt: next });\n }}\n pointer={`${ctx.pointer}/alt`}\n errors={ctx.errors}\n formatLocale={ctx.formatLocale}\n />\n </>\n );\n}\n\n/** Split a comma-separated input into trimmed, non-empty entries. */\nfunction parseCsv(input: string): string[] {\n return input\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry !== '');\n}\n\n/**\n * A comma-separated list editor for short string arrays (tags, locales) — a\n * single text input rather than a repeater, matching the former forms. `hint`\n * names the help text; `emptyToUndefined` drops the key when the list is empty\n * (optional arrays) versus keeping `[]` (required arrays).\n */\nexport function csvListRenderer(options: {\n hint: AdminLabelKey;\n emptyToUndefined: boolean;\n}): (ctx: CustomFieldContext) => React.ReactNode {\n return function renderCsvList(ctx: CustomFieldContext): React.ReactNode {\n const items = Array.isArray(ctx.value) ? (ctx.value as readonly unknown[]) : [];\n const text = items.filter((item): item is string => typeof item === 'string').join(', ');\n return (\n <TextField\n label={ctx.label}\n value={text}\n onChange={(input) => {\n const next = parseCsv(input);\n ctx.onChange(options.emptyToUndefined && next.length === 0 ? undefined : next);\n }}\n required={ctx.required}\n hint={getAdminLabel(options.hint)}\n errors={collectErrorsUnder(ctx.errors, ctx.pointer)}\n />\n );\n };\n}\n\n/**\n * Content sections the owner can hide via `settings.publicVisibility`. The order\n * mirrors the public page; `profile` is intentionally absent because the\n * identity is always public (spec §6.2).\n */\nconst VISIBILITY_SECTIONS: { key: keyof PublicVisibility; label: AdminLabelKey }[] = [\n { key: 'links', label: 'field.publicVisibility.links' },\n { key: 'careers', label: 'field.publicVisibility.careers' },\n { key: 'projects', label: 'field.publicVisibility.projects' },\n { key: 'skills', label: 'field.publicVisibility.skills' },\n { key: 'certifications', label: 'field.publicVisibility.certifications' },\n { key: 'memberships', label: 'field.publicVisibility.memberships' },\n { key: 'volunteering', label: 'field.publicVisibility.volunteering' },\n { key: 'honors', label: 'field.publicVisibility.honors' },\n { key: 'education', label: 'field.publicVisibility.education' },\n { key: 'publications', label: 'field.publicVisibility.publications' },\n { key: 'languages', label: 'field.publicVisibility.languages' },\n { key: 'courses', label: 'field.publicVisibility.courses' },\n { key: 'patents', label: 'field.publicVisibility.patents' },\n { key: 'testScores', label: 'field.publicVisibility.testScores' },\n { key: 'recommendations', label: 'field.publicVisibility.recommendations' },\n { key: 'contact', label: 'field.publicVisibility.contact' },\n];\n\n/**\n * The public-visibility matrix: a checkbox per content section, checked = public.\n * Stored sparsely — only hidden sections (`false`) are kept, and the whole block\n * is dropped once every section is visible again, so the default (all-visible)\n * stays absent. This inversion is why a generic boolean checkbox cannot stand in.\n */\nexport function renderVisibilityMatrix(ctx: CustomFieldContext): React.ReactNode {\n const visibility = asRecord(ctx.value) as Partial<Record<keyof PublicVisibility, boolean>>;\n\n const setVisibility = (key: keyof PublicVisibility, visible: boolean): void => {\n const next: Partial<Record<keyof PublicVisibility, boolean>> = { ...visibility };\n if (visible) {\n delete next[key];\n } else {\n next[key] = false;\n }\n ctx.onChange(Object.keys(next).length > 0 ? next : undefined);\n };\n\n return (\n <>\n <h3 className={styles.subheading}>{getAdminLabel('field.settings.publicVisibility')}</h3>\n <p className={styles.hint}>{getAdminLabel('hint.publicVisibility')}</p>\n {VISIBILITY_SECTIONS.map(({ key, label }) => (\n <CheckboxField\n key={key}\n label={getAdminLabel(label)}\n checked={visibility[key] ?? true}\n onChange={(visible) => {\n setVisibility(key, visible);\n }}\n />\n ))}\n </>\n );\n}\n\n/**\n * A cross-section reference selector (decision C): a dropdown of a sibling\n * section's items (e.g. `projects.relatedCareerId` → `careers[]`), each option\n * labelled by the item's caption and id. The stored value is the referenced\n * `id`. An optional reference offers \"(none)\"; a value with no matching item\n * (a dangling reference) is preserved as its own option rather than silently\n * dropped, so a stale id stays visible until the owner fixes it.\n */\nexport function referenceSelect(spec: {\n /** Sibling section to draw candidates from, e.g. `'careers'`. */\n section: string;\n /** Localized field used as the option caption, e.g. `'organization'`. */\n captionField: string;\n}): (ctx: CustomFieldContext) => React.ReactNode {\n return function renderReferenceSelect(ctx: CustomFieldContext): React.ReactNode {\n const value = asString(ctx.value);\n const items = (() => {\n const list = asRecord(ctx.document)[spec.section];\n return Array.isArray(list) ? (list as readonly unknown[]) : [];\n })();\n\n const candidates: SelectOption[] = items\n .map((item) => {\n const id = idOf(item);\n const caption = firstLocalized(asLocalized(asRecord(item)[spec.captionField]), ctx.locales);\n return { value: id, label: caption ? `${caption} (${id})` : id };\n })\n .filter((option) => option.value !== '');\n\n const danglingId = value !== '' && !candidates.some((option) => option.value === value);\n const options: SelectOption[] = [\n ...(ctx.required ? [] : [{ value: '', label: getAdminLabel('option.none') }]),\n ...candidates,\n // Keep an unrecognized current value selectable so it is never dropped.\n ...(danglingId ? [{ value, label: value }] : []),\n ];\n\n return (\n <SelectField\n label={ctx.label}\n value={value}\n options={options}\n onChange={(next) => {\n ctx.onChange(next || undefined);\n }}\n required={ctx.required}\n errors={errorsAt(ctx.errors, ctx.pointer)}\n />\n );\n };\n}\n","import { validate, type Takuhon } from '@takuhon/core';\nimport { useId, useState } from 'react';\n\nimport styles from './RawJsonEditor.module.css';\nimport { getAdminLabel } from './admin-labels.js';\n\nexport interface RawJsonEditorProps {\n value: Takuhon;\n /** Called with the parsed document whenever the text is valid JSON + schema. */\n onChange: (next: Takuhon) => void;\n}\n\nconst MAX_SHOWN_PROBLEMS = 50;\n\n/**\n * Advanced editing surface: the entire document as JSON text. Edits commit to\n * the draft only when the text parses and passes schema validation, so the\n * structured form view it shares state with never sees a malformed document.\n * This is also the only way to edit sections without a dedicated form (spec\n * §14.1 Phase 5 — JSON editor retained as the advanced mode).\n */\nexport function RawJsonEditor({ value, onChange }: RawJsonEditorProps): React.JSX.Element {\n const [text, setText] = useState(() => JSON.stringify(value, null, 2));\n const [problems, setProblems] = useState<readonly string[]>([]);\n const labelId = useId();\n const errorId = useId();\n\n const apply = (next: string): void => {\n setText(next);\n let parsed: unknown;\n try {\n parsed = JSON.parse(next);\n } catch (error) {\n setProblems([error instanceof Error ? error.message : 'Invalid JSON.']);\n return;\n }\n const result = validate(parsed);\n if (!result.ok) {\n setProblems(\n result.errors\n .slice(0, MAX_SHOWN_PROBLEMS)\n .map((error) => `${error.pointer || '/'}: ${error.message}`),\n );\n return;\n }\n setProblems([]);\n onChange(result.data);\n };\n\n const hasProblems = problems.length > 0;\n\n return (\n <section className={styles.wrapper} aria-labelledby={labelId}>\n <h2 className={styles.heading} id={labelId}>\n {getAdminLabel('mode.advanced')}\n </h2>\n <p className={styles.hint}>{getAdminLabel('advanced.hint')}</p>\n <textarea\n className={styles.textarea}\n value={text}\n spellCheck={false}\n aria-label={getAdminLabel('mode.advanced')}\n aria-invalid={hasProblems || undefined}\n aria-describedby={hasProblems ? errorId : undefined}\n onChange={(event) => {\n apply(event.target.value);\n }}\n />\n {hasProblems ? (\n <div className={styles.problems} id={errorId} role=\"alert\">\n <p className={styles.problemsTitle}>{getAdminLabel('advanced.invalid')}</p>\n <ul>\n {problems.map((problem, i) => (\n <li key={i}>{problem}</li>\n ))}\n </ul>\n </div>\n ) : null}\n </section>\n );\n}\n","import { schema, validate, type LocaleTag, type Takuhon } from '@takuhon/core';\nimport { useEffect, useRef, useState } from 'react';\n\nimport styles from './AdminEditor.module.css';\nimport { RawJsonEditor } from './RawJsonEditor.js';\nimport { getAdminLabel } from './admin-labels.js';\nimport {\n indexErrors,\n indexValidationErrors,\n NO_FIELD_ERRORS,\n type FieldErrorIndex,\n type FieldErrorLike,\n} from './errors.js';\nimport { type UploadAsset } from './primitives/ImageField.js';\nimport { SchemaForm } from './schema-form/SchemaForm.js';\nimport { sectionFieldKind, type SchemaNode } from './schema-form/field-classification.js';\nimport { ADMIN_SECTIONS, SECTION_REGISTRY } from './schema-form/section-registry.js';\n\n/** Result of a save attempt, reported by the host's transport layer. */\nexport type AdminSaveOutcome =\n | { status: 'saved'; version?: string }\n | { status: 'conflict' }\n | { status: 'invalid'; errors: readonly FieldErrorLike[] }\n | { status: 'error'; message?: string };\n\nexport interface AdminEditorProps {\n /** Document to edit, typically loaded from `GET /api/admin/export`. */\n initialDocument: Takuhon;\n /** Persist the document. The editor validates client-side first. */\n onSave: (document: Takuhon) => Promise<AdminSaveOutcome>;\n /** Re-fetch the stored document, replacing the working draft. */\n onReload?: () => Promise<Takuhon>;\n /** Download / hand off the current draft (Export button). */\n onExport?: (document: Takuhon) => void;\n /**\n * Provide a document to load (Import button). Returns raw parsed JSON, which\n * the editor validates; `undefined` cancels. Validation lives here so an\n * invalid file cannot break the draft invariant.\n */\n onImport?: () => Promise<unknown>;\n formatLocale?: (locale: LocaleTag) => string;\n /**\n * Upload an avatar image file (host-supplied; carries the admin token). When\n * provided, the profile form's avatar field offers a file picker; otherwise\n * the avatar stays URL-only.\n */\n uploadAsset?: UploadAsset;\n}\n\ntype Mode = 'form' | 'advanced';\ntype Tone = 'info' | 'success' | 'error';\ninterface Status {\n tone: Tone;\n message: string;\n}\n\nconst schemaRoot = schema as unknown as SchemaNode;\n\nfunction setSection(doc: Takuhon, key: keyof Takuhon, value: unknown): Takuhon {\n return { ...doc, [key]: value };\n}\n\n/**\n * Top-level admin editor: holds the working draft, switches between the field\n * forms and the raw-JSON advanced mode, and runs client-side validation before\n * delegating persistence to the host via `onSave` (transport-agnostic). Server\n * (RFC 7807) and client (`validate`) errors map to the same fields.\n */\nexport function AdminEditor({\n initialDocument,\n onSave,\n onReload,\n onExport,\n onImport,\n formatLocale,\n uploadAsset,\n}: AdminEditorProps): React.JSX.Element {\n const [draft, setDraft] = useState<Takuhon>(initialDocument);\n const [mode, setMode] = useState<Mode>('form');\n const [errors, setErrors] = useState<FieldErrorIndex>(NO_FIELD_ERRORS);\n const [status, setStatus] = useState<Status | null>(null);\n const [busy, setBusy] = useState(false);\n // Bumped whenever the document is replaced wholesale (reload / import) to\n // remount the raw-JSON editor so its text re-seeds from the new draft.\n const [loadGen, setLoadGen] = useState(0);\n // Identifies the latest user intent. A save reads it after awaiting `onSave`\n // and discards its outcome if an edit (which bumps the counter) landed\n // meanwhile — preventing a stale \"Saved.\" or stale server errors.\n const intentRef = useRef(0);\n // When a save fails validation, move focus to the error summary so keyboard\n // and screen-reader users land on the list of problems (the GOV.UK error\n // summary pattern). Set just before the failing `setErrors`; consumed by the\n // effect once the summary has rendered.\n const summaryRef = useRef<HTMLHeadingElement>(null);\n const focusSummaryRef = useRef(false);\n\n const locales = draft.settings.availableLocales;\n\n useEffect(() => {\n if (focusSummaryRef.current && summaryRef.current) {\n summaryRef.current.focus();\n }\n focusSummaryRef.current = false;\n }, [errors]);\n\n // Any edit clears the previous validation snapshot so resolved errors do not\n // linger while the operator works through them, and invalidates any in-flight\n // save outcome.\n const updateDraft = (next: Takuhon): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(null);\n };\n\n const loadDocument = (next: Takuhon, message: Status | null): void => {\n intentRef.current += 1;\n setDraft(next);\n setErrors(NO_FIELD_ERRORS);\n setStatus(message);\n setLoadGen((generation) => generation + 1);\n };\n\n const handleSave = async (): Promise<void> => {\n const result = validate(draft);\n if (!result.ok) {\n focusSummaryRef.current = true;\n setErrors(indexValidationErrors(result.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n return;\n }\n setErrors(NO_FIELD_ERRORS);\n intentRef.current += 1;\n const intent = intentRef.current;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.saving') });\n try {\n const outcome = await onSave(result.data);\n if (intent !== intentRef.current) return; // an edit landed mid-save; ignore\n switch (outcome.status) {\n case 'saved':\n setStatus({ tone: 'success', message: getAdminLabel('status.saved') });\n break;\n case 'conflict':\n setStatus({ tone: 'error', message: getAdminLabel('status.conflict') });\n break;\n case 'invalid':\n focusSummaryRef.current = true;\n setErrors(indexErrors(outcome.errors));\n setStatus({ tone: 'error', message: getAdminLabel('status.invalid') });\n break;\n case 'error':\n setStatus({ tone: 'error', message: outcome.message ?? getAdminLabel('status.error') });\n break;\n }\n } catch {\n if (intent === intentRef.current) {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n } finally {\n setBusy(false);\n }\n };\n\n const handleReload = async (): Promise<void> => {\n if (!onReload) return;\n setBusy(true);\n setStatus({ tone: 'info', message: getAdminLabel('status.loading') });\n try {\n const next = await onReload();\n loadDocument(next, null);\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n } finally {\n setBusy(false);\n }\n };\n\n const handleImport = async (): Promise<void> => {\n if (!onImport) return;\n try {\n const raw = await onImport();\n if (raw === undefined) return;\n const result = validate(raw);\n if (!result.ok) {\n setStatus({ tone: 'error', message: getAdminLabel('status.importInvalid') });\n return;\n }\n loadDocument(result.data, {\n tone: 'info',\n message: getAdminLabel('status.imported'),\n });\n } catch {\n setStatus({ tone: 'error', message: getAdminLabel('status.error') });\n }\n };\n\n // Flattened error list for the summary. This is the safety net that surfaces\n // failures in sections without a dedicated form (e.g. meta, education): their\n // pointers would otherwise map to no visible field.\n const errorEntries = [...errors].flatMap(([pointer, messages]) =>\n messages.map((message) => ({ pointer, message })),\n );\n\n return (\n <div className={styles.editor}>\n <div className={styles.toolbar} role=\"toolbar\" aria-label={getAdminLabel('toolbar.label')}>\n <div className={styles.modes} role=\"group\" aria-label={getAdminLabel('mode.label')}>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'form' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'form'}\n onClick={() => {\n setMode('form');\n }}\n >\n {getAdminLabel('mode.form')}\n </button>\n <button\n type=\"button\"\n className={`${styles.modeButton} ${mode === 'advanced' ? styles.modeActive : ''}`}\n aria-pressed={mode === 'advanced'}\n onClick={() => {\n setMode('advanced');\n }}\n >\n {getAdminLabel('mode.advanced')}\n </button>\n </div>\n <div className={styles.actions}>\n <button\n type=\"button\"\n className={styles.primary}\n disabled={busy}\n onClick={() => {\n void handleSave();\n }}\n >\n {getAdminLabel('action.save')}\n </button>\n {onReload ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleReload();\n }}\n >\n {getAdminLabel('action.reload')}\n </button>\n ) : null}\n {onExport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n onClick={() => {\n onExport(draft);\n }}\n >\n {getAdminLabel('action.export')}\n </button>\n ) : null}\n {onImport ? (\n <button\n type=\"button\"\n className={styles.secondary}\n disabled={busy}\n onClick={() => {\n void handleImport();\n }}\n >\n {getAdminLabel('action.import')}\n </button>\n ) : null}\n </div>\n </div>\n\n <p className={styles.status} role=\"status\" aria-live=\"polite\" data-tone={status?.tone}>\n {status?.message ?? ''}\n </p>\n\n {errorEntries.length > 0 ? (\n <section className={styles.summary} aria-labelledby=\"admin-error-summary\">\n <h2\n className={styles.summaryHeading}\n id=\"admin-error-summary\"\n tabIndex={-1}\n ref={summaryRef}\n >\n {getAdminLabel('status.fixSummary')}\n </h2>\n <ul>\n {errorEntries.map((entry, i) => (\n <li key={i}>\n {entry.pointer === ''\n ? entry.message\n : `${entry.pointer.replace(/^\\//, '')}: ${entry.message}`}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n {mode === 'form' ? (\n <div className={styles.sections}>\n {ADMIN_SECTIONS.map(({ key, label }) => (\n <SchemaForm\n key={key}\n kind={sectionFieldKind(schemaRoot, key)}\n value={draft[key]}\n onChange={(next) => {\n updateDraft(setSection(draft, key, next));\n }}\n pointer={`/${key}`}\n label={getAdminLabel(label)}\n locales={locales}\n errors={errors}\n registry={SECTION_REGISTRY}\n formatLocale={formatLocale}\n uploadAsset={uploadAsset}\n document={draft}\n />\n ))}\n </div>\n ) : (\n <RawJsonEditor key={loadGen} value={draft} onChange={updateDraft} />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["styles","jsx","styles","jsx","styles","jsx","useId","styles","jsx","jsxs","useId","styles","jsx","jsxs","useId","useState","styles","controls","Fragment","jsx","jsxs","useState","useId","useRef","useState","styles","Fragment","jsx","jsxs","useId","useState","useRef","styles","jsx","jsxs","Fragment","jsx","jsxs","styles","Fragment","jsx","jsxs","asRecord","asLocalized","asString","idOf","useId","useState","styles","jsx","jsxs","useState","useId","styles","validate","useRef","useState","styles","jsx","jsxs","useState","useRef","validate","styles"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takuhon/ui",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "React mobile-first profile UI and minimal admin editor components for takuhon",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Takuhon contributors",
@@ -47,7 +47,7 @@
47
47
  "node": ">=22.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@takuhon/core": "1.0.0"
50
+ "@takuhon/core": "1.3.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "react": ">=19",