@ai-matrx/records-ui 0.113.4 → 0.113.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/first-page.cjs.map +1 -1
- package/dist/first-page.js.map +1 -1
- package/dist/index.cjs +14682 -14204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +13632 -13154
- package/dist/index.js.map +1 -1
- package/dist/object-actions.cjs +1 -0
- package/dist/object-actions.cjs.map +1 -1
- package/dist/object-actions.js +1 -0
- package/dist/object-actions.js.map +1 -1
- package/dist/pickers.cjs +6750 -2946
- package/dist/pickers.cjs.map +1 -1
- package/dist/pickers.d.cts +1 -1
- package/dist/pickers.d.ts +1 -1
- package/dist/pickers.js +6775 -2906
- package/dist/pickers.js.map +1 -1
- package/package.json +2 -2
package/dist/pickers.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pickers.ts","../src/TablePickers.tsx","../src/askOnce.ts","../src/editors.tsx","../src/dates.ts","../src/newerKindValues.tsx","../src/choiceLooks.ts","../src/parity.ts","../src/docs.ts","../src/names.ts","../src/RelationPicker.tsx","../src/PickOrAdd.tsx","../src/personChip.tsx","../src/Refusal.tsx","../src/plainWords.ts","../src/refusals.ts","../src/tellApart.ts","../src/gridAttachments.tsx","../src/host.tsx","../src/rights.ts","../src/labels.tsx","../src/signature.tsx","../src/FilePicker.tsx","../src/EntityReferenceControl.tsx","../src/PickOne.tsx","../src/PersonPicker.tsx","../src/FloatingRefusal.tsx","../src/presentation.ts","../src/formatControls.tsx","../src/formattedValue.tsx","../src/typedDateHelper.tsx","../src/personTime.ts","../src/choiceNudge.ts","../src/RecordsMount.tsx","../src/tablePicking.tsx","../src/DataBindingPicker.tsx","../src/PickedSummaries.tsx","../src/values.tsx","../src/embeddedLook.tsx","../src/enumLabels.ts","../src/WholeValue.tsx","../src/ReferenceChips.tsx","../src/kindValues.ts","../src/formulaNames.ts","../src/HeldChangeDecision.tsx"],"sourcesContent":["// src/pickers.ts — @ai-matrx/records-ui/pickers (W1.1)\n//\n// The pick-by-name primitives alone: table / column-value / record pickers, the \"From my data\"\n// binding picker and their read-back words. A host that only needs these (the workflow studio)\n// imports this subpath so the rest of the package's screens never enter its module graph.\nexport { TablePicker, TableScope, ColumnValuesEditor, RecordPicker, useTablesAnywhere } from \"./TablePickers\";\nexport type {\n TableAnywhere,\n TablesAnywhere,\n TablePickerProps,\n TableScopeProps,\n ColumnValuesEditorProps,\n RecordPickerProps,\n} from \"./TablePickers\";\nexport {\n DataBindingPicker,\n emptyDataBinding,\n isDataBinding,\n isCompleteDataBinding,\n defaultBindingTemplate,\n bindingPlaceholdersFor,\n DATA_BINDING_SHAPES,\n DATA_BINDING_MISSING,\n} from \"./DataBindingPicker\";\nexport type { DataBinding, DataBindingShape, DataBindingPickerProps } from \"./DataBindingPicker\";\nexport { TableNameText, ColumnValuesText, RecordNameText } from \"./PickedSummaries\";\nexport { HeldChangeDecision } from \"./HeldChangeDecision\";\nexport type { HeldChangeDecisionProps } from \"./HeldChangeDecision\";\n","\"use client\";\n\n// src/TablePickers.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// PICK BY NAME, NEVER BY ID. The one table picker, column/value row editor and record picker for\n// any host screen that STORES a table id, a record id or `{column key: value}` but must SHOW names:\n// the workflow studio's data steps first (`data.table.*`, `records.*` declare `table_picker`,\n// `column_values`, `record_picker`), every other builder after. Before this a workflow step asked\n// a person to paste a table uuid and hand-write `{\"status\": \"low\"}` as JSON.\n//\n// THE LIST is `custom.data_home_tables()` with no organization — every Table the person can open in\n// every organization she can reach (law: common-docs/policies/access-ladder.md),\n// one flat list, each row naming its organization. The chosen Table's columns and records are read\n// in the organization the Table lives in (`TableScope`), never the active one.\n//\n// WHAT IS STORED is unchanged: the table id, the record id, and `{field.key: stored value}` — the\n// exact keys `custom` record documents carry, so a saved workflow from before this file reads back\n// and runs unchanged. A key that is no longer a column is shown as itself, marked, never dropped.\n\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport type { Field, RecordsDataSource, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider, useFields, useRecords, useTable } from \"@ai-matrx/records/react\";\nimport { Button, CreatablePicker, type CreatableOption } from \"@ai-matrx/design-system\";\nimport { FieldControl } from \"./editors\";\nimport { fieldName, rowNameIn } from \"./names\";\nimport { personActor } from \"./RecordsMount\";\nimport { tablePickerEntries } from \"./tablePicking\";\nimport { RefusalLine } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** One row of `custom.data_home_tables()`. */\nexport interface TableAnywhere {\n table_id: Uuid;\n table_name: string;\n organization_id: Uuid;\n organization_name: string;\n kind: string | null;\n kept_by_the_app: boolean;\n /** When the table last changed (the door's own column) — what tells two same-named tables apart. */\n updated_at?: string | null;\n /** Who made it, when the door says. */\n created_by_name?: string | null;\n}\n\nexport interface TablesAnywhere {\n loading: boolean;\n /** The store's own sentence when the list was refused. */\n error: string | null;\n rows: TableAnywhere[];\n}\n\n// ONE READ PER DATA SOURCE (W1.1, 2026-10-02). Every TableScope / table name on a screen used to\n// read `data_home_tables` for itself — a Find Records result of 20 rows fired 20 identical reads,\n// and when they failed every row sat on \"…\". Reads in flight (and a just-read list, briefly) are\n// shared per data source; a failed read is never kept, so the next mount asks again.\nconst SHARED_FOR_MS = 5_000;\nconst sharedReads = new WeakMap<RecordsDataSource, { at: number; read: Promise<TablesAnywhere> }>();\n\nfunction readTablesAnywhere(dataSource: RecordsDataSource): Promise<TablesAnywhere> {\n const held = sharedReads.get(dataSource);\n if (held && Date.now() - held.at < SHARED_FOR_MS) return held.read;\n const read = Promise.resolve(dataSource.rpc(\"data_home_tables\", {}, { schema: \"custom\" })).then(\n ({ data, error }): TablesAnywhere => {\n if (error) {\n return {\n loading: false,\n error: refusalSentence({ message: String(error[\"message\"] ?? \"\") }) || \"Tables could not be read.\",\n rows: [],\n };\n }\n const rows = (Array.isArray(data) ? (data as TableAnywhere[]) : []).slice();\n rows.sort((a, b) => a.table_name.localeCompare(b.table_name));\n return { loading: false, error: null, rows };\n },\n (thrown: unknown): TablesAnywhere => ({\n loading: false,\n error: String((thrown as Error)?.message ?? thrown) || \"Tables could not be read.\",\n rows: [],\n }),\n );\n sharedReads.set(dataSource, { at: Date.now(), read });\n void read.then((result) => {\n if (result.error && sharedReads.get(dataSource)?.read === read) sharedReads.delete(dataSource);\n });\n return read;\n}\n\n/** Every Table the person can open, in every organization, sorted by name. */\nexport function useTablesAnywhere(dataSource: RecordsDataSource): TablesAnywhere {\n const [state, setState] = useState<TablesAnywhere>({ loading: true, error: null, rows: [] });\n useEffect(() => {\n let live = true;\n void readTablesAnywhere(dataSource).then((result) => {\n if (live) setState(result);\n });\n return () => {\n live = false;\n };\n }, [dataSource]);\n return state;\n}\n\nexport interface TablePickerProps {\n dataSource: RecordsDataSource;\n value: string | null;\n onChange: (tableId: string) => void;\n disabled?: boolean;\n /** Hand in an already-read list to skip a second read. */\n tables?: TablesAnywhere;\n}\n\n/** Pick a Table by its name; the id is what `onChange` hands back. */\nexport function TablePicker({ dataSource, value, onChange, disabled, tables }: TablePickerProps) {\n const own = useTablesAnywhere(dataSource);\n const list = tables ?? own;\n // Tables the app keeps for itself (choice lists, ledgers) stay out of the list unless chosen —\n // the one rule every table picker uses (`tablePicking.ts`).\n const options = tablePickerEntries(\n list.rows.map((t) => ({ ...t, id: t.table_id, name: t.table_name })),\n { keep: value },\n ).entries.map(({ table: t }) => t);\n // Two tables of one name in one organization are told apart by a second line: who made it and\n // when it last changed (the organization hint cannot tell them apart).\n const sameName = new Map<string, number>();\n for (const t of options) {\n const key = `${t.organization_id}|${t.table_name.trim().toLowerCase()}`;\n sameName.set(key, (sameName.get(key) ?? 0) + 1);\n }\n const pickerOptions: CreatableOption[] = options.map((t) => {\n const twin = (sameName.get(`${t.organization_id}|${t.table_name.trim().toLowerCase()}`) ?? 0) > 1;\n const row = t as typeof t & TableAnywhere;\n const second = [\n row.created_by_name ? `by ${row.created_by_name}` : null,\n row.updated_at ? `changed ${new Date(row.updated_at).toLocaleDateString()}` : null,\n ]\n .filter(Boolean)\n .join(\" · \");\n return {\n value: t.table_id,\n // The organization hint already tells two same-named tables apart across organizations.\n label: t.table_name,\n hint: t.organization_name,\n keywords: t.organization_name,\n ...(twin && second\n ? {\n render: (\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate\">{t.table_name}</span>\n <span className=\"truncate text-[11px] text-muted-foreground\">{second}</span>\n </span>\n ),\n }\n : {}),\n };\n });\n const missing = Boolean(value) && !list.loading && !list.error && !list.rows.some((t) => t.table_id === value);\n return (\n <div className=\"flex flex-col gap-1\">\n <CreatablePicker\n value={value || null}\n options={pickerOptions}\n onSelect={onChange}\n placeholder={missing ? \"Table not available\" : \"Choose a table\"}\n searchPlaceholder=\"Search tables\"\n noun=\"table\"\n loading={list.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Table\"\n />\n {list.error && <RefusalLine error={refusalOf(\"door\", list.error, \"Try again in a moment.\")} />}\n {missing && <p className=\"text-[11px] text-destructive\">This table is archived or not shared with you.</p>}\n </div>\n );\n}\n\nexport interface TableScopeProps {\n dataSource: RecordsDataSource;\n /** The signed-in person — the actor every read runs as. */\n userId: Uuid | null;\n tableId: string | null;\n children: ReactNode;\n /** Shown while the Table's organization is unknown, or when no Table is chosen. */\n fallback?: ReactNode;\n /** Shown when the list of Tables could not be read, or the Table is not one this person can\n * open — a scope that never resolves must say so, never wait forever. Defaults to `fallback`. */\n unavailable?: ReactNode;\n tables?: TablesAnywhere;\n}\n\n/** The record store, bound to the organization the chosen Table lives in. */\nexport function TableScope({ dataSource, userId, tableId, children, fallback = null, unavailable, tables }: TableScopeProps) {\n const own = useTablesAnywhere(dataSource);\n const list = tables ?? own;\n const organizationId = list.rows.find((t) => t.table_id === tableId)?.organization_id ?? null;\n if (tableId && !organizationId && !list.loading) return <>{unavailable ?? fallback}</>;\n if (!tableId || !organizationId) return <>{fallback}</>;\n return (\n <RecordsProvider config={{ dataSource, actor: personActor(userId), organizationId }}>\n {children}\n </RecordsProvider>\n );\n}\n\nexport interface ColumnValuesEditorProps {\n tableId: string;\n /** `{field key: stored value}` — what the step matches on or writes. */\n value: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n disabled?: boolean;\n /** The add button's label: \"Add a condition\" for a lookup, \"Add a value\" for a write. */\n addLabel: string;\n}\n\n/** Column / value rows for one Table. Must sit inside a `TableScope`. */\nexport function ColumnValuesEditor({ tableId, value, onChange, disabled, addLabel }: ColumnValuesEditorProps) {\n const fields = useFields(tableId);\n const all = useMemo(() => fields.data ?? [], [fields.data]);\n const byKey = useMemo(() => new Map(all.map((f) => [f.key, f])), [all]);\n const keys = Object.keys(value);\n // A row whose column is not chosen yet lives here until it is.\n const [adding, setAdding] = useState(false);\n\n const optionsFor = (current: string | null): CreatableOption[] =>\n all\n .filter((f) => f.key === current || !(f.key in value))\n .map((f) => ({ value: f.key, label: fieldName(f) }));\n\n const rename = (from: string, to: string) => {\n if (from === to) return;\n const next: Record<string, unknown> = {};\n for (const k of keys) next[k === from ? to : k] = k === from ? null : value[k];\n onChange(next);\n };\n const remove = (key: string) => {\n const { [key]: _gone, ...rest } = value;\n void _gone;\n onChange(rest);\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {fields.error && <RefusalLine error={fields.error} />}\n {keys.map((key) => {\n const field = byKey.get(key);\n return (\n <ColumnValueRow\n key={key}\n columnKey={key}\n field={field}\n loading={fields.loading}\n options={optionsFor(key)}\n value={value[key]}\n disabled={disabled}\n onColumn={(to) => rename(key, to)}\n onValue={(v) => onChange({ ...value, [key]: v })}\n onRemove={() => remove(key)}\n />\n );\n })}\n {adding && (\n <ColumnValueRow\n columnKey={null}\n field={undefined}\n loading={fields.loading}\n options={optionsFor(null)}\n value={null}\n disabled={disabled}\n onColumn={(to) => {\n setAdding(false);\n onChange({ ...value, [to]: null });\n }}\n onValue={() => undefined}\n onRemove={() => setAdding(false)}\n />\n )}\n {!disabled && !adding && keys.length < all.length && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"self-start\" onClick={() => setAdding(true)}>\n {addLabel}\n </Button>\n )}\n </div>\n );\n}\n\nfunction ColumnValueRow({\n columnKey,\n field,\n loading,\n options,\n value,\n disabled,\n onColumn,\n onValue,\n onRemove,\n}: {\n columnKey: string | null;\n field: Field | undefined;\n loading: boolean;\n options: CreatableOption[];\n value: unknown;\n disabled?: boolean | undefined;\n onColumn: (key: string) => void;\n onValue: (value: unknown) => void;\n onRemove: () => void;\n}) {\n // A saved key that is no longer a column keeps its own words and says so.\n const orphan = columnKey !== null && !loading && field === undefined;\n const shown = orphan ? [{ value: columnKey, label: columnKey, hint: \"Not a column\" }, ...options] : options;\n return (\n <div className=\"flex flex-col gap-1 rounded-md border border-border/60 p-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"min-w-0 flex-1\">\n <CreatablePicker\n value={columnKey}\n options={shown}\n onSelect={onColumn}\n placeholder=\"Choose a column\"\n searchPlaceholder=\"Search columns\"\n noun=\"column\"\n loading={loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Column\"\n />\n </div>\n {!disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" aria-label=\"Remove\" onClick={onRemove}>\n ✕\n </Button>\n )}\n </div>\n {field ? (\n <FieldControl field={field} value={value} onChange={onValue} disabled={disabled} />\n ) : orphan ? (\n <p className=\"text-[11px] text-muted-foreground\">{value === null || value === undefined ? \"—\" : String(value)}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface RecordPickerProps {\n tableId: string;\n value: string | null;\n onChange: (recordId: string) => void;\n disabled?: boolean;\n}\n\n/** Pick one record of a Table by its name. Must sit inside a `TableScope`. */\nexport function RecordPicker({ tableId, value, onChange, disabled }: RecordPickerProps) {\n const table = useTable(tableId);\n const records = useRecords(tableId, { pageSize: 200 });\n const rows = records.data?.rows ?? [];\n const options: CreatableOption[] = rows.map((row) => ({\n value: row.id,\n label: rowNameIn(table.data ?? null, row),\n }));\n const missing = Boolean(value) && !records.loading && !records.error && !rows.some((r) => r.id === value);\n return (\n <div className=\"flex flex-col gap-1\">\n <CreatablePicker\n value={value || null}\n options={options}\n onSelect={onChange}\n placeholder={missing ? \"Record not in this table\" : \"Choose a record\"}\n searchPlaceholder=\"Search records\"\n noun=\"record\"\n loading={records.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Record\"\n />\n {records.error && <RefusalLine error={records.error} />}\n </div>\n );\n}\n","// src/askOnce.ts — @ai-matrx/records-ui\n//\n// ONE QUESTION IN FLIGHT, ONE ANSWER FOR EVERY ASKER (lane TABLE-ACTIONS T5.3, PROOF-BOOK 1.18).\n//\n// A table open asked `custom.field_options` 13 times for 2 choice columns (the colours, the label\n// lookup, the paste planner and each re-run of their effects each asked on their own) and the\n// header menus' value counts twice per column. Every asker of the same question, on the same\n// client, within `freshMs` of the last answer, gets that one answer. A refusal is never kept: the\n// next asker asks again. A write that changes the answer calls `forgetAsked` with its prefix.\n\nimport { onTableStructureChanged, type RecordsClient } from \"@ai-matrx/records/core\";\n\ntype Answer = { ok: boolean };\n\ntype Held = Map<string, { at: number; epoch: number; answer: Promise<unknown> }>;\n\n/**\n * A Table's shape moved (a column or its choices were written by anybody on this page): everything\n * kept before that moment is stale, whatever its age. This is what lets the freshness window cover a\n * whole page open (lane DEDUPE-READS) instead of two seconds.\n */\nlet structureEpoch = 0;\nonTableStructureChanged(() => {\n structureEpoch += 1;\n});\n\nconst asked = new WeakMap<object, Held>();\n/** Per data source (the host's one supabase client survives a records client's rebuild) and per person. */\nconst byPerson = new WeakMap<object, Map<string, Held>>();\n\n/**\n * WHO IS ASKING, NOT WHICH OBJECT (lane SEED-ENTITY). The records client is REBUILT when the active\n * organization resolves (~1.5 s into a page); its reads re-fire from effects keyed on the client. The\n * questions kept here are semantic (a table, a column, a set of ids — never the organization), and the\n * answer is the same person's, so a rebuilt client over the SAME data source for the SAME person\n * shares them. A client with no data source in its config (a test double) keeps its own.\n */\nfunction heldFor(client: object): Held {\n const config = (client as { config?: { dataSource?: unknown; actor?: { actor?: string; user_id?: string | null; on_behalf_of?: string | null } } }).config;\n const source = config?.dataSource;\n if (source && typeof source === \"object\" && config?.actor) {\n const who = [config.actor.actor ?? \"-\", config.actor.user_id ?? \"-\", config.actor.on_behalf_of ?? \"-\"].join(\"|\");\n let persons = byPerson.get(source);\n if (!persons) {\n persons = new Map();\n byPerson.set(source, persons);\n }\n let held = persons.get(who);\n if (!held) {\n held = new Map();\n persons.set(who, held);\n }\n return held;\n }\n let held = asked.get(client);\n if (!held) {\n held = new Map();\n asked.set(client, held);\n }\n return held;\n}\n\nexport function askOnce<T extends Answer>(client: object, key: string, ask: () => Promise<T>, freshMs: number): Promise<T> {\n const held = heldFor(client);\n const now = Date.now();\n const kept = held.get(key);\n if (kept && kept.epoch === structureEpoch && now - kept.at <= freshMs) return kept.answer as Promise<T>;\n const answer = ask().then(\n (result) => {\n if (!result.ok) held.delete(key);\n return result;\n },\n (thrown: unknown) => {\n held.delete(key);\n throw thrown;\n },\n );\n held.set(key, { at: now, epoch: structureEpoch, answer });\n return answer;\n}\n\n/** Tests only: forget everything kept for every client (tests that share one data source across cases). */\nexport function forgetAllAsked(client: object): void {\n heldFor(client).clear();\n}\n\n/** Forget every kept answer whose key starts with `prefix` (a write changed what it answers). */\nexport function forgetAsked(client: object, prefix: string): void {\n const held = heldFor(client);\n for (const key of [...held.keys()]) if (key.startsWith(prefix)) held.delete(key);\n}\n\n/**\n * How long a column's choices are shared between askers: one page open, including the records\n * client being rebuilt when the active organization resolves (~2 s in) and every effect that re-runs\n * after it. 2 s ended just before the second fire (lane DEDUPE-READS: Spaces measured one at hydration\n * and one ~2 s later). A write on this page ends it at once (`structureEpoch`); another person's edit\n * shows within this window at most.\n */\nexport const FIELD_OPTIONS_FRESH_MS = 10_000;\n\n/** A column's choices, asked once for every asker in the same moment (`custom.field_options`). */\nexport function fieldOptionsOnce(\n client: Pick<RecordsClient, \"fieldOptions\">,\n fieldId: string,\n): ReturnType<RecordsClient[\"fieldOptions\"]> {\n return askOnce(client, `field_options:${fieldId}`, () => client.fieldOptions({ field_id: fieldId }), FIELD_OPTIONS_FRESH_MS);\n}\n\n/** How long a page of badges is shared between askers: the one page open, ended by any explicit refresh. */\nexport const ENRICH_CELLS_FRESH_MS = 5_000;\n","\"use client\";\n\n// src/editors.tsx — @ai-matrx/records-ui\n//\n// ONE EDITOR PER PARITY TYPE, and every one of them is a design-system\n// primitive. There is no bespoke input in this package and no per-feature\n// editor anywhere in the platform: a Field decides which of these is drawn,\n// from what the STORE stores about it (behaviour + modifiers + format + unit +\n// relation target), never from the value it happens to hold.\n//\n// FLD-9: a Formula is worked out by the system. Its editor is not a disabled\n// text box — it is the value with the sentence the store itself would say if\n// you tried to type into it.\n\nimport { fieldOptionsOnce, forgetAsked } from \"./askOnce\";\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport type { Field, RecordDocument, RecordsError, StoredRecord, Uuid } from \"@ai-matrx/records\";\nimport { allowsOtherValues, choiceValuesOf, coerceTypedAnswer, newerKindOf, decideTypedChoice, isTheChosen, optionKey, rankTypedMatches, readTypedTime, typedDateText, typedTimeText, type ChoiceNudge } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport {\n BasicInput,\n BasicTextarea,\n Badge,\n Button,\n Checkbox,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n} from \"@ai-matrx/design-system\";\nimport { carriesTimeOfDay } from \"./dates\";\nimport { newerKindControl } from \"./newerKindValues\";\nimport { editorKindFor } from \"./parity\";\nimport { fieldName, recordName } from \"./names\";\nimport { RelationPicker } from \"./RelationPicker\";\nimport { AttachmentControl, hostTakesFiles } from \"./gridAttachments\";\nimport { useRecordsUi } from \"./host\";\nimport { EntityReferenceControl } from \"./EntityReferenceControl\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { PersonPicker } from \"./PersonPicker\";\nimport { RefusalLine, RefusalNotice } from \"./Refusal\";\nimport { FloatingRefusal } from \"./FloatingRefusal\";\nimport { refusalFromThrown } from \"./refusals\";\nimport { formatForField } from \"./presentation\";\nimport { formatControl, typedText } from \"./formatControls\";\nimport { TypedDateHelper, type DateHelperKind } from \"./typedDateHelper\";\nimport { FormattedValue } from \"./formattedValue\";\nimport { useChoiceNudge } from \"./choiceNudge\";\nimport { SignaturePad, isSignatureField } from \"./signature\";\nimport { choiceChipLookOf } from \"./choiceLooks\";\n\n/**\n * STORE-RULE-GAPS: the choice editor below takes words that are not a choice on a column that\n * takes other values (`config.allow_other`) — kept as typed, or added to the choices, as the\n * person (or the `custom/choice_nudge` knob) decides. The field editor offers that setting's\n * tick ONLY because this is true — the screen never offers a setting it cannot honour.\n */\nexport const CHOICE_EDITOR_ADDS_WHAT_IS_TYPED = true;\n\n/* ═══ WORDS THAT ARE NOT A CHOICE YET (lane CHOICE-COLUMN-EDIT, 2026-09-27) ═════════════════════\n *\n * A software team's \"Account Type\" column offers Cursor · Claude · Codex and somebody types\n * \"Gemini\". The cell asks: Add “Gemini” to the choices for Account Type? — Add / Keep as typed /\n * Cancel, with Keep as typed only on a column that takes other values. What it asks, or does\n * without asking, is `decideTypedChoice` (@ai-matrx/records) reading the `custom/choice_nudge`\n * knob; this file only draws the answer.\n *\n * 🚨 THE LIE THIS CLOSES. The allow-other picker offered Add “<typed>” and sent the word; the\n * store kept it as an OTHER value and never added it to the choices. Now Add really adds: in a\n * grid cell the value becomes a `ChoiceAddition`, which the grid saves through\n * `recordUpdateAddingChoices` (the new choice and the cell, one transaction); elsewhere the\n * choice is added through `fieldUpdate`'s `options_add` and the cell then takes it.\n */\n\n/** A cell value that also ADDS words to its column's choices. Only a host that declares\n * `addsChoices` (the grid) is ever handed one. */\nexport interface ChoiceAddition {\n readonly addingChoices: true;\n /** What the cell holds — the words (beside the keys of existing choices, for several). */\n readonly value: unknown;\n /** The words added to the column's choices. */\n readonly add: readonly string[];\n}\n\nexport function isChoiceAddition(value: unknown): value is ChoiceAddition {\n return typeof value === \"object\" && value !== null && (value as { addingChoices?: unknown }).addingChoices === true;\n}\n\nexport function choiceAddition(value: unknown, add: readonly string[]): ChoiceAddition {\n return { addingChoices: true, value, add: [...add] };\n}\n\n/** A value with any addition set aside. */\nexport function withoutAddition(value: unknown): { value: unknown; add: readonly string[] } {\n return isChoiceAddition(value) ? { value: value.value, add: value.add } : { value, add: [] };\n}\n\n/** The question a choice cell asks about words that are not one of its choices. */\nexport interface ChoiceAsk {\n /** The words that are not a choice. */\n readonly words: readonly string[];\n /** True only when the column takes other values. */\n readonly keepOffered: boolean;\n /** What the cell takes on Add. */\n readonly onAdd: ChoiceAddition;\n /** What the cell takes on Keep as typed. */\n readonly asTyped: unknown;\n}\n\n/** “Gemini” · “Gemini” and “Copilot” · “A”, “B” and “C”. */\nfunction quoted(words: readonly string[]): string {\n const q = words.map((w) => `“${w}”`);\n return q.length <= 1 ? (q[0] ?? \"\") : `${q.slice(0, -1).join(\", \")} and ${q[q.length - 1]}`;\n}\n\n/** Add “Gemini” to the choices for Account Type? */\nexport function choiceAskSentence(field: Field, words: readonly string[]): string {\n return `Add ${quoted(words)} to the choices for ${fieldName(field)}?`;\n}\n\n/** “Gemini” is not one of the choices for Account Type. */\nexport function notAChoiceSentence(field: Field, words: readonly string[]): string {\n return `${quoted(words)} ${words.length === 1 ? \"is\" : \"are\"} not one of the choices for ${fieldName(field)}.`;\n}\n\n/** The question's three doors, drawn once for the typed cell and the picker alike. */\nexport function ChoiceAskButtons({\n field,\n words,\n keepOffered,\n onAdd,\n onKeep,\n onCancel,\n busy,\n}: {\n field: Field;\n words: readonly string[];\n keepOffered: boolean;\n onAdd: () => void;\n onKeep: () => void;\n onCancel: () => void;\n busy?: boolean | undefined;\n}) {\n return (\n <span data-records-choice-ask=\"\" data-records-cell-note=\"\" role=\"group\" aria-label={choiceAskSentence(field, words)} className=\"flex flex-col gap-1\">\n <span className=\"text-[11px] leading-snug\">{choiceAskSentence(field, words)}</span>\n <span className=\"flex flex-wrap items-center gap-1\">\n <Button type=\"button\" size=\"sm\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onAdd}>\n Add\n </Button>\n {keepOffered ? (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onKeep}>\n Keep as typed\n </Button>\n ) : null}\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onCancel}>\n Cancel\n </Button>\n </span>\n </span>\n );\n}\n\n/** Kinds whose control is the record's own (a choice, a link, a person, a file, a worked-out value). */\nconst FORMAT_BLIND_KINDS = new Set([\"formula\", \"lookup\", \"rollup\", \"json\", \"checkbox\", \"select\", \"multi_select\", \"member\", \"entity_reference\", \"relation\", \"attachment\", \"datetime\"]);\n\nexport interface FieldEditorControlProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n /**\n * A GRID CELL'S PICKER OPENS AT ONCE (merged-grid review 2026-09-26, A2). One click on a selected\n * choice, multi-choice or person cell opens its list directly — no inline Save/Cancel form that\n * grows the row. Honoured by the choice and person pickers; every other control ignores it.\n */\n autoOpen?: boolean | undefined;\n /** The picker's list closed (a pick, Enter, Tab, a click away): the cell commits what is chosen. Escape is `onCancel`. */\n onClose?: (() => void) | undefined;\n /**\n * WHAT THE PERSON TYPED TO OPEN A GRID CELL'S PICKER (merged-grid review 2, A2 — Airtable): a\n * letter typed on a selected choice, multi-choice or person cell opens its list with that text\n * already in the search box. Honoured by the choice and person pickers.\n */\n initialSearch?: string | undefined;\n /** The control's own answer is final (a choice cell's Add / Keep as typed): commit it now. */\n onCommit?: (() => void) | undefined;\n /** The control's own Cancel: the cell goes back to what it held. */\n onCancel?: (() => void) | undefined;\n /**\n * The host saves a `ChoiceAddition` through `recordUpdateAddingChoices` (the grid). Without it\n * a choice control adds the words through `fieldUpdate`'s `options_add` and hands back words.\n */\n addsChoices?: boolean | undefined;\n /**\n * DRAWN AS A FORM QUESTION (lane VIEWS-AND-FIELDS W1-B item 3): a choice is answered from its\n * choices laid out — pills for a few, a searchable list for more (`ChoiceAnswer`) — never a\n * drop-down or a \"Choose\" button. Every other control ignores it.\n */\n asForm?: boolean | undefined;\n /** A FORM'S SINGLE CHOICE WAS PICKED (lane TYPEFORM-2): the runner may go on to the next question. */\n onChosen?: (() => void) | undefined;\n}\n\n/** The label row every editor shares: one line, the label, the unit, the required mark. */\nexport function FieldLabel({ field, htmlFor, children }: { field: Field; htmlFor: string; children?: ReactNode }) {\n return (\n <div className=\"flex items-baseline gap-1.5\">\n <Label htmlFor={htmlFor} className=\"text-xs font-medium\">\n {fieldName(field)}\n </Label>\n {field.required ? <span className=\"text-xs text-destructive\">required</span> : null}\n {/* A length of time reads as h:mm, so its stored unit (seconds) is not a word to show (P4). */}\n {field.unit && newerKindOf(field) !== \"duration\" ? <span className=\"text-xs text-muted-foreground\">{field.unit}</span> : null}\n {children}\n </div>\n );\n}\n\n\n/* ═══ A CELL OPENED BY TYPING (merged-grid cold review, 2026-09-26) ════════════════════════════════\n *\n * 🚨 THE DEFECT. A dispatcher selected a Visit date cell and typed `10/03/2026`; the store kept\n * **Jan 31, 0026**. The typed first character was DROPPED (a date was not a \"typed\" kind), the\n * editor opened on the stored value as the browser's segmented date control, and the rest of the\n * keystrokes landed in it one segment at a time — each half-typed segment a \"valid\" date. A\n * number cell had the same hazard: `-5` or `$50` dropped the first character and APPENDED the rest\n * to the value already in the box (100 → 10050). A choice cell handed the keystrokes to a closed\n * drop-down, whose type-ahead picked whatever option the SECOND letter matched.\n *\n * THE RULE (Google Sheets and Airtable): what a person types into a selected cell goes into a\n * plain TEXT box, whole; nothing is written until they commit; on commit the text is read by the\n * ONE typed-answer reader (`coerceTypedAnswer` — the same one a paste, a public form and an import\n * use), in the reader's locale; and anything it would have to guess is REFUSED with its sentence,\n * the box still holding what was typed. A kind whose value is not typed words (a linked record, a\n * person, a file, a document) and a tick box (one click or Space toggles it) are not opened by a\n * keystroke at all — Enter opens them.\n */\n\n/** A draft that is still the words a person typed, with the reader's verdict on them. */\nexport interface TypedDraft {\n readonly typedDraft: true;\n readonly text: string;\n /**\n * What the text reads as, why it is not a value, or — for a choice column — the question about\n * words that are not a choice yet. `null` while the column's choices (and the knob) load.\n */\n readonly judged: { value: unknown } | { refusal: string; why?: string; cancelOnly?: true } | { ask: ChoiceAsk } | null;\n /**\n * The words the cell OPENED with (Enter, a double-click, F2 — `draftForOpening`). Committing them\n * unchanged writes nothing: opening a cell and pressing Enter never rewrites what is stored.\n */\n readonly openedAs?: string | undefined;\n}\n\nexport function isTypedDraft(value: unknown): value is TypedDraft {\n return typeof value === \"object\" && value !== null && (value as { typedDraft?: unknown }).typedDraft === true;\n}\n\n/** Text kinds take the typed words as the value itself: a letter is a letter. */\nconst TYPED_AS_WORDS = new Set([\"text\", \"long_text\", \"phone\"]);\n/**\n * Kinds whose typed words are READ into a value on commit. A link and an email are read too\n * (review 2, A9): \"company.com\" is kept as https://company.com, and words that cannot be an email\n * say what one looks like — before anything reaches the store.\n */\nconst TYPED_AND_READ = new Set([\"number\", \"currency\", \"percent\", \"datetime\", \"select\", \"multi_select\", \"email\", \"url\"]);\n\n/**\n * What a keystroke on a selected cell does to THIS column: `\"words\"` — the text is the value;\n * `\"read\"` — the text is read on commit; `\"search\"` — the column's picker opens with the text as\n * its search (a choice, a multi-choice, a person: Airtable); `\"none\"` — typing does not open it.\n */\nexport function typingOpens(field: Field): \"words\" | \"read\" | \"search\" | \"none\" {\n const kind = String(editorKindFor(field));\n if (kind === \"formula\" || kind === \"lookup\" || kind === \"rollup\") return \"none\";\n if (kind === \"select\" || kind === \"multi_select\" || kind === \"member\") return \"search\";\n const format = formatForField(field);\n if (format && format.id === \"time\") return \"read\";\n if (format && format.id === \"rating\") return \"read\";\n if (TYPED_AS_WORDS.has(kind)) return \"words\";\n if (TYPED_AND_READ.has(kind)) return \"read\";\n return \"none\";\n}\n\n/**\n * The reader's verdict on typed text for this column (choices: when they are known; `nudge`: the\n * `custom/choice_nudge` knob, `null` while it is asked, absent meaning its default `ask`).\n */\n/** The few words a cell says when what was typed cannot be an email, a link or a phone number. */\nexport const SHORT_REFUSAL = {\n email: \"Enter a valid email\",\n url: \"Enter a valid link\",\n phone: \"Enter a valid phone number\",\n time: \"Enter a time, like 2:30 PM\",\n date: \"Enter a date\",\n number: \"Enter a number\",\n value: \"Not a valid value\",\n} as const;\n\nexport function judgeTyped(field: Field, text: string, choices?: StoredRecord[] | null, nudge?: ChoiceNudge | null): TypedDraft[\"judged\"] {\n const trimmed = text.trim();\n const kind = String(editorKindFor(field));\n const format = formatForField(field);\n if (trimmed === \"\") return { value: null };\n if (format && format.id === \"time\") {\n // THE ONE TIME READER (`@ai-matrx/records` `readTypedTime`): `1200PM`, `12pm`, `9:30a`, `0930`\n // are all read; a bare `9` (morning or evening?) is refused with the way to write it.\n const read = readTypedTime(trimmed);\n return read.ok ? { value: read.value } : { refusal: SHORT_REFUSAL.time, why: `${fieldName(field)} holds a time of day, and ${read.why}` };\n }\n if (kind === \"select\" || kind === \"multi_select\") {\n if (!choices || nudge === null) return null;\n const several = field.multi || kind === \"multi_select\";\n const words = several ? trimmed.split(/\\s*[,;\\n]\\s*/).filter(Boolean) : [trimmed];\n const allowOther = allowsOtherValues(field);\n // ONE DECISION PER WORD, from the one helper every surface uses.\n const parts: string[] = [];\n const add: string[] = [];\n const ask: string[] = [];\n const notChoices: string[] = [];\n let keepOffered = allowOther;\n for (const word of words) {\n const decided = decideTypedChoice({ words: word, options: choices, allowOther, nudge });\n if (decided.decision === \"empty\") continue;\n if (decided.decision === \"chosen\") parts.push(decided.key);\n else {\n parts.push(decided.words);\n if (decided.decision === \"add\") add.push(decided.words);\n else if (decided.decision === \"ask\") {\n ask.push(decided.words);\n keepOffered = keepOffered && decided.keepOffered;\n } else if (decided.decision === \"not_a_choice\") notChoices.push(decided.words);\n }\n }\n const valueOf = (list: string[]) => (several ? list : (list[0] ?? null));\n if (notChoices.length > 0) return { refusal: notAChoiceSentence(field, notChoices), cancelOnly: true };\n if (ask.length > 0) {\n return {\n ask: { words: ask, keepOffered, onAdd: choiceAddition(valueOf(parts), [...add, ...ask]), asTyped: valueOf(parts) },\n };\n }\n if (add.length > 0) return { value: choiceAddition(valueOf(parts), add) };\n return { value: valueOf(parts) };\n }\n if (format && (format.id === \"rating\")) {\n const n = Number(trimmed);\n const max = format.options?.ratingMax ?? 5;\n return Number.isInteger(n) && n >= 0 && n <= max\n ? { value: n === 0 ? null : n }\n : { refusal: `Enter 1 to ${max}`, why: `${fieldName(field)} is a rating from 1 to ${max}.` };\n }\n // A PHONE NUMBER IS READ TOO (lane CELL-EDITORS, night walk 2026-10-06): any words used to be saved.\n // Digits with the usual marks (+, spaces, dashes, dots, brackets, an extension) and 7 to 15 digits.\n if (kind === \"phone\" || (format && format.id === \"phone\")) {\n const digits = trimmed.replace(/\\D/g, \"\");\n const usual = /^\\+?[\\d\\s().-]+(\\s*(x|ext\\.?)\\s*\\d+)?$/i.test(trimmed);\n return usual && digits.length >= 7 && digits.length <= 20 ? { value: trimmed } : { refusal: SHORT_REFUSAL.phone };\n }\n const showsAsPercent = Boolean(format && (format.id === \"percent\" || format.id === \"progress\"));\n const read = coerceTypedAnswer(field as never, text, { label: fieldName(field), showsAsPercent });\n // A CELL HAS NO ROOM FOR A PARAGRAPH (interface-text rules): an email or a link that cannot be one is\n // said in a few words, never echoing what was typed — the box beside it already shows that.\n // EVERY TYPED REFUSAL IS A SHORT LABEL (REVIEW-FIX 9, interface-text): \"Enter a date\", never the\n // reader's paragraph; the full reason rides the note's tooltip (`why`).\n if (\"refusal\" in read) {\n if (kind === \"email\" || kind === \"url\") return { refusal: SHORT_REFUSAL[kind] };\n const short =\n kind === \"datetime\" ? SHORT_REFUSAL.date : kind === \"number\" || kind === \"currency\" || kind === \"percent\" || showsAsPercent ? SHORT_REFUSAL.number : read.refusal.length <= 32 ? read.refusal : SHORT_REFUSAL.value;\n return short === read.refusal ? { refusal: short } : { refusal: short, why: read.refusal };\n }\n // A percent kept as a fraction is typed as the percent a person reads.\n if (typeof read.value === \"number\" && format && (format.id === \"percent\" || format.id === \"progress\") && format.options?.percentScale === \"fraction\") {\n return { value: Math.round((read.value / 100) * 1e9) / 1e9 };\n }\n return { value: read.value };\n}\n\n/**\n * WHICH HELPER SITS BESIDE A TYPED BOX: a calendar for a date, a calendar and a list of times for a\n * moment, a list of times for a time of day — or none. `value` is the stored value, when there is one.\n */\nexport function dateHelperKind(field: Field, value?: unknown): DateHelperKind | null {\n const format = formatForField(field);\n if (format && format.id === \"time\") return \"time\";\n if (String(editorKindFor(field)) !== \"datetime\") return null;\n return String(field.config?.[\"kind\"] ?? \"\") === \"datetime\" || carriesTimeOfDay(field, value) ? \"datetime\" : \"date\";\n}\n\n/** The words a stored value opens as in its column's typed box — the words the reader reads back to it. */\nexport function openingText(field: Field, value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"\";\n const helper = dateHelperKind(field, value);\n if (helper === \"time\") {\n const read = readTypedTime(String(value));\n if (!read.ok) return String(value);\n const [h, m] = read.value.split(\":\").map(Number);\n return typedTimeText(h!, m!);\n }\n if (helper) return typedDateText(value, { withTime: helper === \"datetime\" });\n const format = formatForField(field);\n return format ? typedText(format, value) : String(value);\n}\n\n/** Kinds whose Enter / double-click / F2 editor is the typed box too — never the browser's own control. */\nconst OPENS_AS_TYPED_TEXT = new Set([\"datetime\", \"number\", \"currency\", \"percent\"]);\n\n/**\n * 🚨 THE DRAFT A CELL OPENS WITH BY ENTER, A DOUBLE-CLICK OR F2 (grids review 3, 2026-09-30, a\n * BLOCKER). A date, a time or a date-and-time column opened the browser's own picker, which lost a\n * typed time and saved \"now\"; a money column's own box dropped a typed percent sign. Every way into\n * these columns is now the SAME typed box a keystroke opens, holding the stored value's words and\n * read once on commit. `undefined` for every other column (it keeps its own control).\n */\nexport function draftForOpening(field: Field, current: unknown): TypedDraft | undefined {\n const format = formatForField(field);\n if (format && format.id === \"rating\") return undefined;\n const opens = (format && format.id === \"time\") || OPENS_AS_TYPED_TEXT.has(String(editorKindFor(field)));\n if (!opens) return undefined;\n const text = openingText(field, current);\n return { typedDraft: true, text, judged: judgeTyped(field, text), openedAs: text };\n}\n\n/**\n * THE DRAFT A KEYSTROKE OPENS A CELL WITH — or `undefined` when typing does not open this column.\n * A text column takes the typed words as its value; every other typed column holds a TypedDraft.\n */\nexport function draftFromTyping(field: Field, seed: string): string | TypedDraft | undefined {\n const opens = typingOpens(field);\n if (opens === \"none\") return undefined;\n if (opens === \"words\") return seed;\n return { typedDraft: true, text: seed, judged: judgeTyped(field, seed) };\n}\n\n/**\n * \"Reads as …\" EARNS ITS PLACE (interface-text): it floats over the cell only when it tells the person\n * something the box does not. Typed \"9/5/2026\" it would repeat the box, so it is not drawn; typed\n * \"Sep 5 2026\" or \"12.5\" for a money column, what it reads as is news. `always`: an addition to a\n * list of choices is always said. Keyed by the typed words, so it is measured again as they change.\n */\nfunction ReadsAsNote({ typed, always, children }: { typed: string; always: boolean; children: ReactNode }) {\n const note = useRef<HTMLSpanElement | null>(null);\n const [repeats, setRepeats] = useState(false);\n useLayoutEffect(() => {\n if (always) return;\n const words = (t: string | null | undefined) => (t ?? \"\").replace(/^Reads as/, \"\").replace(/\\s+/g, \"\").toLowerCase();\n setRepeats(words(note.current?.textContent) === words(typed));\n }, [typed, always]);\n if (repeats) return null;\n return (\n <span ref={note} data-records-typed-reads-as=\"\" data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">\n {children}\n </span>\n );\n}\n\n/** The box a typed draft is edited in: the words, and what they read as — or why they are not a value. */\nfunction TypedTextControl({ field, value, onChange, disabled, id, onCommit, onCancel }: FieldEditorControlProps & { value: TypedDraft }) {\n const client = useOptionalRecordsClient();\n const kind = String(editorKindFor(field));\n const needsChoices = kind === \"select\" || kind === \"multi_select\";\n const nudge = useChoiceNudge(needsChoices);\n const [choices, setChoices] = useState<StoredRecord[] | null>(null);\n useEffect(() => {\n if (!needsChoices || !client) return;\n let cancelled = false;\n void fieldOptionsOnce(client, field.id).then((result) => {\n if (!cancelled) setChoices(result.ok ? inTheStoresOrder(result.data ?? []) : []);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, needsChoices]);\n // The verdict on what is ALREADY in the box once the choices (and the knob) arrive.\n useEffect(() => {\n if (choices && nudge && value.judged === null) onChange({ ...value, judged: judgeTyped(field, value.text, choices, nudge) });\n }, [choices, nudge, value, field, onChange]);\n const judged = value.judged;\n const format = formatForField(field);\n const helper = dateHelperKind(field);\n const retype = (text: string) =>\n onChange({\n typedDraft: true,\n text,\n judged: judgeTyped(field, text, needsChoices ? choices : undefined, needsChoices ? nudge : undefined),\n ...(value.openedAs !== undefined ? { openedAs: value.openedAs } : {}),\n });\n const box = (\n <BasicInput\n id={id}\n value={value.text}\n disabled={disabled}\n autoComplete=\"off\"\n aria-label={fieldName(field)}\n aria-invalid={judged !== null && \"refusal\" in judged ? true : undefined}\n onChange={(e) => retype(e.target.value)}\n />\n );\n return (\n <span className=\"flex flex-col gap-0.5\">\n {helper && !disabled ? (\n <span className=\"flex min-w-0 items-center gap-0.5\">\n {box}\n <TypedDateHelper kind={helper} text={value.text} onText={retype} label={fieldName(field)} onPicked={onCommit} startOpen={value.openedAs !== undefined} />\n </span>\n ) : (\n box\n )}\n {judged === null ? (\n <span data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">Reading {fieldName(field)}'s choices…</span>\n ) : \"ask\" in judged ? (\n <ChoiceAskButtons\n field={field}\n words={judged.ask.words}\n keepOffered={judged.ask.keepOffered}\n onAdd={() => {\n onChange({ ...value, judged: { value: judged.ask.onAdd } });\n onCommit?.();\n }}\n onKeep={() => {\n onChange({ ...value, judged: { value: judged.ask.asTyped } });\n onCommit?.();\n }}\n onCancel={() => onCancel?.()}\n />\n ) : \"refusal\" in judged ? (\n <>\n <FloatingRefusal text={judged.refusal} why={\"why\" in judged ? judged.why : undefined} />\n {judged.cancelOnly && onCancel ? (\n <span data-records-cell-note=\"\" data-records-choice-ask=\"\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" onClick={() => onCancel()}>\n Cancel\n </Button>\n </span>\n ) : null}\n </>\n ) : judged.value === null || judged.value === undefined ? null : (\n <ReadsAsNote key={value.text} typed={value.text} always={isChoiceAddition(judged.value)}>\n {isChoiceAddition(judged.value) ? `Adds ${quoted(judged.value.add)} to the choices for ${fieldName(field)}. ` : null}\n Reads as{\" \"}\n {needsChoices ? (\n String(\n (Array.isArray(withoutAddition(judged.value).value) ? (withoutAddition(judged.value).value as unknown[]) : [withoutAddition(judged.value).value])\n .map((k) => {\n const option = choices?.find((o) => optionKey(o) === k);\n return option ? recordName(option.data as RecordDocument | undefined, null, String(k)) : String(k);\n })\n .join(\", \"),\n )\n ) : (\n (() => {\n const shown = format ?? (kind === \"datetime\" ? { id: carriesTimeOfDay(field, judged.value) ? \"datetime\" : \"date\" } : undefined);\n return shown ? <FormattedValue value={judged.value} format={shown} /> : String(judged.value);\n })()\n )}\n </ReadsAsNote>\n )}\n </span>\n );\n}\n\n/** A column that holds the person's own name (\"Name\", \"Full name\", \"Your name\"). */\nfunction isPersonsName(field: Field): boolean {\n const words = `${field.key} ${field.label ?? \"\"}`.toLowerCase();\n return /(^|[\\s_])(full[\\s_]?)?name(\\s|$)/.test(words) && !/(therapist|doctor|physician|company|business|pet|room)/.test(words);\n}\n\nexport function FieldControl({ field, value, onChange, disabled, id, autoOpen, onClose, onCommit, onCancel, addsChoices, initialSearch, asForm, onChosen }: FieldEditorControlProps) {\n const host = useRecordsUi();\n const kind = editorKindFor(field);\n const inputId = id ?? `field-${field.key}`;\n // A STRANGER'S OWN PAGE FILLS HER OWN DETAILS (lane HANDOVER, 2026-09-28). A public form or\n // booking page has no records client (nobody is signed in), and there the browser may offer the\n // person's own name, email and phone. In a signed-in grid or record form it never does: the\n // cell holds somebody else's email, and the browser's suggestions would be her own.\n const ownDetails = useOptionalRecordsClient() === null;\n\n // A CELL OPENED BY TYPING edits the typed words, whatever the column's own control is.\n if (isTypedDraft(value)) return <TypedTextControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} onCommit={onCommit} onCancel={onCancel} />;\n\n // A SIGNATURE IS DRAWN, never typed (lane 10 W1-A): the one pad, in every form, record panel\n // and grid editor that asks for this column (`signature.tsx`).\n if (isSignatureField(field)) return <SignaturePad id={inputId} value={value} onChange={onChange} disabled={disabled} />;\n\n // THE NEWER KINDS (lane 10 P4): a length of time typed as 45 min, an address in its parts, a\n // barcode typed or photographed; who made it and a count are shown, never typed.\n const newerControl = newerKindControl({ field, value, onChange, disabled, id: inputId });\n if (newerControl !== undefined) return newerControl;\n\n // THE COLUMN'S OWN FORMAT EDITS ITS VALUE (merge tranche 6e): stars for a rating, a percent\n // typed as a percent whatever scale it is kept in, money typed with its symbol and commas.\n // A format with no opinion about its input falls through to the kind's own control below.\n const format = formatForField(field);\n // A TIME OF DAY IS TYPED WORDS AND A HELPER, NEVER THE BROWSER'S TIME CONTROL (grids review 3).\n if (format && format.id === \"time\") return <TypedWordsControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n if (format && !FORMAT_BLIND_KINDS.has(String(kind))) {\n const own = formatControl({ format, value, onChange, disabled, id: inputId, label: fieldName(field), ownDetails });\n if (own) return own;\n }\n\n switch (kind) {\n case \"formula\":\n case \"lookup\":\n case \"rollup\":\n return (\n <div id={inputId} className=\"rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground\">\n {/* The store's own sentence for typing into a computed field. */}\n {value === null || value === undefined ? \"—\" : String(value)}\n <span className=\"ml-2 italic\">\n {fieldName(field)} is worked out by the system, so it cannot be typed in\n </span>\n </div>\n );\n case \"json\":\n return <JsonControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"long_text\":\n return (\n <BasicTextarea\n id={inputId}\n rows={3}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n case \"number\":\n case \"currency\":\n case \"percent\":\n return (\n <BasicInput\n id={inputId}\n type=\"number\"\n inputMode=\"decimal\"\n className=\"tabular-nums\"\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\n />\n );\n case \"datetime\":\n // A TYPED BOX AND A HELPER, NEVER THE BROWSER'S PICKER (grids review 3): the record form,\n // a public form and a bulk change read what is typed through the one date reader.\n return <TypedWordsControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"email\":\n case \"phone\":\n case \"url\":\n return (\n <BasicInput\n id={inputId}\n type={kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\"}\n // THE RIGHT KEYBOARD (lane TYPEFORM-2): @ on the email keyboard, the dial pad for a phone, / and .com for a link.\n inputMode={kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\"}\n {...(ownDetails ? { autoComplete: kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\" } : {})}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n case \"checkbox\":\n return <CheckboxControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"select\":\n case \"multi_select\":\n return <OptionControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} addsChoices={addsChoices} initialSearch={initialSearch} asForm={asForm} onChosen={onChosen} />;\n case \"member\":\n // A person field asks who is in the organization, never what is in a\n // Table — see PersonPicker's header for the screen that made this split.\n return <PersonPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} initialSearch={initialSearch} />;\n case \"entity_reference\":\n // SC-R: a note, a web site, an agent … — chips of what it names, never a text box.\n return <EntityReferenceControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"attachment\":\n // A FILE COMES FROM THE HOST'S FILE WINDOW OR AN UPLOAD (`gridAttachments.tsx`), never from a\n // list of the kernel File Table's rows. A host with neither port keeps the relation picker.\n if (hostTakesFiles(host)) {\n return <AttachmentControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} />;\n }\n return <RelationPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"relation\":\n return <RelationPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} onPicked={onCommit} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} />;\n default:\n if (typeof value === \"boolean\" || field.config?.[\"kind\"] === \"boolean\") {\n return (\n <Checkbox\n id={inputId}\n checked={value === true}\n disabled={disabled}\n onCheckedChange={(next) => onChange(next === true)}\n />\n );\n }\n return (\n <BasicInput\n id={inputId}\n {...(ownDetails && isPersonsName(field) ? { autoComplete: \"name\" } : {})}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n }\n}\n\n/**\n * A DATE, A TIME OR A MOMENT OUTSIDE A GRID CELL (the record form, a public form, a bulk change):\n * the same typed box and helper a cell opens, for a host that holds plain VALUES. The words are read\n * on every keystroke and the value is handed over the moment they read; words that do not read keep\n * their sentence under the box, the value stays what it was, and leaving the box puts the words back\n * to that value — so what the box shows is always what will be saved.\n */\nexport function TypedWordsControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const [text, setText] = useState(() => openingText(field, value));\n const [refusal, setRefusal] = useState<string | null>(null);\n const [why, setWhy] = useState<string | undefined>(undefined);\n const sent = useRef<unknown>(value);\n // A value that moves under the box (a reload, another control) is shown — unless it is what was just read.\n useEffect(() => {\n if (value === sent.current) return;\n sent.current = value;\n setText(openingText(field, value));\n setRefusal(null);\n }, [value, field]);\n const helper = dateHelperKind(field, value);\n const retype = (next: string) => {\n setText(next);\n const judged = judgeTyped(field, next);\n if (judged && \"value\" in judged) {\n setRefusal(null);\n sent.current = judged.value;\n onChange(judged.value);\n } else if (judged && \"refusal\" in judged) {\n setRefusal(judged.refusal);\n setWhy(\"why\" in judged ? judged.why : undefined);\n }\n };\n return (\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"flex min-w-0 items-center gap-0.5\">\n <BasicInput\n id={id}\n value={text}\n disabled={disabled}\n autoComplete=\"off\"\n aria-invalid={refusal ? true : undefined}\n placeholder={helper ? typedDatePlaceholder(helper) : undefined}\n onChange={(e) => retype(e.target.value)}\n onBlur={() => {\n if (!refusal) return;\n setText(openingText(field, sent.current));\n setRefusal(null);\n }}\n />\n {helper && !disabled ? <TypedDateHelper kind={helper} text={text} onText={retype} label={fieldName(field)} /> : null}\n </span>\n {refusal ? <FloatingRefusal text={refusal} why={why} /> : null}\n </span>\n );\n}\n\n/**\n * WHAT AN EMPTY DATE BOX SHOWS: the SHAPE to type, never a date (WALK3-FIX, 2026-10-07). It showed\n * \"10/03/2026 2:30 PM\" — a real-looking day — and on 10/07 a person read it as a stale default\n * prefilled into Cleanings' Appointment Date. The pattern follows the locale's own order.\n */\nexport function typedDatePlaceholder(helper: \"date\" | \"datetime\" | \"time\" | string): string {\n const time = \"h:mm AM\";\n if (helper === \"time\") return time;\n const pattern = typedDateText(\"2026-11-22\").replace(\"2026\", \"YYYY\").replace(\"11\", \"MM\").replace(\"22\", \"DD\");\n return helper === \"datetime\" ? `${pattern} ${time}` : pattern;\n}\n\n/**\n * A TICK BOX, WITH ITS THIRD STATE SAID OUT LOUD.\n *\n * LIMITS-FIX 2026-09-21. `checkbox` is the store's fourteenth parity type and it holds a\n * REAL boolean — but a record nobody has answered holds NO VALUE AT ALL, and that is a\n * different fact from `false`. An unticked box cannot show the difference, so this control\n * draws the box AND, while the answer is missing, the word \"not answered yet\" beside it\n * with the way to keep it that way. Ticking writes `true`, unticking writes `false`, and\n * \"Clear\" puts the record back to never having said — which no plain checkbox can do.\n */\nfunction CheckboxControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const unanswered = value === null || value === undefined;\n return (\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id={id}\n checked={value === true}\n disabled={disabled}\n aria-label={fieldName(field)}\n onCheckedChange={(next) => onChange(next === true)}\n />\n {unanswered ? (\n <span className=\"text-xs italic text-muted-foreground\">not answered yet</span>\n ) : (\n <>\n <span className=\"text-xs text-muted-foreground\">{value === true ? \"Yes\" : \"No\"}</span>\n {field.required ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-5 px-1 text-[10px]\"\n disabled={disabled}\n onClick={() => onChange(null)}\n >\n Clear\n </Button>\n )}\n </>\n )}\n </div>\n );\n}\n\n/**\n * A document-shaped value, edited as the text it is. It is parsed on every\n * keystroke and the PARSE FAILURE IS SHOWN — a box that silently handed the\n * store unparseable text and let it answer `22P02 invalid input syntax` is a\n * refusal the person could have been spared half a second earlier.\n */\nfunction JsonControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const initial = value === null || value === undefined ? \"\" : typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n const [text, setText] = useState(initial);\n const [broken, setBroken] = useState<RecordsError | null>(null);\n return (\n <div className=\"flex flex-col gap-1\">\n <BasicTextarea\n id={id}\n rows={4}\n className=\"font-mono text-[11px]\"\n value={text}\n disabled={disabled}\n onChange={(e) => {\n const next = e.target.value;\n setText(next);\n if (next.trim() === \"\") {\n setBroken(null);\n onChange(null);\n return;\n }\n try {\n onChange(JSON.parse(next));\n setBroken(null);\n } catch (thrown) {\n // The parser's own words (\"Unexpected token } in JSON at position 14\")\n // are an engineer's: they go out of sight, the person reads a sentence.\n setBroken(\n refusalFromThrown(\n thrown,\n `${fieldName(field)} is not readable as structured data yet.`,\n \"Fix the text so it reads as structured data, or discard it to put back what was there.\",\n \"invalid_argument\",\n ),\n );\n }\n }}\n />\n {broken ? (\n // The typed text is still in the box: the notice owns the two doors out. In a grid cell it\n // floats over the table (`data-records-cell-note`), so the row never grows.\n <span data-records-cell-note=\"\" className=\"block\">\n <RefusalNotice\n error={broken}\n onKeepEditing={() => (id ? document.getElementById(id)?.focus() : undefined)}\n onDiscard={() => {\n setText(initial);\n setBroken(null);\n }}\n />\n </span>\n ) : null}\n </div>\n );\n}\n\n/**\n * THE ORDER THE STORE KEEPS (STORE-RULE-GAPS). Every option carries the position it was\n * declared at in `metadata.option_position` — the list as a person wrote it, and a choice\n * added by typing goes LAST, where the store put it. `custom.field_options` answers in no\n * particular order, so this control orders by that position (a row with none after those\n * that have one, then by when it was made) instead of drawing whatever order came back.\n */\nexport function inTheStoresOrder(options: StoredRecord[]): StoredRecord[] {\n const position = (o: StoredRecord): number => {\n const raw = (o as { metadata?: Record<string, unknown> | null }).metadata?.[\"option_position\"];\n const n = typeof raw === \"number\" ? raw : typeof raw === \"string\" ? Number(raw) : Number.NaN;\n return Number.isFinite(n) ? n : Number.POSITIVE_INFINITY;\n };\n const made = (o: StoredRecord): string => String((o as { created_at?: unknown }).created_at ?? \"\");\n return [...options].sort((a, b) => position(a) - position(b) || made(a).localeCompare(made(b)));\n}\n\n/**\n * FLD-5 / FLD-6. A pick-list IS a Table and an option is a Record of it — that part is\n * unchanged. What a CELL holds is the option's own stable WORD (its key), not the\n * option record's uuid, so renaming a choice rewrites no row; the read doors hand\n * back the LABEL and name the key beside it in `_choices`. This control therefore\n * recognises all three ways of naming the same choice — `isTheChosen` — and WRITES\n * the key, which is the contract. The options are read through the store's own\n * `custom.field_options` door, which resolves the options Table from the Field's\n * config — this component never has to know which Table that is.\n */\nfunction OptionControl({ field, value, onChange, disabled, id, autoOpen, onClose, onCancel, addsChoices, initialSearch, asForm, onChosen }: FieldEditorControlProps) {\n // NOT `useRecordsClient`. A drop-down is the commonest question on a public\n // form, and this control asked the hook that THROWS for a client the public\n // arm of `FormRunner` deliberately never mounts — so a stranger opening a\n // form with one choice question got HTTP 500 (VERIFIER-10, F1).\n const client = useOptionalRecordsClient();\n const [options, setOptions] = useState<StoredRecord[] | null>(null);\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n /** Bumped when this control added a choice, so the list is read again. */\n const [reread, setReread] = useState(0);\n\n useEffect(() => {\n if (!client) return;\n let cancelled = false;\n void fieldOptionsOnce(client, field.id).then((result) => {\n if (cancelled) return;\n if (result.ok) setOptions(inTheStoresOrder(result.data ?? []));\n else setRefusal(result.error);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, reread]);\n\n // EVERY STATE CARRIES THE CELL'S OWN ID. A cell that identified itself only\n // when it happened to be a text box is a cell nobody can tell apart from the\n // developer window that used to open instead of it.\n // A PUBLIC PAGE CARRIES THE CHOICES IT ASKS (lane HANDOVER, 2026-09-28): the form and booking\n // doors hand each choice question its live choices' labels as `public_choices`, so a stranger\n // picks \"Follow-up\" instead of typing a word the owner then has to match up.\n const handed = publicChoicesOf(field);\n if (!client && handed.length > 0) {\n // A public page IS a form: its choices are laid out in their own colours (`ChoiceAnswer`).\n return <ChoiceAnswer field={field} choices={handed} value={value} onChange={onChange} disabled={disabled} id={id} onChosen={onChosen} />;\n }\n if (!client) {\n // ABSENT AND HONEST. The choices of a field live in the owner's own data,\n // and a page answered without an account may not read it — so the question\n // says what it is and takes the answer as text rather than drawing an empty\n // drop-down or taking the page down.\n return (\n <div className=\"flex flex-col gap-1\">\n <BasicInput\n id={id}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n {/* The Field's own name is printed above by `FieldLabel`; saying it\n again here is how the screen read \"Service typeService type is…\". */}\n <p className=\"text-xs text-muted-foreground\">\n This is normally picked from a list. A page answered without an account cannot read that\n list, so type your answer and whoever receives it will match it up.\n </p>\n </div>\n );\n }\n if (refusal)\n return (\n <div id={id}>\n <RefusalLine error={refusal} />\n </div>\n );\n if (!options) return <p id={id} className=\"text-xs text-muted-foreground\">Reading this field's choices…</p>;\n if (asForm && options.length > 0) {\n const titled = (option: StoredRecord) => recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n return (\n <ChoiceAnswer\n field={field}\n choices={options.map((option) => ({ key: optionKey(option), label: titled(option) }))}\n value={value}\n onChange={onChange}\n disabled={disabled}\n id={id}\n onChosen={onChosen}\n isChosen={(choice, v) => {\n const option = options.find((o) => optionKey(o) === choice.key);\n return option ? isTheChosen(option, v) : false;\n }}\n />\n );\n }\n // ONE PICKER FOR EVERY CHOICE COLUMN (lane CHOICE-TAILS, 2026-09-27). A column that takes other\n // values and one that takes only its own choices draw the same combobox: search the choices,\n // pick one, or type a word that is none of them and be asked (Add / Keep as typed only where\n // the column takes other values / Cancel), exactly as a grid cell asks. The record form used to\n // draw a closed drop-down for a closed column, so a person filling in a record had no way to\n // add the word they needed. Outside a grid cell (the record form, the form runner) there is no\n // `autoOpen`, so the list opens on a press; in a grid cell it opens at once and closing it commits.\n // A GRID CELL IS NO EXCEPTION (merged-grid review 2, A2): its list used to be a plain drop-down\n // with no search, so Enter opened a list a person could not type into. Every choice cell now\n // opens THIS picker — search, arrows, Enter picks, Escape closes.\n if (CHOICE_EDITOR_ADDS_WHAT_IS_TYPED) {\n return (\n <OpenChoicePicker\n field={field}\n options={options}\n value={value}\n onChange={onChange}\n disabled={disabled}\n id={id}\n autoOpen={autoOpen}\n onClose={onClose}\n onCancel={onCancel}\n initialSearch={initialSearch}\n addsChoices={addsChoices}\n allowOther={allowsOtherValues(field)}\n onChoicesChanged={() => {\n // The kept answer is stale now: the next read asks the store.\n if (client) forgetAsked(client, `field_options:${field.id}`);\n setReread((n) => n + 1);\n }}\n />\n );\n }\n if (options.length === 0) {\n // Two different facts, and a person acts on them differently: a choice\n // field whose Table is empty, and a choice field that names no Table at\n // all. One blank control for both is the silent failure.\n return (\n <p id={id} className=\"text-xs text-muted-foreground\">\n {field.options_table_id\n ? `${fieldName(field)} takes its choices from a Table that has no records yet — add the choices there and they appear here.`\n : `${fieldName(field)} does not name the Table its choices come from yet, so there is nothing to choose. A table admin sets it in the field editor.`}\n </p>\n );\n }\n\n const titleOf = (option: StoredRecord) =>\n recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n\n if (field.multi) {\n // WHAT IS PICKED, however the value says it. The document a read door hands this\n // control carries LABELS; the row holds KEYS; a screen written before this contract\n // sends IDS. `isTheChosen` knows all three, and what goes back is always the key.\n const chosen = options.filter((option) => choiceValuesOf(value).some((v) => isTheChosen(option, v)));\n const picked = new Set(chosen.map((option) => optionKey(option)));\n const toggles = (\n <div id={autoOpen ? undefined : id} className=\"flex flex-wrap gap-1\">\n {options.map((option) => (\n <Button\n key={option.id}\n type=\"button\"\n size=\"sm\"\n variant={picked.has(optionKey(option)) ? \"default\" : \"outline\"}\n disabled={disabled}\n onClick={() => {\n const next = new Set(picked);\n if (next.has(optionKey(option))) next.delete(optionKey(option));\n else next.add(optionKey(option));\n onChange(next.size === 0 ? null : [...next]);\n }}\n >\n {titleOf(option)}\n </Button>\n ))}\n </div>\n );\n if (!autoOpen) return toggles;\n // IN A GRID CELL: the list floats over the grid (portalled), so the row never grows; the cell\n // commits what is ticked when the list closes.\n return (\n <Popover\n defaultOpen\n onOpenChange={(open) => {\n if (!open) onClose?.();\n }}\n >\n <PopoverTrigger asChild>\n <Button id={id} type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 max-w-full truncate\">\n {chosen.length === 0 ? \"Choose\" : chosen.map(titleOf).join(\", \")}\n </Button>\n </PopoverTrigger>\n <PopoverContent sizing=\"content\" className=\"max-w-[20rem] p-2\" align=\"start\">\n {toggles}\n </PopoverContent>\n </Popover>\n );\n }\n\n // The SINGLE choice, the same way: what is selected is worked out from the option, not\n // from a string comparison against whatever spelling the document happened to use, and\n // what goes back is the key.\n const current = options.find((option) => isTheChosen(option, value));\n return (\n <Select\n value={current ? optionKey(current) : \"\"}\n disabled={disabled ?? false}\n onValueChange={(next) => onChange(next === \"\" ? null : next)}\n {...(autoOpen\n ? {\n // IN A GRID CELL the list opens at once and a pick is the commit (Airtable).\n defaultOpen: true,\n onOpenChange: (open: boolean) => {\n if (!open) onClose?.();\n },\n }\n : {})}\n >\n <SelectTrigger id={id} size=\"sm\">\n <SelectValue placeholder=\"Choose\" />\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.id} value={optionKey(option)}>\n {titleOf(option)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\n/**\n * A CHOICE COLUMN THAT TAKES OTHER VALUES (STORE-RULE-GAPS). The relation picker's shape —\n * a search box over the choices and a line at the foot for words that are not one of them.\n * What that line does is `decideTypedChoice` with the `custom/choice_nudge` knob: ask (Add /\n * Keep as typed / Cancel), add without asking, or keep as typed. Add REALLY adds (see\n * `ChoiceAddition` above); Keep as typed sends the words and the store keeps them as an other\n * value. A word that already names a choice (by key or label, any case) is that choice.\n */\nfunction OpenChoicePicker({\n field,\n options,\n value,\n onChange,\n disabled,\n id,\n addsChoices,\n autoOpen,\n onClose,\n onCancel,\n initialSearch,\n allowOther = true,\n onChoicesChanged,\n}: FieldEditorControlProps & { options: StoredRecord[]; allowOther?: boolean; onChoicesChanged: () => void }) {\n const client = useOptionalRecordsClient();\n const nudge = useChoiceNudge();\n // IN A GRID CELL the list is open from the start and closing it is the cell's commit.\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n const [search, setSearch] = useState(initialSearch ?? \"\");\n const [adding, setAdding] = useState(false);\n const [addRefused, setAddRefused] = useState<RecordsError | null>(null);\n const titleOf = (option: StoredRecord) =>\n recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n const held = withoutAddition(value);\n const current = choiceValuesOf(held.value);\n const pickedWords = current.map((v) => {\n const option = options.find((o) => isTheChosen(o, v));\n return option ? titleOf(option) : String(v);\n });\n // A CHOICE WEARS ITS OWN COLOUR HERE TOO (W1-B item 2): the picked chip and every option in the\n // list are the chip the grid cell draws (`choiceChipLookOf`), never the theme's accent.\n const chipOf = (option: StoredRecord | undefined, word: string) =>\n option ? choiceChipLookOf(field, optionKey(option), titleOf(option)) : choiceChipLookOf(field, word);\n const q = search.trim();\n // THE ONE RANKING (`@ai-matrx/records` `rankTypedMatches`, grids review 3): exact, starts with,\n // a word starts with, contains — `Cal` highlights Calibration, never Electrical.\n const visible = rankTypedMatches(options, q, titleOf);\n const decided = decideTypedChoice({ words: q, options, allowOther, nudge: nudge ?? \"ask\" });\n\n /** The cell takes `word`; `adding` says whether it is also added to the choices. */\n const choose = (word: string, addingIt = false) => {\n const pending = held.add.filter((w) => w.toLowerCase() !== word.toLowerCase());\n let next: unknown;\n let add: string[] = [...pending];\n if (field.multi) {\n const existing = current.map((v) => {\n const option = options.find((o) => isTheChosen(o, v));\n return option ? optionKey(option) : String(v);\n });\n const has = existing.some((v) => v.toLowerCase() === word.toLowerCase());\n const list = has ? existing.filter((v) => v.toLowerCase() !== word.toLowerCase()) : [...existing, word];\n if (addingIt && !has) add.push(word);\n add = add.filter((w) => list.some((v) => v.toLowerCase() === w.toLowerCase()));\n next = list.length === 0 ? null : list;\n } else {\n add = addingIt ? [word] : [];\n next = word;\n }\n onChange(add.length > 0 ? choiceAddition(next, add) : next);\n setSearch(\"\");\n // A SINGLE CHOICE IS DONE ON THE PICK — closed AFTER the value is handed over, because in a grid\n // cell closing is the commit and it must commit what was just picked.\n if (!field.multi) setOpen(false);\n };\n\n /** Add the typed words to the choices, and the cell takes them. */\n const addTyped = () => {\n setAddRefused(null);\n if (addsChoices || !client) {\n choose(q, Boolean(addsChoices));\n return;\n }\n // A HOST THAT SAVES WORDS ONLY (the record form): the choice is added now, through the\n // column's own door, and the cell then takes its words — which name a choice by then.\n setAdding(true);\n void client.fieldUpdate({ field_id: field.id, patch: { options_add: [q] } }).then((result) => {\n setAdding(false);\n if (!result.ok) {\n setAddRefused(result.error);\n return;\n }\n onChoicesChanged();\n choose(q);\n });\n };\n\n const offList = q !== \"\" && decided.decision !== \"chosen\" && decided.decision !== \"empty\";\n // A NEW WORD IS ONE \"CREATE\" ROW, NEVER A QUESTION (lane CELL-EDITORS, night walk 2026-10-06; Notion):\n // typing \"Webinar\" in Kind of work replaced the list with 'Add \"Webinar\" to the choices for Kind of\n // work?' and Add / Cancel. Now the list shows what matches and \"Create “Webinar”\" sits at its foot.\n // ONE FIXED SPOT, AND THE LIST FILTERED (REVIEW-FIX 7, 2026-10-06 — Notion): the Create row used to\n // jump to the top when nothing matched, and a no-match search listed every choice. Now it is always\n // the last row, under the matches only; with no match it is the only row, so one Enter creates it.\n // A column that takes no new choices says so instead.\n const foot = null;\n const add =\n offList && (decided.decision === \"ask\" || decided.decision === \"add\")\n ? { label: `Create “${q}”`, onAdd: addTyped, disabled: adding }\n : offList && decided.decision === \"keep_as_typed\"\n ? { label: `Use “${q}”`, onAdd: () => choose(q) }\n : null;\n const listed = visible;\n\n const pickedOptions = current.map((v) => options.find((o) => isTheChosen(o, v)));\n const cellChips = pickedWords.map((word, i) => {\n const chip = chipOf(pickedOptions[i], word);\n return (\n <Badge key={word} variant=\"outline\" className={cn(\"text-[11px]\", chip.className)} data-records-choice-chip=\"\">\n {word}\n </Badge>\n );\n });\n // WHAT IS PICKED, AT THE HEAD OF THE OPEN LIST, EACH WITH ITS × (Airtable, Notion, the old Sheet).\n const headChips = pickedWords.map((word, i) => {\n const option = pickedOptions[i];\n return {\n id: `${word}-${i}`,\n label: word,\n chip: chipOf(option, word).className,\n onRemove: () => {\n if (field.multi) choose(option ? optionKey(option) : String(current[i]));\n else onChange(null);\n },\n };\n });\n const anchored = autoOpen === true;\n\n return (\n <div id={id} className=\"flex flex-wrap items-center gap-1\">\n {anchored || disabled ? null : cellChips}\n {disabled ? (\n cellChips\n ) : (\n // THE ONE \"PICK OR ADD\" BUILDER (PickOrAdd.tsx) — the relation picker draws the same one.\n // In a grid cell it hangs from the cell's own chips; no button is drawn in the cell.\n <PickOrAdd\n anchored={anchored}\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n chips={headChips}\n multi={field.multi}\n triggerLabel={`Pick for ${fieldName(field)}`}\n triggerText={pickedWords.length === 0 ? \"Choose\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={(next) => {\n setSearch(next);\n setAddRefused(null);\n }}\n items={listed.map((option) => ({\n id: option.id,\n label: titleOf(option),\n chip: chipOf(option, titleOf(option)).className,\n picked: current.some((v) => isTheChosen(option, v)),\n }))}\n onPick={(optionId) => {\n const option = options.find((o) => o.id === optionId);\n if (option) choose(optionKey(option));\n }}\n empty={q === \"\" ? <p className=\"p-2 text-xs text-muted-foreground\">No choices yet — type one to add it.</p> : null}\n add={add}\n foot={foot}\n // ENTER ON A NEW WORD answers the question with its first answer — Add — exactly as Tab\n // then Enter does (grids review 3); a column that may not take it says so and Enter waits.\n footNote={\n addRefused ? (\n <RefusalLine error={addRefused} />\n ) : offList && decided.decision === \"not_a_choice\" ? (\n // never_add on a column that takes only its choices: said, never a silent nothing.\n <>\n <p data-records-typed-refusal=\"\" className=\"p-2 text-xs text-muted-foreground\">\n {notAChoiceSentence(field, [q])}\n </p>\n {autoOpen ? (\n <span data-records-choice-ask=\"\" className=\"px-2 pb-1\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n </span>\n ) : null}\n </>\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n\n/** The chip a picked record shows as — REC-2's \"a record is a chip\" in one place. */\nexport function RecordChip({\n title,\n onRemove,\n className,\n}: {\n title: string;\n onRemove?: (() => void) | undefined;\n className?: string | undefined;\n}) {\n return (\n // A chip carries a RECORD'S OWN TITLE, which nobody here chose the length of —\n // \"Marisol Okonkwo — 418 Calle Puerto Vallarta, Camarillo\" is an ordinary customer\n // name. So it caps at its container and ends in an ellipsis with the whole name in\n // its tooltip, rather than being cut mid-word by whatever box it landed in\n // (lane FIX-14, 2026-09-22).\n <Badge variant=\"secondary\" className={cn(\"max-w-full gap-1 text-[11px]\", className)} title={title}>\n <span className=\"min-w-0 truncate\">{title}</span>\n {onRemove ? (\n <button type=\"button\" onClick={onRemove} aria-label={`Remove ${title}`} className=\"shrink-0 opacity-60 hover:opacity-100\">\n ×\n </button>\n ) : null}\n </Badge>\n );\n}\n\nexport type { Uuid };\n\n/** The choices a public page was handed for this question (`public_choices`), or none. */\nexport function publicChoicesOf(field: Field): Array<{ key: string; label: string }> {\n const raw = (field as unknown as { public_choices?: unknown }).public_choices;\n if (!Array.isArray(raw)) return [];\n return raw.flatMap((c) => {\n const o = c as { key?: unknown; label?: unknown };\n return typeof o.key === \"string\" && typeof o.label === \"string\" ? [{ key: o.key, label: o.label }] : [];\n });\n}\n\n/** How many choices a form lays out before it adds a search box above them. */\nexport const FORM_SEARCH_AFTER = 8;\n\n/** The keys a person presses to pick a choice, Typeform's way: A for the first, B for the second. */\nconst CHOICE_LETTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n/**\n * A CHOICE ANSWERED ON A FORM (MAKE-HOME W5b — Typeform, Tally). Every choice is a full-width row in\n * the form's own colour (the theme's primary, which the form's look sets), with its letter: pressing\n * A picks the first, B the second, and Enter goes on. The verifier walk (2026-10-02) found the\n * choices drawn as pills sized to their words in every colour of the grid's palette — a stranger's\n * intake form read as a table's cells. Past eight choices a search box sits above the rows. A single\n * choice is a radio group; several are toggles. The answer is the choice's key.\n */\nexport function ChoiceAnswer({\n field,\n choices,\n value,\n onChange,\n disabled,\n id,\n isChosen,\n onChosen,\n}: {\n field: Field;\n /** A single choice was picked (not un-picked): the form may go on. */\n onChosen?: (() => void) | undefined;\n choices: ReadonlyArray<{ key: string; label: string }>;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n /** Whether `choice` is what `v` holds; defaults to its key or label, as written. */\n isChosen?: ((choice: { key: string; label: string }, v: unknown) => boolean) | undefined;\n}) {\n const [search, setSearch] = useState(\"\");\n const held = field.multi ? choiceValuesOf(value) : value === null || value === undefined || value === \"\" ? [] : [value];\n const on = (choice: { key: string; label: string }) =>\n held.some((v) => (isChosen ? isChosen(choice, v) : String(v) === choice.key || String(v) === choice.label));\n const press = (choice: { key: string; label: string }) => {\n if (!field.multi) {\n const picking = !on(choice);\n onChange(picking ? choice.key : null);\n if (picking) onChosen?.();\n return;\n }\n const keys = choices.filter((c) => (c.key === choice.key ? !on(c) : on(c))).map((c) => c.key);\n onChange(keys.length === 0 ? null : keys);\n };\n const lettered = choices.length <= CHOICE_LETTERS.length;\n // ROVING FOCUS (lane TYPEFORM-2): one Tab stop — the chosen choice, or the first — and the arrow\n // keys move between choices; on a single choice an arrow also picks, as a radio group does.\n const tabStop = choices.find((c) => on(c))?.key ?? choices[0]?.key;\n const option = (choice: { key: string; label: string }) => {\n const chosen = on(choice);\n const letter = lettered ? CHOICE_LETTERS[choices.indexOf(choice)] : null;\n return (\n <button\n key={choice.key}\n type=\"button\"\n role={field.multi ? \"checkbox\" : \"radio\"}\n aria-checked={chosen}\n aria-label={choice.label}\n disabled={disabled}\n tabIndex={field.multi || choice.key === tabStop ? 0 : -1}\n onClick={() => press(choice)}\n data-records-choice-answer={choice.key}\n className={cn(\n \"flex min-h-11 w-full items-center gap-3 rounded-md border px-3 py-2 text-left text-base font-medium text-foreground transition-colors sm:min-h-10 sm:text-sm\",\n chosen ? \"border-primary bg-primary/10\" : \"border-primary/30 bg-primary/[0.03] hover:bg-primary/10\",\n )}\n >\n {letter ? (\n <kbd\n aria-hidden=\"true\"\n className={cn(\n \"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border font-sans text-xs font-semibold\",\n chosen ? \"border-primary bg-primary text-primary-foreground\" : \"border-primary/40 text-primary\",\n )}\n >\n {letter}\n </kbd>\n ) : null}\n <span className=\"min-w-0 flex-1 break-words\">{choice.label}</span>\n {chosen ? (\n <span aria-hidden=\"true\" className=\"shrink-0 text-primary\">\n ✓\n </span>\n ) : null}\n </button>\n );\n };\n // THE LETTER KEYS: anywhere in the question but the search box, a letter picks its choice.\n const onKeyDown = (event: React.KeyboardEvent) => {\n if (disabled || event.metaKey || event.ctrlKey || event.altKey) return;\n if ((event.target as HTMLElement).tagName === \"INPUT\") return;\n const arrow = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 }[event.key];\n if (arrow) {\n const buttons = Array.from(\n (event.currentTarget as HTMLElement).querySelectorAll<HTMLButtonElement>(\"[data-records-choice-answer]\"),\n );\n const here = buttons.indexOf(event.target as HTMLButtonElement);\n if (buttons.length === 0) return;\n event.preventDefault();\n const next = buttons[(Math.max(here, 0) + arrow + buttons.length) % buttons.length]!;\n next.focus();\n if (!field.multi) {\n const choice = choices.find((c) => c.key === next.dataset[\"recordsChoiceAnswer\"]);\n if (choice && !on(choice)) onChange(choice.key);\n }\n return;\n }\n if (!lettered) return;\n const at = CHOICE_LETTERS.indexOf(event.key.toUpperCase());\n if (event.key.length !== 1 || at < 0 || at >= choices.length) return;\n event.preventDefault();\n press(choices[at]!);\n };\n const group = { role: field.multi ? \"group\" : \"radiogroup\", \"aria-label\": fieldName(field), onKeyDown } as const;\n if (choices.length <= FORM_SEARCH_AFTER) {\n return (\n <div id={id} className=\"flex w-full flex-col gap-2\" {...group}>\n {choices.map(option)}\n </div>\n );\n }\n const q = search.trim().toLowerCase();\n const shown = q === \"\" ? choices : choices.filter((c) => c.label.toLowerCase().includes(q));\n return (\n <div id={id} className=\"flex w-full flex-col gap-2\" onKeyDown={onKeyDown}>\n <BasicInput\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search\"\n aria-label={`Search — ${fieldName(field)}`}\n autoComplete=\"off\"\n className=\"h-11 text-base sm:h-9 sm:text-sm\"\n />\n <div className=\"flex max-h-80 w-full flex-col gap-2 overflow-y-auto\" role={group.role} aria-label={group[\"aria-label\"]}>\n {shown.map(option)}\n {shown.length === 0 ? <p className=\"text-xs text-muted-foreground\">No match</p> : null}\n </div>\n </div>\n );\n}\n","/**\n * 🚨 THE ONE DATE HELPER EVERY LAYOUT READS (lane UI-FIX-18, VERIFIER-18 H2 / M1).\n *\n * MEASURED 2026-09-24 on production, browser in America/Los_Angeles: Kitchen's start date,\n * stored `2026-04-01`, read **Apr 1** in the grid, **Mar 31** on the calendar, **3/31** in\n * the gallery, and Backyard Deck's May 1 read **4/30** in the record panel. The grid was right\n * because it formats through the design system's registry (`formatFieldValue`), which reads a\n * bare `YYYY-MM-DD` as a day on a calendar. Every other surface called `new Date(\"2026-04-01\")`\n * itself — which JavaScript parses as UTC MIDNIGHT — and then printed it in the viewer's zone,\n * so everybody west of Greenwich saw the day before.\n *\n * THE CLASS, NOT THE INSTANCE. No component in this package parses or prints a date on its\n * own any more; it asks this file, and this file asks the SAME registry the grid asks. The\n * calendar's day key is the one thing the registry does not answer, and it is answered here\n * by the same rule: a bare calendar date IS its own day (read the characters), an instant\n * (`…Z`, `…+hh:mm`) is placed on the viewer's own calendar.\n *\n * The store's own stamps — Created time and Last changed time (`fx.created_time`,\n * `fx.modified_time`) — are instants, and are printed like every other date-and-time cell\n * (VERIFIER-18 M1 found `2026-09-25T00:13:34.564Z` in the grid, the gallery and the panel).\n */\nimport { formatFieldValue, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { Field } from \"@ai-matrx/records\";\n\n/** A day on a calendar with no time and no zone — `2026-04-01`, or a zoneless local midnight. */\nconst BARE_CALENDAR_DATE = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ]00:00(?::00(?:\\.0+)?)?)?$/;\n\ntype SystemStamp = \"autonumber\" | \"created_time\" | \"modified_time\";\n\n/** The store's own stamp this Field is, when it is one (`config.system`). */\nexport function systemStampOf(field: Pick<Field, \"type\" | \"config\">): SystemStamp | null {\n if (field.type !== \"formula\") return null;\n const system = String((field.config ?? {})[\"system\"] ?? \"\");\n return system === \"autonumber\" || system === \"created_time\" || system === \"modified_time\" ? system : null;\n}\n\n/**\n * Does this value (or, with no value, this Field) carry a TIME OF DAY as well as a date?\n *\n * A DATE IS A DATE (chair ruling, 2026-09-24). The control and the text follow the STORED\n * VALUE's shape, never `config.kind` alone: a value with no time part — `1988-06-14`, a date\n * of birth on a `kind: \"datetime\"` Field — gets a date-only control and a date-only reading\n * everywhere (grid, form, panel, calendar). With no value yet, only a Field that says so\n * outright carries a time: the older `format: \"datetime\"`, or the store's own Created / Last\n * changed stamps (instants by construction).\n */\nexport function carriesTimeOfDay(field: Pick<Field, \"type\" | \"config\" | \"format\">, value?: unknown): boolean {\n if (value !== undefined && value !== null && value !== \"\") return hasTimePart(value);\n const stamp = systemStampOf(field);\n if (stamp === \"created_time\" || stamp === \"modified_time\") return true;\n return (field.format ?? \"\").toLowerCase() === \"datetime\";\n}\n\n/**\n * THE TIME OF DAY A MOMENT CARRIES, in the reader's clock (\"3:30 PM\") — the same words the grid's\n * date-and-time cell ends in — or null for a bare day. A calendar's month card and a timeline's bar\n * show it before the title (lane 10 P4, verifier V8 #7), as Google Calendar does.\n */\nexport function timeOfDayWords(value: unknown): string | null {\n if (!hasTimePart(value)) return null;\n const at = value instanceof Date ? value : new Date(value as string | number);\n return Number.isNaN(at.getTime()) ? null : at.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A value that names a moment in the day, not just the day. */\nexport function hasTimePart(value: unknown): boolean {\n if (value instanceof Date || typeof value === \"number\") return true;\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n if (BARE_CALENDAR_DATE.test(trimmed)) return false;\n return /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/.test(trimmed);\n}\n\n/** Is this Field a date column at all — a dated range, or the store's own time stamp? */\nexport function isDateField(field: Pick<Field, \"type\" | \"config\">): boolean {\n const stamp = systemStampOf(field);\n if (stamp === \"created_time\" || stamp === \"modified_time\") return true;\n if (field.type !== \"range\") return false;\n const kind = String((field.config ?? {})[\"kind\"] ?? \"\");\n return kind === \"date\" || kind === \"datetime\";\n}\n\n/**\n * The format a date-ish Field draws with, or `undefined` for a Field that is not one. With a\n * value, it is that value's own shape; without, the Field's (`carriesTimeOfDay`).\n * `presentation.formatForField` answers dates through this, so the grid and every card agree.\n */\nexport function dateFormatFor(\n field: Pick<Field, \"type\" | \"config\" | \"format\">,\n value?: unknown,\n): FieldFormatConfig | undefined {\n if (!isDateField(field)) return undefined;\n return carriesTimeOfDay(field, value) ? { id: \"datetime\" } : { id: \"date\" };\n}\n\n/**\n * THE TEXT OF ONE DATE VALUE, in the viewer's language — through the design system's\n * registry, exactly as the grid prints it, in the value's own shape. `null` when the value is\n * not a date at all, so the caller can fall back to its own reading (THE FALLBACK LAW).\n */\nexport function dateText(field: Pick<Field, \"type\" | \"config\" | \"format\">, value: unknown): string | null {\n const format = dateFormatFor(field, value) ?? (isDateLike(value) ? { id: hasTimePart(value) ? \"datetime\" : \"date\" } : undefined);\n if (!format) return null;\n const result = formatFieldValue(value, format);\n return result.ok && !result.empty ? result.text : null;\n}\n\nfunction isDateLike(value: unknown): boolean {\n return typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}/.test(value.trim());\n}\n\nfunction pad(n: number): string {\n return n < 10 ? `0${n}` : String(n);\n}\n\n/**\n * THE CALENDAR DAY a value falls on, as `YYYY-MM-DD` — the key a calendar files a card under.\n *\n * A bare calendar date is its own day. An instant is placed on the VIEWER's calendar: a visit\n * logged at 5:13 PM Pacific on 24 September is on the 24th for the person in Pacific time,\n * even though it is already the 25th in UTC.\n */\nexport function calendarDayOf(value: unknown): string | null {\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n const bare = BARE_CALENDAR_DATE.exec(trimmed);\n if (bare) return `${bare[1]}-${bare[2]}-${bare[3]}`;\n if (trimmed === \"\") return null;\n } else if (typeof value !== \"number\" && !(value instanceof Date)) {\n return null;\n }\n const at = value instanceof Date ? value : new Date(value as string | number);\n if (Number.isNaN(at.getTime())) return null;\n return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;\n}\n\n/** The heading of one calendar day — `Apr 1, 2026` — built on local midnight, never UTC. */\nexport function calendarDayLabel(day: string): string {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(day);\n if (!m) return day;\n const at = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n return at.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n}\n\n// ---------------------------------------------------------------------------------------------\n// DAY ARITHMETIC ON THE VIEWER'S OWN CALENDAR (lane VIEWS-AND-FIELDS, sublane TL, 2026-10-02).\n// A day key is `YYYY-MM-DD`, built and read at LOCAL midnight — never `new Date(\"YYYY-MM-DD\")`,\n// which is UTC midnight and lands on the day before for everybody west of Greenwich. The timeline\n// places and moves bars with these; a move is always a whole number of days.\n\n/** The day key of a moment, on the viewer's calendar. */\nexport function dayKeyOf(at: Date): string {\n return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;\n}\n\n/** A day key as local midnight. */\nexport function dayAt(day: string): Date {\n const [y, m, d] = day.split(\"-\").map(Number);\n return new Date(y!, (m ?? 1) - 1, d ?? 1);\n}\n\n/** The day `n` days after (or before, when negative) `day`. */\nexport function addDays(day: string, n: number): string {\n const at = dayAt(day);\n at.setDate(at.getDate() + n);\n return dayKeyOf(at);\n}\n\n/** Whole days from `from` to `to` (negative when `to` is earlier). DST-safe: rounds the hour away. */\nexport function daysBetween(from: string, to: string): number {\n return Math.round((dayAt(to).getTime() - dayAt(from).getTime()) / 86_400_000);\n}\n","\"use client\";\n\n// src/newerKindValues.tsx — @ai-matrx/records-ui\n//\n// HOW THE NINE NEWER KINDS ARE SHOWN AND EDITED (lane 10 VIEWS-AND-FIELDS, sublane P4; champions:\n// Airtable's and SmartSuite's field types). One component per job, reached from the ONE value\n// drawing (`values.tsx`: RecordValue / renderValue / scalarText) and the ONE control\n// (`editors.tsx`: FieldControl), so the grid, the gallery, the board, the calendar, the record\n// panel and every form draw a kind the same way:\n//\n// rating stars (the registry's `rating` format, its top star read from the max Rule)\n// duration h:mm, typed as 45 min, 1:30 or 1h 30m\n// created by an initial and a name; last changed by — the same\n// status the choice chip, with its group's mark (To do ○, In progress ◐, Done ●)\n// address one line, opened in maps; edited in its five parts\n// barcode the code in monospace; on a phone that can, a photo of it fills it in\n// rich text Markdown drawn as React elements — never raw HTML, never innerHTML\n// count a whole number\n//\n// The store judges every value (`custom._kind_value_ok`); what is here only draws and reads.\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { codeSpanText, findInlineCodeSpans } from \"@ai-matrx/content-ir/source\";\nimport {\n ADDRESS_PARTS,\n NOT_A_MEMBER_WORDS,\n STATUS_GROUP_WORDS,\n addressMapUrl,\n addressText,\n durationText,\n isAddressValue,\n isPersonStamp,\n newerKindOf,\n personStampText,\n readTypedDuration,\n safeLinkHref,\n statusGroupOf,\n type AddressPart,\n type AddressValue,\n type Field,\n type PersonStamp,\n type StatusGroup,\n} from \"@ai-matrx/records\";\nimport { BasicInput, cn } from \"@ai-matrx/design-system\";\n\nconst own = (event: { stopPropagation: () => void }) => event.stopPropagation();\n\n// ── READ ───────────────────────────────────────────────────────────────────────────────────\n\n/**\n * One value of a newer kind, drawn — or `undefined` when the field is not one of the kinds drawn\n * here (the caller's own drawing applies). Never called for an empty value.\n */\nexport function newerKindValue(field: Field, value: unknown, opts: { inCell?: boolean | undefined } = {}): ReactNode | undefined {\n switch (newerKindOf(field)) {\n case \"duration\": {\n const words = durationText(value);\n return words === null ? undefined : (\n <span className=\"tabular-nums\" data-records-duration=\"\">\n {words}\n </span>\n );\n }\n case \"created_by\":\n case \"modified_by\":\n return isPersonStamp(value) ? <PersonStampChip stamp={value} /> : undefined;\n case \"address\":\n return isAddressValue(value) || typeof value === \"string\" ? <AddressLink value={value} /> : undefined;\n case \"barcode\":\n return typeof value === \"string\" ? (\n <span className=\"inline-flex min-w-0 items-center gap-1 font-mono text-xs\" data-records-barcode=\"\" title={value}>\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n ▮▯▮\n </span>\n <span className=\"truncate\">{value}</span>\n </span>\n ) : undefined;\n case \"rich_text\":\n return typeof value === \"string\" ? <SafeMarkdown text={value} clipped={opts.inCell === true} /> : undefined;\n case \"count\":\n return typeof value === \"number\" ? <span className=\"tabular-nums\">{value.toLocaleString()}</span> : undefined;\n default:\n return undefined;\n }\n}\n\n/**\n * Who made or last changed a record: an initial and a name — or, for a write the platform made,\n * \"System\", and for an agent's, \"Agent for\" the person it wrote for (V8 #4).\n */\nexport function PersonStampChip({ stamp }: { stamp: PersonStamp }) {\n const words = personStampText(stamp) ?? NOT_A_MEMBER_WORDS;\n const tier = stamp.actor ?? \"user\";\n const name = tier === \"user\" ? stamp.name : null;\n const initial = tier === \"system\" ? \"⚙\" : tier === \"agent\" ? \"✦\" : name && name.trim() !== \"\" ? name.trim()[0]!.toUpperCase() : \"?\";\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\" data-records-person-stamp={tier}>\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-muted text-[10px] font-medium text-foreground\"\n >\n {initial}\n </span>\n <span className={cn(\"truncate\", tier === \"user\" && !name ? \"italic text-muted-foreground\" : \"\")}>{words}</span>\n </span>\n );\n}\n\nfunction AddressLink({ value }: { value: AddressValue | string }) {\n const words = addressText(value);\n const href = addressMapUrl(value);\n if (!words || !href) return <span className=\"text-muted-foreground\">—</span>;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex min-w-0 items-center gap-1 text-primary hover:underline\"\n title=\"Open in maps\"\n data-records-address=\"\"\n onClick={own}\n >\n <span aria-hidden=\"true\">⌖</span>\n <span className=\"truncate\">{words}</span>\n </a>\n );\n}\n\n/** The mark a status group wears beside its choice, Linear's way. */\nexport const STATUS_GROUP_MARK: Record<StatusGroup, string> = { todo: \"○\", in_progress: \"◐\", done: \"●\" };\n\n/**\n * The group mark for one status value, with the group's name for hover; null when not a status.\n * The read puts the choice's WORDS in the cell and its KEY under `_choices` (V8 #2: every chip read\n * \"○ To do\" because the words were looked up as a key) — so the key is read from `_choices` first.\n */\nexport function statusMarkOf(\n field: Field,\n value: unknown,\n document?: Record<string, unknown> | null,\n): { mark: string; group: StatusGroup; words: string } | null {\n if (newerKindOf(field) !== \"status\" || typeof value !== \"string\") return null;\n const chosen = (document?.[\"_choices\"] as Record<string, unknown> | undefined)?.[field.key];\n const key = chosen && typeof chosen === \"object\" && typeof (chosen as { key?: unknown }).key === \"string\" ? (chosen as { key: string }).key : value;\n const group = statusGroupOf(field, key);\n return { mark: STATUS_GROUP_MARK[group], group, words: STATUS_GROUP_WORDS[group] };\n}\n\n// ── RICH TEXT: A SAFE SUBSET OF MARKDOWN, AS REACT ELEMENTS ───────────────────────────────\n\n/**\n * Inline Markdown: **bold**, _italic_ / *italic*, `code`, [words](https://…). Everything else is text.\n * Code spans are found by THE rule (`findInlineCodeSpans`, @ai-matrx/content-ir/source) and drawn first;\n * the marks are read only in the text between them.\n */\nfunction inline(text: string, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let at = 0;\n let n = 0;\n for (const r of findInlineCodeSpans(text)) {\n if (r.start < at) continue;\n if (r.start > at) out.push(...marks(text.slice(at, r.start), `${key}-m${n++}`));\n out.push(<code key={`${key}-c${n++}`} className=\"rounded bg-muted px-1 font-mono text-[0.9em]\">{codeSpanText(text.slice(r.start, r.end))}</code>);\n at = r.end;\n }\n if (at < text.length) out.push(...marks(text.slice(at), `${key}-m${n++}`));\n return out;\n}\n\n/** The marks of inline text that holds no code span: bold, italic, links. */\nfunction marks(text: string, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n const re = /(\\*\\*[^*]+\\*\\*|__[^_]+__|\\[[^\\]]+\\]\\([^)\\s]+\\)|\\*[^*\\s][^*]*\\*|_[^_\\s][^_]*_)/g;\n let last = 0;\n let i = 0;\n for (const m of text.matchAll(re)) {\n const at = m.index ?? 0;\n if (at > last) out.push(text.slice(last, at));\n const tok = m[0];\n const k = `${key}-${i++}`;\n if (tok.startsWith(\"**\") || tok.startsWith(\"__\")) out.push(<strong key={k}>{tok.slice(2, -2)}</strong>);\n else if (tok.startsWith(\"[\")) {\n const link = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(tok);\n // Read as a browser would follow it — entities and escapes decoded (V8 #5) — and only a web\n // page, an email address or a phone number becomes a link.\n const href = safeLinkHref(link?.[2] ?? \"\");\n out.push(\n href ? (\n <a key={k} href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"text-primary underline-offset-2 hover:underline\" onClick={own}>\n {link?.[1]}\n </a>\n ) : (\n link?.[1] ?? tok\n ),\n );\n } else out.push(<em key={k}>{tok.slice(1, -1)}</em>);\n last = at + tok.length;\n }\n if (last < text.length) out.push(text.slice(last));\n return out;\n}\n\n/**\n * Markdown drawn as React elements — paragraphs, # headings, - and 1. lists, and the inline marks.\n * No HTML is ever parsed or injected: a `<` in the text is drawn as the character it is.\n */\nexport function SafeMarkdown({ text, clipped }: { text: string; clipped?: boolean }) {\n const blocks: ReactNode[] = [];\n const lines = text.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n let list: { ordered: boolean; items: string[] } | null = null;\n let para: string[] = [];\n const flushPara = () => {\n if (para.length > 0) {\n blocks.push(<p key={`p${blocks.length}`}>{inline(para.join(\" \"), `p${blocks.length}`)}</p>);\n para = [];\n }\n };\n const flushList = () => {\n if (list) {\n const items = list.items.map((item, i) => <li key={i}>{inline(item, `l${blocks.length}-${i}`)}</li>);\n blocks.push(\n list.ordered ? (\n <ol key={`o${blocks.length}`} className=\"ml-4 list-decimal\">{items}</ol>\n ) : (\n <ul key={`u${blocks.length}`} className=\"ml-4 list-disc\">{items}</ul>\n ),\n );\n list = null;\n }\n };\n for (const raw of lines) {\n const line = raw.trimEnd();\n const bullet = /^\\s*[-*+]\\s+(.*)$/.exec(line);\n const numbered = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line);\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (bullet || numbered) {\n flushPara();\n const ordered = Boolean(numbered);\n if (list && list.ordered !== ordered) flushList();\n if (!list) list = { ordered, items: [] };\n list.items.push((bullet ?? numbered)![1]!);\n } else if (heading) {\n flushPara();\n flushList();\n blocks.push(<p key={`h${blocks.length}`} className=\"font-semibold\">{inline(heading[2]!, `h${blocks.length}`)}</p>);\n } else if (line.trim() === \"\") {\n flushPara();\n flushList();\n } else {\n flushList();\n para.push(line.trim());\n }\n }\n flushPara();\n flushList();\n return (\n <span\n className={cn(\"block min-w-0 space-y-1 whitespace-normal text-sm\", clipped ? \"max-h-[4.5em] overflow-hidden\" : \"\")}\n data-records-rich-text=\"\"\n >\n {blocks}\n </span>\n );\n}\n\n// ── EDIT ───────────────────────────────────────────────────────────────────────────────────\n\ntype ControlProps = { field: Field; value: unknown; onChange: (value: unknown) => void; disabled?: boolean | undefined; id: string };\n\n/** The control for a newer kind, or undefined when the field's base control is right for it. */\nexport function newerKindControl(props: ControlProps): ReactNode | undefined {\n switch (newerKindOf(props.field)) {\n case \"duration\":\n return <DurationControl {...props} />;\n case \"address\":\n return <AddressControl {...props} />;\n case \"barcode\":\n return <BarcodeControl {...props} />;\n case \"created_by\":\n case \"modified_by\":\n case \"count\":\n return (\n <div id={props.id} className=\"rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground\">\n {props.value === null || props.value === undefined ? \"—\" : newerKindValue(props.field, props.value)}\n </div>\n );\n default:\n return undefined;\n }\n}\n\n/** A length of time, typed the way people say it; the value is seconds. */\nfunction DurationControl({ value, onChange, disabled, id }: ControlProps) {\n const [text, setText] = useState(() => durationText(value) ?? \"\");\n const [wrong, setWrong] = useState(false);\n useEffect(() => {\n setText(durationText(value) ?? \"\");\n }, [value]);\n return (\n <span className=\"flex flex-col gap-1\">\n <BasicInput\n id={id}\n value={text}\n disabled={disabled}\n inputMode=\"numeric\"\n placeholder=\"45 min\"\n aria-invalid={wrong || undefined}\n className=\"tabular-nums\"\n onChange={(e) => {\n setText(e.target.value);\n if (e.target.value.trim() === \"\") {\n setWrong(false);\n onChange(null);\n return;\n }\n const seconds = readTypedDuration(e.target.value);\n setWrong(seconds === null);\n if (seconds !== null) onChange(seconds);\n }}\n onBlur={() => {\n if (!wrong) setText(durationText(value) ?? \"\");\n }}\n />\n {wrong ? <span className=\"text-[11px] text-destructive\">Write it like 45 min, 1:30 or 1h 30m.</span> : null}\n </span>\n );\n}\n\nconst ADDRESS_LABELS: Record<AddressPart, string> = {\n street: \"Street\",\n city: \"City\",\n region: \"State or region\",\n postal_code: \"Postal code\",\n country: \"Country\",\n};\nconst ADDRESS_EXAMPLES: Record<AddressPart, string> = {\n street: \"1420 Cedar Ridge Pkwy\",\n city: \"Boulder\",\n region: \"CO\",\n postal_code: \"80301\",\n country: \"US\",\n};\n\n/** An address in its five parts; a part left empty is left out. */\nfunction AddressControl({ value, onChange, disabled, id }: ControlProps) {\n const held: AddressValue = isAddressValue(value) ? value : typeof value === \"string\" && value.trim() !== \"\" ? { street: value } : {};\n const set = (part: AddressPart, words: string) => {\n const next: AddressValue = { ...held, [part]: words };\n const kept = Object.fromEntries(Object.entries(next).filter(([, v]) => typeof v === \"string\" && v.trim() !== \"\")) as AddressValue;\n onChange(Object.keys(kept).length === 0 ? null : kept);\n };\n return (\n <span id={id} className=\"grid grid-cols-2 gap-1.5\" data-records-address-control=\"\">\n {ADDRESS_PARTS.map((part) => (\n <BasicInput\n key={part}\n aria-label={ADDRESS_LABELS[part]}\n placeholder={ADDRESS_EXAMPLES[part]}\n className={part === \"street\" ? \"col-span-2\" : \"\"}\n value={typeof held[part] === \"string\" ? (held[part] as string) : \"\"}\n disabled={disabled}\n {...(part === \"street\" ? { autoComplete: \"street-address\" } : {})}\n onChange={(e) => set(part, e.target.value)}\n />\n ))}\n </span>\n );\n}\n\ntype Detector = { detect: (source: ImageBitmapSource) => Promise<Array<{ rawValue: string }>> };\ntype DetectorCtor = new (opts?: { formats?: string[] }) => Detector;\n\n/** The phone's own barcode reader, when it has one (Chrome on Android). Null: no scanning here. */\nfunction barcodeDetector(): DetectorCtor | null {\n const ctor = (globalThis as { BarcodeDetector?: DetectorCtor }).BarcodeDetector;\n return typeof ctor === \"function\" ? ctor : null;\n}\n\n/** A barcode, typed — and on a phone that reads barcodes, photographed. */\nfunction BarcodeControl({ value, onChange, disabled, id }: ControlProps) {\n const file = useRef<HTMLInputElement>(null);\n const [said, setSaid] = useState<string | null>(null);\n const Detect = barcodeDetector();\n return (\n <span className=\"flex flex-col gap-1\">\n <span className=\"flex items-center gap-1.5\">\n <BasicInput\n id={id}\n className=\"font-mono\"\n value={typeof value === \"string\" ? value : \"\"}\n disabled={disabled}\n placeholder=\"4006381333931\"\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n {Detect && !disabled ? (\n <>\n <button\n type=\"button\"\n className=\"shrink-0 rounded-md border px-2 py-1 text-xs hover:bg-accent\"\n onClick={() => file.current?.click()}\n >\n Scan\n </button>\n <input\n ref={file}\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n className=\"hidden\"\n onChange={async (e) => {\n const photo = e.target.files?.[0];\n e.target.value = \"\";\n if (!photo) return;\n try {\n const found = await new Detect().detect(await createImageBitmap(photo));\n if (found[0]?.rawValue) {\n onChange(found[0].rawValue);\n setSaid(null);\n } else setSaid(\"No barcode in that photo. Try closer, in good light.\");\n } catch {\n setSaid(\"This phone could not read that photo. Type the code instead.\");\n }\n }}\n />\n </>\n ) : null}\n </span>\n {said ? <span className=\"text-[11px] text-muted-foreground\">{said}</span> : null}\n </span>\n );\n}\n","// src/choiceLooks.ts — @ai-matrx/records-ui · merge tranche 6f (early)\n//\n// A CHOICE WEARS THE COLOUR ITS OWNER GAVE IT.\n//\n// The older /data grid let a person paint each choice of a list (\"Completed\" green, \"Scheduled\"\n// blue), and those colours are kept on the Field itself: `display_format.options.choices`, the\n// document `custom.field_update` writes (the /data Sheet's seam writes it the same way, and a\n// column's settings here write it back). The grid used to ignore it and HASH THE WORD into a\n// colour, so a column painted green on /data came up amber here, and a colour a person set in the\n// settings changed nothing on screen — the silent half of a setting.\n//\n// Pure: no React, no store call. The Field the grid already holds carries everything.\n\nimport { newerKindOf, type Field } from \"@ai-matrx/records\";\nimport {\n CHOICE_CHIP_CLASS,\n NEUTRAL_CHIP_CLASS,\n STYLE_COLORS,\n type ChoiceColorLookup,\n type StyleColor,\n} from \"@ai-matrx/design-system/data-table\";\n\n/** One choice's look, as the Field keeps it. */\nexport interface ChoiceLook {\n value: string;\n label?: string;\n color?: StyleColor;\n}\n\n/** The Field's display document, which the store keeps beside its declared keys. */\nexport function displayFormatOf(field: Field): { id: string; options: Record<string, unknown> } | null {\n const raw = (field as unknown as { display_format?: unknown }).display_format;\n if (!raw || typeof raw !== \"object\") return null;\n const id = (raw as { id?: unknown }).id;\n if (typeof id !== \"string\" || id === \"\") return null;\n const options = (raw as { options?: unknown }).options;\n return { id, options: options && typeof options === \"object\" ? (options as Record<string, unknown>) : {} };\n}\n\nfunction isStyleColor(v: unknown): v is StyleColor {\n return typeof v === \"string\" && (STYLE_COLORS as readonly string[]).includes(v);\n}\n\n/** Every choice look the Field keeps, in its own order. A colour outside the palette is dropped. */\nexport function choiceLooksOf(field: Field): ChoiceLook[] {\n const display = displayFormatOf(field);\n const choices = display?.options[\"choices\"];\n if (!Array.isArray(choices)) return [];\n const out: ChoiceLook[] = [];\n for (const c of choices) {\n if (!c || typeof c !== \"object\") continue;\n const value = (c as { value?: unknown }).value;\n if (typeof value !== \"string\" || value.trim() === \"\") continue;\n const color = (c as { color?: unknown }).color;\n const label = (c as { label?: unknown }).label;\n out.push({\n value: value.trim(),\n ...(typeof label === \"string\" && label.trim() !== \"\" ? { label: label.trim() } : {}),\n ...(isStyleColor(color) ? { color } : {}),\n });\n }\n return out;\n}\n\n/**\n * ONE WORD, HOWEVER IT WAS WRITTEN. A moved list keeps its words as `completed` / `truck_4` and\n * shows them as `Completed` / `Truck 4`; a colour kept against either spelling is the same choice.\n */\nexport function choiceWord(value: unknown): string {\n return String(value ?? \"\")\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\n/**\n * NOTION'S STATUS COLOURS, BY GROUP: To-do grey, In progress blue, Complete green. A status choice\n * the column paints nothing for wears its group's colour, so a fresh Status column reads the way\n * Notion's does with nobody picking a colour. A choice with a colour of its own keeps it\n * (`storedChoiceColor` asks the column first).\n */\nexport const STATUS_GROUP_COLOR = { todo: \"gray\", in_progress: \"blue\", done: \"green\" } as const satisfies Record<string, StyleColor>;\n\n/** The colour a status choice's GROUP gives it, or `undefined` when the column is not a Status. */\nexport function statusGroupColor(field: Field, value: unknown): StyleColor | undefined {\n if (newerKindOf(field) !== \"status\" || value === null || value === undefined || value === \"\") return undefined;\n const word = choiceWord(value);\n if (word === \"\") return undefined;\n const groups = ((field.config ?? {}) as Record<string, unknown>)[\"status_groups\"];\n if (groups && typeof groups === \"object\") {\n // the group is kept under the choice's KEY; the cell may hold its WORDS (\"In progress\" ↔ in_progress)\n for (const [key, group] of Object.entries(groups as Record<string, unknown>)) {\n if (choiceWord(key) !== word) continue;\n return group === \"in_progress\" ? STATUS_GROUP_COLOR.in_progress : group === \"done\" ? STATUS_GROUP_COLOR.done : STATUS_GROUP_COLOR.todo;\n }\n }\n return STATUS_GROUP_COLOR.todo;\n}\n\n/** The colour this Field keeps for this value, or `undefined` when it keeps none. */\nexport function storedChoiceColor(field: Field, value: unknown): StyleColor | undefined {\n if (value === null || value === undefined || value === \"\") return undefined;\n const word = choiceWord(value);\n if (word === \"\") return undefined;\n for (const look of choiceLooksOf(field)) {\n if (!look.color) continue;\n if (choiceWord(look.value) === word || (look.label && choiceWord(look.label) === word)) return look.color;\n }\n return statusGroupColor(field, value);\n}\n\n/**\n * THE COLOUR-BY LOOKUP, STORED COLOURS FIRST. A value whose column keeps a colour for it wears\n * that colour; any other value still paints, deterministically, through `fallback` — a colour-by\n * that silently did nothing would be the screen lying about a setting a person just changed.\n */\nexport function storedChoiceColorLookup(\n fields: readonly Field[],\n fallback: ChoiceColorLookup,\n): ChoiceColorLookup {\n const byKey = new Map(fields.map((f) => [f.key, f] as const));\n return (fieldKey, value) => {\n const field = byKey.get(fieldKey);\n return (field ? storedChoiceColor(field, value) : undefined) ?? fallback(fieldKey, value);\n };\n}\n\n/**\n * THE ORDER A NEW CHOICE IS PAINTED IN (Airtable): each choice added to a list takes the next\n * palette colour the list does not wear yet, so a fresh list reads as distinct chips with nobody\n * picking a colour. Grey last — it reads as \"no colour\".\n */\nexport const NEW_CHOICE_PALETTE: readonly StyleColor[] = [\"blue\", \"green\", \"amber\", \"red\", \"violet\", \"teal\", \"slate\"];\n\n/** The colour the next choice of a list takes, given the colours its choices already wear. */\nexport function nextChoiceColor(worn: ReadonlyArray<StyleColor | null | undefined>): StyleColor {\n const taken = new Set(worn.filter((c): c is StyleColor => Boolean(c)));\n const free = NEW_CHOICE_PALETTE.find((c) => !taken.has(c));\n return free ?? NEW_CHOICE_PALETTE[worn.length % NEW_CHOICE_PALETTE.length]!;\n}\n\n/**\n * THE ONE CHIP A CHOICE IS DRAWN AS — the grid cell, the picker's list and its chip, a form's\n * pills: the colour the column keeps for the value (by any of the words given — its key, its\n * label), else the neutral chip. One answer, so no surface paints a choice its own way.\n */\nexport function choiceChipLookOf(field: Field, ...words: unknown[]): { className: string; color: StyleColor | null } {\n for (const word of words) {\n const color = storedChoiceColor(field, word);\n if (color) return { className: CHOICE_CHIP_CLASS[color], color };\n }\n return { className: NEUTRAL_CHIP_CLASS, color: null };\n}\n","// src/parity.ts — @ai-matrx/records-ui\n//\n// FLD-11, the parity floor. A Field stores a BEHAVIOUR (one of five) plus\n// modifiers, unit and format; a person picked one of THIRTEEN parity types in\n// the UI. This resolves the second from the first, using the same facts the\n// store's own `custom.parity_field_types()` describes — which is generated into\n// `@ai-matrx/records` and imported here, never retyped.\n//\n// Nothing in this file decides policy. It decides which editor to draw.\n\nimport { displayFormatOf } from \"./choiceLooks\";\nimport {\n KERNEL_TABLES,\n PARITY_FIELD_TYPES,\n fieldKindFor,\n newerKindOf,\n type Field,\n type FieldKind,\n type KernelTargets,\n type ParityFieldType,\n} from \"@ai-matrx/records\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\nimport { isSignatureField } from \"./docs\";\nimport { fieldTypeChoice, isSystemFieldKind, type PickableFieldType } from \"./fieldTypes\";\n\n/** The kernel ids come from the store's own kernel rows, never from a literal here. */\nconst kernelId = (name: string): string =>\n KERNEL_TABLES.find((t) => t.name === name)?.id ?? \"\";\nconst KERNEL_FILE_TABLE = kernelId(\"File\");\nconst KERNEL_PERSON_TABLE = kernelId(\"Person\");\n\nexport const PARITY_LABEL: Record<ParityFieldType, string> = {\n attachment: \"Attachment\",\n checkbox: \"Yes / no\",\n currency: \"Currency\",\n datetime: \"Date\",\n email: \"Email\",\n formula: \"Formula\",\n lookup: \"Lookup\",\n member: \"Person\",\n multi_select: \"Multi-select\",\n percent: \"Percent\",\n phone: \"Phone\",\n rollup: \"Rollup\",\n select: \"Select\",\n url: \"Link\",\n};\n\n/** The \"made of\" sentence the store itself publishes, for the field editor's help text. */\nexport const PARITY_MADE_OF: Record<string, string> = Object.fromEntries(\n PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of]),\n);\n\n/**\n * Plain text and plain number are behaviours with no parity type of their own.\n *\n * 🚨 THIS IS NOW AN ALIAS, AND THAT IS THE POINT (TAILS-3, 2026-09-21). The\n * classifier moved into `@ai-matrx/records` as `FieldKind` so that the editor a\n * person types into and the COERCION applied to what they typed are decided by\n * one body. They were decided by two, and the public booking page paid for it:\n * \"Vehicle Year takes a number, and it was given a string\" on every table with\n * a number field.\n */\nexport type EditorKind = FieldKind;\n\n/** The kernel ids come from the store's own kernel rows, never from a literal here. */\nconst KERNEL: KernelTargets = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };\n\n/**\n * Which editor one Field wants. Reads the Field's own declaration only — the\n * behaviour, the modifiers, the format, the relation target and the config —\n * because those are what the store stores, and a screen that guessed from a\n * value would draw a different editor for an empty record.\n *\n * It is `fieldKindFor` with this package's kernel ids bound. Nothing here\n * decides anything the core does not.\n */\nexport function editorKindFor(field: Field): EditorKind {\n return fieldKindFor(field, KERNEL);\n}\n\n/**\n * WHICH KIND A PERSON PICKED, read back off the Field the store keeps — the ONE reader every\n * \"what does this column hold\" answer goes through (the Settings column list, the column panel).\n *\n * `editorKindFor` answers which EDITOR to draw, and for two families that is not the kind a\n * person picked: a Signature is a text Field whose format is `signature` (it draws a line of\n * text), and the store's stamps — Record number, Created time, Last changed time — are formula\n * Fields whose `config.system` names the stamp. Read through the editor classifier alone, the\n * Settings list called a Signature \"Text\" and a Record number \"Worked out from other columns\"\n * (lane 10 W1-A, guard `every-pickable-kind-reads-back-as-itself.test.tsx`).\n *\n * `undefined` when the Field is none of the kinds the menu offers.\n */\nexport function pickableTypeOf(field: Field): PickableFieldType | undefined {\n if (isSignatureField(field)) return \"signature\";\n // LANE 10 P4: the nine newer kinds, each a base type wearing a format (`newerKindOf`).\n const newer = newerKindOf(field);\n if (newer) return newer;\n // A RATING OR A TIME made as a plain column wearing its look (`LOOK_KINDS`): named by that kind.\n const look = displayFormatOf(field)?.id;\n if (look === \"rating\" && field.type === \"range\") return \"rating\";\n if (look === \"time\" && field.type === \"text\") return \"time\";\n const system = (field.config as Record<string, unknown> | undefined)?.[\"system\"];\n if (field.type === \"formula\" && typeof system === \"string\" && isSystemFieldKind(system)) return system;\n const kind = editorKindFor(field);\n return fieldTypeChoice(kind) ? (kind as PickableFieldType) : undefined;\n}\n\n/**\n * The type word a person sees in a header or a settings row — and it is the\n * SAME word the field panel offers, read from `FIELD_TYPE_CHOICES`, so a column\n * added as \"Money\" is never described anywhere else as \"Currency\".\n */\nexport function fieldTypeLabel(field: Field): string {\n const kind = pickableTypeOf(field) ?? editorKindFor(field);\n const known = fieldTypeChoice(kind)?.label;\n if (known) return field.multi && kind !== \"multi_select\" ? `${known} (many)` : known;\n const plain: Record<string, string> = {\n // `boolean` is the BEHAVIOUR word; `checkbox` is the type a person picks. Both are\n // written the way a person writes them, never as a raw token.\n boolean: \"Yes / no\",\n date: \"Date\",\n json: \"Structured data\",\n relation: \"Link to a record\",\n };\n // Never a raw token on a screen: an editor kind this table has not named is\n // still written the way a person writes it.\n return plain[kind] ?? humanizeIdentifier(kind);\n}\n","\"use client\";\n\n// src/docs.ts — @ai-matrx/records-ui · SCR-20, SCR-21, SCR-22\n//\n// DOCUMENTS OVER RECORDS. A template is a body whose tokens point at Fields BY\n// ID; a render is written ONCE and frozen with the SHA-256 of its own text; a\n// signature seals that exact version and is immutable once made.\n//\n// Three things this package refuses to re-implement, because the store already\n// does them and doing them twice is how two answers appear:\n// · which tokens a body contains — `custom.doc_tokens`;\n// · which of them this Table cannot answer, and why — `custom.doc_unresolved_tokens`;\n// · whether a signature still holds — `custom.doc_signature_intact`.\n//\n// The token syntax is the store's own: `{{field:<the field's id>}}`. A name\n// would be a token that silently stops resolving the day somebody renames a\n// Field, which is the exact failure REC-17 exists to prevent.\n\nimport type { Field, Uuid } from \"@ai-matrx/records\";\n\n/** The one token form, written the way the store's own pattern reads it. */\nexport function fieldToken(fieldId: Uuid): string {\n return `{{field:${fieldId}}}`;\n}\n\n/** THE DECLARATIVE SPEC an agent writes. One template, whole, in one object. */\nexport interface DocTemplateSpec {\n name: string;\n /** The body, tokens and all. */\n body: string;\n}\n\n/**\n * A template written in terms of Field KEYS — which is how an agent thinks and\n * how a person reads — turned into the store's id-based tokens. The agent writes\n * `{{title}}`; what is stored points at the Field's id, so a rename never\n * silently empties the document.\n *\n * A key this Table does not have is LEFT EXACTLY AS IT IS, so\n * `custom.doc_unresolved_tokens` names it and the screen shows the store's own\n * reason — it is never quietly deleted from the body.\n */\nexport function bodyFromKeys(body: string, fields: Field[]): string {\n const byKey = new Map(fields.map((f) => [f.key, f.id]));\n return body.replace(/\\{\\{\\s*([a-zA-Z0-9_]+)\\s*\\}\\}/g, (whole, key: string) => {\n const id = byKey.get(key);\n return id ? fieldToken(id) : whole;\n });\n}\n\n/** The reverse, for a person reading a stored body: ids shown as the Field's label. */\nexport function bodyForReading(body: string, fields: Field[]): string {\n const byId = new Map(fields.map((f) => [f.id, f.label || f.key]));\n return body.replace(/\\{\\{\\s*field:([0-9a-fA-F-]{36})\\s*\\}\\}/g, (whole, id: string) => {\n const label = byId.get(id);\n return label ? `{{${label}}}` : whole;\n });\n}\n\n/** VAL-10: a signature is a Value on a text Field whose format is `signature`. */\nexport function isSignatureField(field: Field): boolean {\n return field.type === \"text\" && (field.format ?? \"\").toLowerCase() === \"signature\";\n}\n","// src/names.ts — @ai-matrx/records-ui\n//\n// WHAT A PERSON READS, NEVER WHAT THE MACHINE STORES.\n//\n// Measured on the real screens (independent verdict, 19 September): a table row\n// read `Saved views · 9 fields · records_ui_view`, a relation cell read a bare\n// `8f2c…` identifier, a header read `stage` because the Field's label was\n// blank, and the type word on a column tooltip read `long_text`. Airtable,\n// Notion and Linear never show a person an internal name; the verdict called\n// this one of the three things a first-time user feels within a minute.\n//\n// So every place this package prints something a person reads goes through one\n// of these three functions. They are deliberately dumb: they choose the best\n// human string that IS AVAILABLE and, when none is, say what the thing is\n// rather than printing the token. No screen in this package formats a name of\n// its own any more.\n\nimport type { Field, ReadRow, RecordDocument, Table } from \"@ai-matrx/records\";\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\n\n/** The name of one Field, as a header, a form label or a peek's term. */\nexport function fieldName(field: Field): string {\n const label = (field.label ?? \"\").trim();\n // A LABEL THAT IS ONLY A MACHINE KEY is not a name (merged-grid review 2026-09-26): a table made\n // by an import or an agent kept `label: \"job_no\"`, and the header read `job_no`. A key joined by\n // underscores is written the way a person writes it (\"Job no\"). A single lowercase word the\n // owner typed (\"mobile\", \"title\") is their own words and is shown as they wrote it.\n if (label !== \"\" && label === field.key && /^[a-z0-9]+(?:[_.-][a-z0-9]+)+$/.test(label)) return humanizeIdentifier(label);\n if (label !== \"\") return label;\n const name = (field.name ?? \"\").trim();\n if (name !== \"\") return name;\n return humanizeIdentifier(field.key);\n}\n\n/** The name of one Table, as a card, a heading or a breadcrumb. */\nexport function tableName(table: Table): string {\n const name = (table.name ?? \"\").trim();\n if (name !== \"\") return name;\n const singular = (table.label_singular ?? \"\").trim();\n if (singular !== \"\") return singular;\n return humanizeIdentifier(table.slug ?? \"\");\n}\n\n/**\n * The name of one RECORD, for a chip, a card, a relation cell or a peek title.\n *\n * `titleKey` is the Table's own `title_field` when the caller knows the Table —\n * that is the store's answer to \"what makes this record a chip\" (REC-2) — and\n * the conventional keys are tried after it. A record with nothing readable is\n * NOT shown as a truncated uuid: it says it has no name yet, because \"8f2c1b0a\"\n * tells a person nothing and looks like a bug.\n */\nexport function recordName(\n document: RecordDocument | undefined,\n titleKey?: string | null,\n fallback = \"Untitled\",\n): string {\n const data = (document ?? {}) as Record<string, unknown>;\n const keys = [titleKey, \"title\", \"name\", \"label\", \"full_name\", \"subject\", \"summary\"].filter(\n (key): key is string => typeof key === \"string\" && key !== \"\",\n );\n for (const key of keys) {\n const value = data[key];\n // AN ID IS NEVER A NAME, AND THIS FUNCTION USED TO RETURN ONE (TAILS-2, 2026-09-21).\n // A Table's title column may be a RELATION, and a relation's stored value IS the other\n // record's id (FLD-6 / REL-1) — so `recordName` handed every caller a bare uuid for\n // every Table titled that way, which is how the board's unplaced list came to read\n // \"11 records are not in any of these columns — ca5f1ac7-…\". A caller that can resolve\n // the id resolves it (`scalarText` with the label lookup); a caller that cannot is\n // better off reading the next column, and then the fallback, than a hex number.\n if (typeof value === \"string\" && value.trim() !== \"\" && !looksLikeId(value.trim())) {\n return value.trim();\n }\n if (typeof value === \"number\") return String(value);\n }\n return fallback;\n}\n\n\n/**\n * Is this string the store's id for something, rather than words a person wrote?\n *\n * The same question `custom._card_words` asks on the database, with the same regex, so the\n * screen and the store agree about what is a name (TAILS-2, 2026-09-21).\n */\nexport function looksLikeId(value: unknown): boolean {\n return typeof value === \"string\" && isUuidShape(value.trim());\n}\n\n/** The same question for a row the read door returned. */\nexport function rowName(row: ReadRow | undefined, titleKey?: string | null, fallback = \"Untitled\"): string {\n return recordName(row?.document, titleKey, fallback);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════════════\n// NAMING A RECORD WHOSE TABLE YOU ALREADY HOLD — ONE CALL, NOT A COPY PER SCREEN.\n// ═══════════════════════════════════════════════════════════════════════════════════════\n//\n// 🚨 WHY THESE TWO EXIST (lane RELATION-DISPLAY-2, 2026-09-21).\n//\n// `check:one-reference-builder` shipped with a baseline of SIX, and its own header said the\n// number was not zero because \"moving six surfaces onto the store door is real work\". Three\n// of the six were not asking the store's question at all. `Grid.tsx` names the row a person\n// is looking at for the Talk action; `Peek.tsx` names the record being peeked at;\n// `PortalsPanel.tsx` names the rows of the portal's own client Table; and this repo's\n// `TryEverythingScreen.tsx` does the same in two places. NONE of them is resolving a\n// RELATION — they hold the Table and they hold the document, and there is nothing to ask a\n// door about. What they were each doing by hand was the two-line join between them:\n//\n// recordName(row.document, table.title_field)\n//\n// Written out five times in four files, which is how a Table whose title column is `cname`\n// came to read \"Untitled\" on one screen and correctly on the next. It is the same question\n// as the store's, one rung down the ladder, and the same one answer should serve it — so it\n// lives HERE, in the file the guard exempts BY CONSTRUCTION as the primitive itself, and\n// every screen calls it instead of re-deriving it.\n//\n// WHAT THESE ARE NOT. They are not a second resolver and must never become one. They take a\n// Table a caller ALREADY HAS and a document it ALREADY HAS. The moment a caller is holding\n// an ID and wants words, that is the store's question and the answer is\n// `client.relationWords` / `client.relationWordsMany` — which ask the read-access ladder\n// BEFORE they read a name, apply that column's own display spec, and return the withheld\n// sentence for a record the reader may not open. Nothing in here can do any of that, and\n// nothing in here should try.\n\n/** A Table as far as naming is concerned — its own declared title column (REC-2). */\ntype TitledTable = Pick<Table, \"title_field\"> | null | undefined;\n\n/**\n * THE NAME OF A RECORD WHOSE TABLE YOU ALREADY HOLD.\n *\n * `table` is the Table the record belongs to; its `title_field` is the store's answer to\n * \"what makes this record a chip\" (REC-2) and is tried first, then the conventional keys,\n * then the fallback. A Table that has not loaded yet is `null` and the conventional keys\n * still answer — a name arriving a tick late is better than a screen that shows nothing.\n */\nexport function recordNameIn(\n table: TitledTable,\n document: RecordDocument | undefined,\n fallback = \"Untitled\",\n): string {\n return recordName(document, table?.title_field ?? null, fallback);\n}\n\n/**\n * THE NAME A CHANGE NOTICE USES — the record as it is AFTER the change (merged-grid tails,\n * 2026-09-26). Typing a first name into a row's label column read \"Changed Title on Untitled\":\n * the notice named the row from the document held before the write. The row is called what it is\n * called now; only when the change emptied its name does the notice use the name it had.\n */\nexport function changedRecordName(\n table: TitledTable,\n document: RecordDocument | undefined,\n key: string,\n after: unknown,\n): string {\n const now = recordName({ ...((document ?? {}) as Record<string, unknown>), [key]: after } as RecordDocument, table?.title_field ?? null, \"\");\n return now !== \"\" ? now : recordNameIn(table, document);\n}\n\n/** The same, for a row the read door returned. */\nexport function rowNameIn(table: TitledTable, row: ReadRow | undefined, fallback = \"Untitled\"): string {\n return recordName(row?.document, table?.title_field ?? null, fallback);\n}\n\n/**\n * WHAT A RELATION CHIP SAYS WHEN THE RECORD IT POINTS AT IS NOT YOURS.\n *\n * A relation joins two records in two tables, and holding one end says nothing\n * about the other: a Job shared with you may point at a Client nobody shared.\n * The chip then has three possible answers and only one of them is honest —\n * the target's TITLE is a leak, a bare id is a bug with a hex number in it, and\n * a permanent \"Loading…\" is a lie that never resolves.\n *\n * This is the SAME sentence `platform.relation_withheld_label()` answers on the\n * database, word for word, so a person reads one wording whether the screen or\n * the store worked it out. Changing it changes both (RELATION-DECLARE,\n * 2026-09-20).\n */\nexport const WITHHELD_RECORD_LABEL = \"A record you have not been given access to\";\n/**\n * WHEN THE STORE COULD NOT BE ASKED (a 503, a dropped connection) the name is UNREAD, not\n * withheld: saying \"not given access\" for a failed read lies about the data (W1.1 verifier,\n * 2026-10-02). This is what a reference reads until a later read answers.\n */\nexport const UNREAD_RECORD_LABEL = \"Couldn't load this name\";\n\n/**\n * THE PLURAL A PERSON READS, NEVER A MACHINE'S \"…ss\" (VERIFIER-16 M3 / VERIFIER-17 M3).\n *\n * A table the store or the mover never gave a real plural carries `name + \"s\"` — so a table\n * already named in the plural reads \"Customerss\", \"Status optionss\". That word was made by a\n * machine appending one letter, and it says nothing the name does not; it is never shown.\n * Returns the table's own plural when a person (or the example library) wrote one, and `null`\n * when the only plural on record is that appended letter.\n */\nexport function realPlural(table: { name?: string | null; label_singular?: string | null; label_plural?: string | null }): string | null {\n const plural = (table.label_plural ?? \"\").trim();\n if (plural === \"\") return null;\n for (const base of [table.name, table.label_singular]) {\n const b = (base ?? \"\").trim();\n if (b !== \"\" && plural === `${b}s`) return null;\n }\n return plural;\n}\n\n/**\n * ONE RECORD'S NOUN, IN A SENTENCE (\"Book a 30-minute visit\") — lane HANDOVER, 2026-09-28.\n *\n * Cedar Ridge Physical Therapy's booking page was titled \"Book a 30-minute Visits appointment\":\n * the table's NAME (a plural, a heading) was put where one record's noun goes. The noun is the\n * table's own singular (\"Visit\"), else its name, else the fallback; a Title-case word is written\n * the way a sentence writes it (\"visit\"), an acronym is kept (\"MRI scan\").\n */\nexport function singularNoun(\n table: { name?: string | null; label_singular?: string | null } | null | undefined,\n fallback = \"record\",\n): string {\n const word = (table?.label_singular ?? \"\").trim() || (table?.name ?? \"\").trim() || fallback;\n return word\n .split(/\\s+/)\n .map((w) => (/^[A-Z][a-z'’-]*$/.test(w) ? w.toLowerCase() : w))\n .join(\" \");\n}\n\n/**\n * A plural for a sentence (\"Check in ran on 2 appointments\"): the table's real plural, else the\n * singular with an \"s\" only when that does not double a final \"s\".\n */\nexport function pluralNoun(table: { name?: string | null; label_singular?: string | null; label_plural?: string | null } | null | undefined, fallback = \"record\"): string {\n const real = table ? realPlural(table) : null;\n if (real) return real;\n const singular = (table?.label_singular ?? \"\").trim() || fallback;\n return /s$/i.test(singular) ? singular : `${singular}s`;\n}\n\n\n// ═══════════════════════════════════════════════════════════════════════════════════════\n// WHAT A CARD IS TITLED BY (lane UI-FIX-18, VERIFIER-18 H5).\n// ═══════════════════════════════════════════════════════════════════════════════════════\n//\n// MEASURED 2026-09-24 on production: *ZZZ UI-QUICK-1 Rincon-style Jobs* (title column `title`)\n// grouped by Stage titled every kanban card \"false\" or \"true\". The board took the FIRST Field\n// the read door answered that was not the group column — here the *Urgent* checkbox — as the\n// title. A card is named by what names its record: the Table's own `title_field` first (REC-2),\n// then the conventional name keys, then the first words column in declared order. A yes/no\n// column, the column the board is grouped by and the store's own stamps never title a card.\n\nconst CONVENTIONAL_TITLE_KEYS = [\"title\", \"name\", \"label\", \"full_name\", \"subject\", \"summary\"];\n\nfunction canTitle(field: Field, excluded: ReadonlySet<string>): boolean {\n if (excluded.has(field.key)) return false;\n if (field.type === \"boolean\") return false;\n if (field.type === \"formula\" && (field.config ?? {})[\"system\"]) return false;\n return true;\n}\n\n/**\n * THE FIELD A CARD IS TITLED BY — kanban, calendar, gallery and pipeline alike.\n *\n * Order: the Table's `title_field` → a conventional name key (`title`, `name`, …) → the first\n * text column in declared `sort` order → the first other column that can title (never a\n * checkbox, never the group column, never a system stamp). `undefined` when nothing can, and\n * the card falls back to `rowName`, which says \"Untitled\" rather than \"false\".\n */\nexport function cardTitleField(\n fields: readonly Field[],\n titleKey: string | null | undefined,\n exclude: readonly (string | null | undefined)[] = [],\n): Field | undefined {\n const excluded = new Set(exclude.filter((k): k is string => typeof k === \"string\" && k !== \"\"));\n const ordered = [...fields].sort((a, b) => (a.sort ?? 100) - (b.sort ?? 100) || a.key.localeCompare(b.key));\n const byKey = (key: string) => ordered.find((f) => f.key === key && canTitle(f, excluded));\n if (titleKey) {\n const declared = byKey(titleKey);\n if (declared) return declared;\n }\n for (const key of CONVENTIONAL_TITLE_KEYS) {\n const found = byKey(key);\n if (found) return found;\n }\n return (\n ordered.find((f) => f.type === \"text\" && canTitle(f, excluded)) ?? ordered.find((f) => canTitle(f, excluded))\n );\n}\n","\"use client\";\n\n// src/RelationPicker.tsx — @ai-matrx/records-ui · SCR-N-2\n//\n// THE ONE GENERIC RELATION PICKER. Before it, every relation-shaped field in\n// the product had a type-specific picker (image, file, url, scope) and a plain\n// `relation` field was not editable at all.\n//\n// It reads the target Table's records through the read door, shows each one as\n// its own chip (REC-2: the title field is what makes a record a chip), and\n// respects `relation_max` by saying the number rather than silently dropping a\n// pick.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { Field, ReadRow, RecordsError, Table, Uuid } from \"@ai-matrx/records\";\nimport { rankTypedMatches } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { BasicInput, Button, cn } from \"@ai-matrx/design-system\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { RecordChip } from \"./editors\";\nimport { UNREAD_RECORD_LABEL, WITHHELD_RECORD_LABEL, fieldName } from \"./names\";\nimport { RefusalLine, RefusalNotice } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { tellApart } from \"./tellApart\";\n\nexport interface RelationPickerProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n /**\n * WHETHER A PERSON MAY MAKE THE THING SHE IS LOOKING FOR (RELATION-CREATE, 2026-09-22).\n *\n * On by default, because that is what this control is for on every surface a\n * person fills a record in: the grid cell, the generated form, a public form\n * runner. The one surface that passes `false` is the filter builder — picking\n * a value to FILTER by is not a reason to put a new customer in the book, and\n * a Create button there would write a row nobody asked for.\n */\n allowCreate?: boolean | undefined;\n /**\n * A SINGLE LINK'S PICK IS ITS COMMIT in a grid cell (Enter on the highlighted match, or a click):\n * called after a one-record column picks a record, so the cell saves without a second Save.\n */\n onPicked?: (() => void) | undefined;\n /**\n * IN A GRID CELL the list is open from the start and hangs from the cell (lane CELL-EDITORS,\n * 2026-10-06): no \"Pick\" button over a Save / Cancel row. Closing it is the cell's commit.\n */\n autoOpen?: boolean | undefined;\n /** The list closed: the cell commits what is picked. */\n onClose?: (() => void) | undefined;\n /** Escape in a grid cell's list: the cell's cancel — nothing is written (`PickOrAdd.onEscape`). */\n onCancel?: (() => void) | undefined;\n}\n\n/**\n * The sentence this control shows on a screen served to somebody with NO ACCOUNT.\n *\n * VERIFIER-10 finding F1, on production: a published job-request form whose\n * first question was a relation answered HTTP 500 to a stranger, because this\n * control asked `useRecordsClient` for a client that the public arm of\n * `FormRunner` deliberately never mounts — the browser on that page holds no\n * key, knows no organization and may not read a row. That is CORRECT; what was\n * wrong was asking for it with the hook that throws.\n *\n * A picker here cannot exist: searching the owner's records is exactly the read\n * `custom.form_public` refuses a stranger, and a control that offered it would\n * be the leak. So the question is ABSENT and says so, with what to do instead,\n * and the rest of the form is still answerable.\n */\nexport const NO_STORE_ON_THIS_SCREEN_REASON =\n \"This question points at a record in somebody's own data, and a page answered without an \" +\n \"account is never allowed to search that. Leave it blank — whoever receives your answer will \" +\n \"fill it in.\";\n\nexport function RelationPicker({ field, value, onChange, disabled, id, className, allowCreate = true, onPicked, autoOpen, onClose, onCancel }: RelationPickerProps) {\n // NOT `useRecordsClient`. See NO_STORE_ON_THIS_SCREEN_REASON above: this\n // control is drawn on the public form runner, which mounts no store client at\n // all, and the hook that throws took the whole page down with it.\n const client = useOptionalRecordsClient();\n const [rows, setRows] = useState<ReadRow[] | null>(null);\n // WHAT EACH ROW AND EACH PICKED ID IS CALLED — the store's answer, keyed by id.\n // Never derived here: see the block above the effect below.\n const [words, setWords] = useState<Record<string, string>>({});\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n const [search, setSearch] = useState(\"\");\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Closing the list — a pick, Escape, a click away — is what a grid cell commits on.\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n // ── MAKING THE ONE THAT IS NOT THERE YET (RELATION-CREATE, 2026-09-22).\n // A person filling in a Job whose customer has never been written down had\n // exactly one thing to read here — \"Nothing in that table matches.\" — and\n // nowhere to go: leave the record, find the Customers table, add a row, come\n // back, re-open the picker, search again. Airtable and Notion both end that\n // list with \"Create <what you typed>\", and so does this one now. It is added\n // HERE, in the one generic relation picker, so the grid cell, the generated\n // record form, the form runner and every future relation surface inherit it\n // from the same control instead of each growing its own.\n const [target, setTarget] = useState<Table | null>(null);\n const [targetRefusal, setTargetRefusal] = useState<RecordsError | null>(null);\n const [creating, setCreating] = useState(false);\n const [newTitle, setNewTitle] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [createRefusal, setCreateRefusal] = useState<RecordsError | null>(null);\n\n const picked = useMemo<string[]>(\n () => (Array.isArray(value) ? value.map(String) : value === null || value === undefined ? [] : [String(value)]),\n [value],\n );\n\n // ── THE TARGET'S ROWS, ON MOUNT AND NOT ON OPEN (RELATION-DECLARE, 2026-09-20).\n // This used to wait for the popover, so every chip on every relation cell read\n // \"Loading…\" until somebody clicked Pick — a word that never resolved, on a\n // screen nobody was going to click. A chip is a NAME; it is read far more often\n // than it is changed, so what it needs is fetched when the cell is drawn.\n //\n // WHAT IT NO LONGER FETCHES IS THE TABLE (lane RELATION-DISPLAY-2, 2026-09-21).\n // It used to read `tableList()` for the target's `title_field` and name every row\n // and every chip itself — the third of three copies of that derivation, and the\n // reason a column configured to read \"Maria Chen — Rincon\" still offered a flat\n // list of two identical \"Maria Chen\"s to pick between. The picker now shows the\n // SAME WORDS THE CELL SHOWS, because they come from the same place: this column's\n // own display spec, resolved by the store, with the ladder asked first.\n useEffect(() => {\n const target = field.relation_target;\n if (!target || !client) return;\n let cancelled = false;\n void client.list({ table_id: target as Uuid, limit: 200 }).then((result) => {\n if (cancelled) return;\n if (result.ok) setRows(result.data.rows);\n else setRefusal(result.error);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.relation_target]);\n\n // ── AND WHAT EVERY ONE OF THEM IS CALLED — IN ONE CALL.\n // The rows this reader may see AND the ids already picked go to the store together.\n // A picked id that is not in the visible page is the interesting case: a Job shared\n // with you may point at a Client nobody shared, and the two possibilities — \"further\n // down a long list\" and \"not hers\" — have different sentences. The door tells them\n // apart, because the ladder runs inside it; a name assembled out here has already\n // been read. An id the door gives no words for reads the same sentence the store\n // itself gives (`platform.relation_withheld_label()`): never the title, never a bare\n // id, and never a \"Loading…\" that resolves for nobody.\n useEffect(() => {\n if (!rows || !client) return;\n const wanted = [...new Set([...rows.map((row) => row.id), ...picked])].filter(\n (id) => words[id] === undefined,\n );\n if (wanted.length === 0) return;\n let cancelled = false;\n void client\n .relationWordsMany({ field_id: field.id, record_ids: wanted as Uuid[] })\n .then((result) => {\n if (cancelled) return;\n const learned: Record<string, string> = {};\n for (const id of wanted) {\n const said = result.ok ? result.data[id] : undefined;\n // A FAILED read is unread, never withheld — only an answer of nothing is withheld.\n learned[id] = !result.ok\n ? UNREAD_RECORD_LABEL\n : typeof said === \"string\" && said !== \"\"\n ? said\n : WITHHELD_RECORD_LABEL;\n }\n setWords((current) => ({ ...current, ...learned }));\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, rows, picked, words]);\n\n // ── THE TARGET TABLE, READ ONLY WHEN SOMEBODY OPENS THE PICKER.\n // Deliberately NOT on mount: `RelationPicker` is drawn on every relation cell\n // of every row, and the read above was cut back to the rows for exactly that\n // reason (RELATION-DISPLAY-2). What a create needs — the Table's own name and\n // its `title_field` — is only needed once a person has opened the control, so\n // it is fetched then and cached for the life of the cell.\n useEffect(() => {\n if (!open || !allowCreate || target || targetRefusal || !client) return;\n const id = field.relation_target;\n if (!id) return;\n let cancelled = false;\n void client.tableList().then((result) => {\n if (cancelled) return;\n if (!result.ok) {\n setTargetRefusal(result.error);\n return;\n }\n const found = result.data.find((t) => t.id === id) ?? null;\n if (found) setTarget(found);\n else\n setTargetRefusal(\n refusalOf(\n \"door\",\n \"That Table is not one you can open, so a new record cannot be added to it from here.\",\n ),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [client, open, allowCreate, target, targetRefusal, field.relation_target]);\n\n if (!client) {\n // ABSENT AND HONEST, never a dead popover. No store client is mounted on\n // this screen at all, which on a public form is the correct posture.\n return (\n // The Field's own name is already printed above this control by\n // `FieldLabel`, so the sentence does not say it a second time.\n <p id={id} className={cn(\"text-xs text-muted-foreground\", className)}>\n {NO_STORE_ON_THIS_SCREEN_REASON}\n </p>\n );\n }\n\n if (!field.relation_target) {\n // Absent, and honest about why: a relation with no declared target is a\n // Field the store has not finished, not a picker that \"has no options\".\n return (\n <p className=\"text-xs text-muted-foreground\">\n {fieldName(field)} points at records, but it does not say which Table yet, so there is nothing to pick\n from. A table admin sets its target in the field editor.\n </p>\n );\n }\n\n // A chip carries the record's NAME. Before `names.ts`, a relation whose target had\n // not loaded yet drew `8f2c1b0a` — a bare identifier, which the verdict of 19\n // September counted among the three things a first-time user feels within a minute.\n // It now reads THIS COLUMN'S OWN WORDS, resolved by the store: the same string the\n // cell shows, so what a person picks from and what they then read back are never two\n // different answers. A record that is not this reader's says so in the store's own\n // words instead of waiting forever.\n const titleOf = (recordId: string) => words[recordId] ?? \"Loading…\";\n const full = field.multi && field.relation_max !== null && picked.length >= field.relation_max;\n\n const toggle = (recordId: string) => {\n if (!field.multi) {\n const choosing = picked[0] !== recordId;\n onChange(choosing ? recordId : null);\n setOpen(false);\n // After the draft has taken the pick, so the cell saves what was just chosen.\n if (choosing && onPicked) setTimeout(onPicked, 0);\n return;\n }\n const next = new Set(picked);\n if (next.has(recordId)) next.delete(recordId);\n else if (!full) next.add(recordId);\n onChange(next.size === 0 ? null : [...next]);\n };\n\n // WHAT THE NEW ONE IS CALLED IN THE BUTTON — the Table's own singular label if\n // it has one, its name otherwise. Never a hardcoded \"item\": a person adding a\n // customer reads \"New customer\".\n const targetWord = (target?.label_singular ?? \"\").trim() || (target?.name ?? \"\").trim() || \"record\";\n\n const create = async (rawTitle: string) => {\n const title = rawTitle.trim();\n const tableId = field.relation_target;\n if (!tableId || title === \"\" || busy) return;\n if (!target) {\n // Cannot happen from the rendered control (it draws only once the Table is\n // in hand), and if it ever does the person is told rather than ignored.\n setCreateRefusal(refusalOf(\"unreachable\", \"Still reading that Table.\", \"Try again in a moment.\"));\n return;\n }\n const titleField = target.title_field;\n if (!titleField) {\n // ABSENT AND HONEST, never a dead button: REC-2 says a record without a\n // title column cannot be a chip, so a row made here would come back\n // nameless. The remedy names who can fix it and where.\n setCreateRefusal(\n refusalOf(\n \"not_supported\",\n `${target.name} has no column that names a record yet, so a new one would have nothing to show here.`,\n \"A table admin picks its title column in that table's settings.\",\n ),\n );\n return;\n }\n setBusy(true);\n setCreateRefusal(null);\n const written = await client.recordWrite({ table_id: tableId as Uuid, data: { [titleField]: title } });\n if (!written.ok) {\n setBusy(false);\n setCreateRefusal(written.error);\n return;\n }\n const createdId = String(written.data);\n // THE NEW ROW AND ITS WORDS COME BACK FROM THE STORE, never assembled here:\n // this column's display spec may join two of the target's columns, and the\n // only body that knows that is the door (`custom.relation_words_many`). The\n // words effect above picks the new id up because `picked` now carries it.\n const refreshed = await client.list({ table_id: tableId as Uuid, limit: 200 });\n if (refreshed.ok) setRows(refreshed.data.rows);\n setBusy(false);\n setCreating(false);\n setNewTitle(\"\");\n setSearch(\"\");\n toggle(createdId);\n };\n\n // Two records with one name carry the words that tell them apart (see tellApart.ts),\n // and a search reads those words too — \"Sunset\" finds the Patricia Marsh on Sunset Blvd.\n const apart = tellApart(rows ?? [], titleOf);\n // THE ONE RANKING (`rankTypedMatches`, grids review 3): the name ranks exact, starts with, a word\n // starts with, contains; the words that tell two apart only ever find a record.\n const visible = rankTypedMatches(rows ?? [], search, (row) => [titleOf(row.id), apart.get(row.id) ?? \"\"]);\n\n const anchored = autoOpen === true;\n const cellChips = picked.map((recordId) => (\n <RecordChip\n key={recordId}\n title={titleOf(recordId)}\n {...(disabled || anchored ? {} : { onRemove: () => toggle(recordId) })}\n />\n ));\n\n return (\n // Never wider than where it is drawn (a grid cell beside a sticky column: B3-07) — chips truncate, the button wraps.\n <div className={cn(\"flex min-w-0 max-w-full flex-wrap items-center gap-1\", className)}>\n {anchored && !disabled ? null : cellChips}\n {disabled ? null : (\n // THE ONE \"PICK OR ADD\" BUILDER (PickOrAdd.tsx) — the choice editor draws the same one.\n // In a grid cell it hangs from the cell's own chips; what is picked heads the list with its ×.\n <PickOrAdd\n anchored={anchored}\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n multi={field.multi}\n chips={picked.map((recordId) => ({ id: recordId, label: titleOf(recordId), onRemove: () => toggle(recordId) }))}\n triggerId={id}\n triggerLabel={`Pick for ${fieldName(field)}`}\n triggerText={picked.length === 0 ? \"Pick\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={setSearch}\n items={visible.map((row) => ({\n id: row.id,\n label: titleOf(row.id),\n detail: apart.get(row.id) ?? null,\n picked: picked.includes(row.id),\n title: apart.has(row.id) ? `${titleOf(row.id)} — ${apart.get(row.id)}` : titleOf(row.id),\n attrs: { \"data-relation-candidate\": row.id },\n }))}\n onPick={toggle}\n notice={\n <>\n {refusal ? <RefusalLine error={refusal} className=\"p-2\" /> : null}\n {!rows && !refusal ? <p className=\"p-2 text-xs text-muted-foreground\">Reading…</p> : null}\n {full ? (\n <p className=\"p-2 text-xs text-muted-foreground\">\n {fieldName(field)} can point at {field.relation_max} at most. Remove one to add another.\n </p>\n ) : null}\n </>\n }\n empty={rows ? <p className=\"p-2 text-xs text-muted-foreground\">Nothing in that table matches.</p> : null}\n add={\n allowCreate && !full && !targetRefusal && target && !creating\n ? {\n label: search.trim() !== \"\" ? `Create “${search.trim()}”` : `New ${targetWord}`,\n disabled: busy,\n // TYPED SOMETHING THAT IS NOT THERE? That IS the name. The champions\n // (Airtable, Notion) make the search text the new record's title in one\n // press; an empty box asks for one.\n onAdd: () => {\n if (search.trim() !== \"\") void create(search);\n else {\n setNewTitle(\"\");\n setCreating(true);\n }\n },\n }\n : null\n }\n foot={\n !allowCreate || full ? undefined : targetRefusal ? (\n <RefusalLine error={targetRefusal} className=\"p-2\" />\n ) : !target ? (\n <p className=\"p-2 text-xs text-muted-foreground\">Reading that table…</p>\n ) : creating ? (\n <div className=\"flex items-center gap-1 p-1\">\n <BasicInput\n autoFocus\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n void create(newTitle);\n }\n }}\n placeholder={`New ${targetWord}`}\n className=\"h-7 flex-1 text-xs\"\n aria-label={`Name the new ${targetWord}`}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"default\"\n disabled={busy || newTitle.trim() === \"\"}\n onClick={() => void create(newTitle)}\n >\n {busy ? \"Creating…\" : \"Create\"}\n </Button>\n </div>\n ) : undefined\n }\n footNote={\n allowCreate && !full && createRefusal ? (\n // The typed title is still in the search box: the notice owns the\n // two doors out (lane REFUSAL-SWEEP).\n <RefusalNotice\n error={createRefusal}\n className=\"mt-1 max-w-72\"\n onKeepEditing={() => setCreateRefusal(null)}\n onDiscard={() => {\n setCreateRefusal(null);\n setSearch(\"\");\n }}\n />\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n","\"use client\";\n\n// src/PickOrAdd.tsx — @ai-matrx/records-ui\n//\n// THE ONE \"PICK OR ADD\" BUILDER (lane STORE-RULE-GAPS, 2026-09-23).\n//\n// A button that opens a popover with a search box, the list of what can be picked, and — when\n// what was typed is not there — one line at the foot that makes it: Create “<typed>” for a\n// relation (a new record in the Table it points at), Add “<typed>” for a choice column that\n// takes other values (a new choice, added by the store as typed). The champions (Airtable,\n// Notion, Linear) end a picker's list with exactly that line, and they draw it the same way\n// everywhere, so this package draws it ONCE: `RelationPicker` and the open choice editor in\n// `editors.tsx` are both built from this, and neither carries a copy of the layout.\n//\n// What stays with the caller is what differs: which items there are, what picking one means,\n// what the add line says and does, and any state of its own above the list (a refusal, a\n// \"Reading…\", a ceiling) or at the foot (a name box, a refusal of the add).\n\nimport { useEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { PersonAvatar, PersonChip } from \"./personChip\";\nimport { BasicInput, Button, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ScrollArea, cn } from \"@ai-matrx/design-system\";\n\n/** What a list row and its chips need of a glyph: drawn in the text colour, never a font. */\nfunction Glyph({ d, className }: { d: string; className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={className}>\n <path d={d} />\n </svg>\n );\n}\nconst TICK = \"m5 12 4 4L19 6\";\nconst CROSS = \"M18 6 6 18M6 6l12 12\";\nconst PLUS = \"M12 5v14M5 12h14\";\n\nexport interface PickOrAddItem {\n id: string;\n label: string;\n /** A second line that tells two same-named items apart. */\n detail?: string | null | undefined;\n picked: boolean;\n /** The tooltip; defaults to the label. */\n title?: string | undefined;\n /**\n * The item drawn AS A CHIP in these classes — a choice in the colour its column keeps for it\n * (`choiceChipLookOf`), so the list reads the way the cell does. Absent: plain words.\n */\n chip?: string | undefined;\n /** Attributes a caller's tests and walks select by (e.g. `data-relation-candidate`). */\n attrs?: Record<string, string> | undefined;\n /** The row cannot be picked right now (a pick still being written). */\n disabled?: boolean | undefined;\n /** The row is a PERSON: their initials in a circle before the name (`personChip.tsx`). */\n person?: boolean | undefined;\n}\n\n/** A picked value, drawn at the head of the open list with its × (Airtable, Notion). */\nexport interface PickOrAddChip {\n id: string;\n label: string;\n /** The chip's colour classes (`choiceChipLookOf`); absent: the plain record chip. */\n chip?: string | undefined;\n /** Takes it off. Absent: the chip is shown and cannot be taken off here. */\n onRemove?: (() => void) | undefined;\n /** A PERSON: drawn as the person chip, never the record chip. */\n person?: boolean | undefined;\n}\n\nexport interface PickOrAddProps {\n /** The trigger's accessible name, e.g. \"Pick for Category\". */\n triggerLabel: string;\n /**\n * The trigger's height. \"field\" (the default) is the height of the text box beside it in a form\n * (WALK3-FIX, 2026-10-07: Pick/Choose sat 4px shorter than the date box in the same grid row);\n * \"compact\" keeps the small button a filter row or a chooser draws.\n */\n triggerSize?: \"field\" | \"compact\" | undefined;\n /** The trigger's visible word, e.g. \"Pick\", \"Change\", \"Choose\". */\n triggerText: string;\n triggerId?: string | undefined;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n search: string;\n onSearch: (search: string) => void;\n items: PickOrAddItem[];\n onPick: (id: string) => void;\n /** Above the list: a refusal, a \"Reading…\", a ceiling reached. */\n notice?: ReactNode;\n /** When the list is empty. */\n empty?: ReactNode;\n /** The add line at the foot. Absent = no add line. */\n add?: { label: string; onAdd: () => void; disabled?: boolean | undefined } | null | undefined;\n /** The foot's own state, drawn in place of the add line when there is one (a name box, a \"Reading that table…\"). */\n foot?: ReactNode;\n /** Under the add line: a refusal of the add, with its own doors. */\n footNote?: ReactNode;\n /**\n * ENTER WITH NOTHING TO PICK when the foot is the caller's own (a choice cell's Add / Keep as\n * typed / Cancel question): what the question's first answer does (grids review 3, 2026-09-30: a\n * new choice word + Enter did nothing, while Tab then Enter added it). Absent: the add line.\n */\n onEnterWithNoMatch?: (() => void) | undefined;\n /**\n * ESCAPE PUTS EVERYTHING BACK (REVIEW-FIX 2, 2026-10-06). In a grid cell closing the list is the\n * cell's commit, so Escape — which only closed it — wrote whatever the list held, a choice taken\n * off by Backspace included. When given, Escape (from the search box or Radix's own dismiss) calls\n * this INSTEAD of closing: the cell's cancel, which writes nothing and shows what it held.\n */\n onEscape?: (() => void) | undefined;\n /**\n * IN A GRID CELL (lane CELL-EDITORS, 2026-10-06). No trigger button is drawn: the list hangs from\n * `children` — what the cell already shows — the way Airtable's and the old Sheet's lists hang from\n * the cell. Elsewhere (a record form) the trigger button opens it.\n */\n anchored?: boolean | undefined;\n /** What the anchored cell shows under its open list (its chips). */\n children?: ReactNode;\n /** What is picked, at the head of the open list, each with its × (Backspace takes off the last). */\n chips?: PickOrAddChip[] | undefined;\n /**\n * SEVERAL CAN BE PICKED: a pick keeps the list open, and Enter on an empty search — before the\n * arrows chose a row — finishes (the old Sheet's B2-04: Enter used to toggle the first row forever).\n */\n multi?: boolean | undefined;\n}\n\n/**\n * THE LIST'S OWN KEYS (merged-grid review 2, 2026-09-27, A2 — Airtable / Linear / Notion). While a\n * picker is open it owns its keystrokes: the search box takes letters and Space, ArrowUp/ArrowDown\n * move the highlight, Enter picks the highlighted row, Escape closes. TAB IS NOT ITS KEY (lane\n * CELL-EDITORS): it goes on to the cell, which saves and moves to the next one, as in every grid —\n * and in a form it moves to the next question. No other key leaks into the grid or the page behind.\n */\nexport function useListKeys(args: {\n count: number;\n /** Changes whenever what the list shows changes (the search): the highlight goes back to the top. */\n resetOn: unknown;\n onPick: (index: number) => void;\n /** Enter with nothing to pick (no match): the add line, when there is one. */\n onNothing?: (() => void) | undefined;\n onClose: () => void;\n /** Enter before the arrows moved (a several-choice list with an empty search): finish. */\n onFinish?: (() => void) | undefined;\n /** Backspace on an empty search: take off the last picked one. */\n onBackspaceEmpty?: (() => void) | undefined;\n /** Whether the search box is empty (Backspace and the finishing Enter read it). */\n searchEmpty?: boolean | undefined;\n}) {\n const { count, resetOn, onPick, onNothing, onClose, onFinish, onBackspaceEmpty, searchEmpty } = args;\n const [highlight, setHighlight] = useState(0);\n /** The arrows (not the pointer) chose the row: Enter then picks it rather than finishing. */\n const [moved, setMoved] = useState(false);\n useEffect(() => {\n setHighlight(0);\n setMoved(false);\n }, [resetOn]);\n const at = count === 0 ? -1 : Math.min(highlight, count - 1);\n const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n // Tab belongs to the cell (save and move on) or the form (the next question).\n if (event.key === \"Tab\") return;\n // THE OPEN PICKER OWNS EVERY OTHER KEY: never the grid's shortcut, never the cell's Enter commit.\n event.stopPropagation();\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setMoved(true);\n if (count > 0) setHighlight((h) => (Math.min(h, count - 1) + 1) % count);\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setMoved(true);\n if (count > 0) setHighlight((h) => (Math.min(h, count - 1) - 1 + count) % count);\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n if (onFinish && searchEmpty && !moved) onFinish();\n else if (at >= 0) onPick(at);\n else onNothing?.();\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n onClose();\n } else if (event.key === \"Backspace\" && searchEmpty && onBackspaceEmpty) {\n event.preventDefault();\n onBackspaceEmpty();\n }\n };\n return { highlight: at, setHighlight, onKeyDown };\n}\n\n/** One row of an open list: a fill when highlighted (it follows the pointer), a tick when picked. */\nexport function PickRow({\n label,\n detail,\n title,\n chip,\n picked,\n highlighted,\n disabled,\n attrs,\n icon,\n person,\n onPick,\n onPoint,\n}: {\n label: string;\n detail?: string | null | undefined;\n title?: string | undefined;\n chip?: string | undefined;\n picked: boolean;\n highlighted: boolean;\n disabled?: boolean | undefined;\n attrs?: Record<string, string> | undefined;\n /** A glyph in the tick's place (the add line's +). */\n icon?: \"plus\" | undefined;\n /** A person row: their circle before the name. */\n person?: boolean | undefined;\n onPick: () => void;\n onPoint: () => void;\n}) {\n const ref = useRef<HTMLButtonElement | null>(null);\n // THE HIGHLIGHT IS ALWAYS IN VIEW: the arrows walk past the list's visible edge and it follows.\n useEffect(() => {\n if (highlighted) ref.current?.scrollIntoView?.({ block: \"nearest\" });\n }, [highlighted]);\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={picked}\n disabled={disabled ?? false}\n onClick={onPick}\n onMouseMove={onPoint}\n title={title ?? label}\n {...(attrs ?? {})}\n data-pick-highlighted={highlighted ? \"\" : undefined}\n className={cn(\n \"flex w-full min-w-0 items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:opacity-50\",\n highlighted ? \"bg-accent text-accent-foreground\" : \"\",\n )}\n >\n <span className=\"flex size-3.5 shrink-0 items-center justify-center\">\n {picked ? <span data-pick-tick=\"\" className=\"contents\"><Glyph d={TICK} className=\"size-3.5\" /></span> : null}\n {icon === \"plus\" ? <Glyph d={PLUS} className=\"size-3.5 text-muted-foreground\" /> : null}\n </span>\n {person ? <PersonAvatar name={label} size=\"md\" /> : null}\n <span className=\"min-w-0 flex-1\">\n {chip ? (\n <span className={cn(\"inline-flex max-w-full truncate rounded-md border px-1.5 py-0.5 text-xs font-medium\", chip)} data-records-choice-chip=\"\">\n {label}\n </span>\n ) : (\n <span className=\"block truncate\">{label}</span>\n )}\n {detail ? (\n <span className=\"block truncate text-xs text-muted-foreground\" data-tell-apart=\"\">\n {detail}\n </span>\n ) : null}\n </span>\n </button>\n );\n}\n\n/** What is picked, at the head of an open list: each a chip with its ×. */\nexport function PickChips({ chips }: { chips: PickOrAddChip[] }) {\n if (chips.length === 0) return null;\n return (\n <div className=\"flex flex-wrap gap-1 px-1 pb-1\" data-pick-chips=\"\">\n {chips.map((c) =>\n c.person ? (\n <PersonChip key={c.id} name={c.label} onRemove={c.onRemove} />\n ) : (\n <span\n key={c.id}\n data-pick-chip=\"\"\n title={c.label}\n className={cn(\n \"inline-flex max-w-full items-center gap-1 rounded-md border px-1.5 py-0.5 text-xs font-medium\",\n c.chip ?? \"bg-secondary text-secondary-foreground\",\n )}\n >\n <span className=\"min-w-0 truncate\">{c.label}</span>\n {c.onRemove ? (\n <button\n type=\"button\"\n aria-label={`Remove ${c.label}`}\n onClick={c.onRemove}\n className=\"shrink-0 rounded-sm opacity-60 hover:opacity-100\"\n >\n <Glyph d={CROSS} className=\"size-3\" />\n </button>\n ) : null}\n </span>\n ),\n )}\n </div>\n );\n}\n\nexport function PickOrAdd({\n triggerSize = \"field\",\n triggerLabel,\n triggerText,\n triggerId,\n open,\n onOpenChange,\n search,\n onSearch,\n items,\n onPick,\n notice,\n empty,\n add,\n foot,\n footNote,\n onEnterWithNoMatch,\n anchored,\n children,\n chips,\n multi,\n onEscape,\n}: PickOrAddProps) {\n // THE ADD LINE IS THE LIST'S LAST ROW (the old Sheet's \"Use / Add …\", Notion's \"Create\"): ranked\n // after every real match, so it never takes Enter from one, and the arrows reach it.\n const addRow = add && !foot ? add : null;\n const count = items.length + (addRow ? 1 : 0);\n /** Where the add row sits among the rows the keys walk: always after every item (one fixed spot). */\n const addAt = addRow ? items.length : -1;\n const itemAt = (index: number) => index;\n const removable = (chips ?? []).filter((c) => c.onRemove);\n const keys = useListKeys({\n count,\n resetOn: search,\n onPick: (index) => {\n if (index === addAt) {\n if (addRow && !addRow.disabled) addRow.onAdd();\n return;\n }\n const item = items[itemAt(index)];\n if (item && !item.disabled) onPick(item.id);\n },\n onNothing: onEnterWithNoMatch ?? (add && !add.disabled ? add.onAdd : undefined),\n onClose: () => (onEscape ? onEscape() : onOpenChange(false)),\n ...(multi ? { onFinish: () => onOpenChange(false) } : {}),\n ...(removable.length > 0 ? { onBackspaceEmpty: () => removable[removable.length - 1]?.onRemove?.() } : {}),\n searchEmpty: search === \"\",\n });\n const hasFoot = Boolean(foot) || Boolean(footNote);\n const addRowNode = addRow ? (\n <PickRow\n label={addRow.label}\n picked={false}\n icon=\"plus\"\n disabled={addRow.disabled}\n attrs={{ \"data-pick-add\": \"\" }}\n highlighted={addAt === keys.highlight}\n onPick={addRow.onAdd}\n onPoint={() => keys.setHighlight(addAt)}\n />\n ) : null;\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n {anchored ? (\n <PopoverAnchor asChild>\n <div data-pick-anchor=\"\" className=\"flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1\" aria-label={triggerLabel}>\n {children}\n </div>\n </PopoverAnchor>\n ) : (\n <PopoverTrigger asChild>\n <Button id={triggerId} type=\"button\" size=\"sm\" variant=\"outline\" className={triggerSize === \"field\" ? \"h-9\" : undefined} aria-label={triggerLabel}>\n {triggerText}\n </Button>\n </PopoverTrigger>\n )}\n {/*\n * NO WIDTH HERE. The one picker primitive asks the design system for CONTENT sizing\n * and the system decides how wide that is (lane FIX-14): a `w-64` pasted on one\n * surface is what cut `Create “Marisol Okonkwo — 418 Calle Pu` mid-word. Content sizing\n * is never narrower than what it hangs from, so in a cell it is at least the cell's width.\n */}\n <PopoverContent\n sizing=\"content\"\n padding=\"xs\"\n align=\"start\"\n side=\"bottom\"\n sideOffset={anchored ? 2 : 4}\n animated={false}\n data-matrx-cell-editor=\"\"\n // Every key inside the open list is the list's (see `useListKeys`) — except Tab.\n onKeyDown={(event) => {\n if (event.key !== \"Tab\") event.stopPropagation();\n }}\n // Radix dismisses on Escape before the search box hears it: a cell's Escape is its cancel.\n onEscapeKeyDown={(event) => {\n if (!onEscape) return;\n event.preventDefault();\n onEscape();\n }}\n // The cell keeps its own focus story; closing never throws focus back at a trigger.\n onCloseAutoFocus={(event) => {\n if (anchored) event.preventDefault();\n }}\n >\n {chips ? <PickChips chips={chips} /> : null}\n <BasicInput\n value={search}\n onChange={(e) => onSearch(e.target.value)}\n onKeyDown={keys.onKeyDown}\n placeholder=\"Search\"\n aria-label={`Search — ${triggerLabel}`}\n autoFocus\n autoComplete=\"off\"\n className=\"mb-1 h-8 text-sm\"\n />\n {notice}\n <ScrollArea className=\"max-h-64\">\n <div role=\"listbox\" aria-label={triggerLabel} aria-multiselectable={multi ? true : undefined}>\n {items.map((item, index) => (\n <PickRow\n key={item.id}\n label={item.label}\n detail={item.detail}\n title={item.title}\n chip={item.chip}\n picked={item.picked}\n disabled={item.disabled}\n attrs={item.attrs}\n person={item.person}\n highlighted={index === keys.highlight}\n onPick={() => onPick(item.id)}\n onPoint={() => keys.setHighlight(index)}\n />\n ))}\n {addRowNode}\n </div>\n {items.length === 0 && empty ? empty : null}\n </ScrollArea>\n {hasFoot ? (\n <div className=\"mt-1 border-t pt-1\">\n {foot}\n {footNote}\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\n// src/personChip.tsx — @ai-matrx/records-ui\n//\n// A PERSON LOOKS LIKE A PERSON (lane CELL-EDITORS, night walk 2026-10-06). A person cell's chip was the\n// same purple chip a link to a record wears, and the person list had no faces, so \"Dr. Maria Chen\" and\n// a linked \"Maria Chen — Rincon\" customer read the same. A person is a round pill with their initials in\n// a circle and their name — never the link chip — in the cell, at the head of the open list, on every\n// row of the list and on the record page. Notion and Airtable draw people this way.\n\nimport { cn } from \"@ai-matrx/design-system\";\n\n/** Up to two letters for a person's circle: the first letters of their first two words, or of an email. */\nexport function initialsOf(name: string): string {\n const words = name.replace(/@.*$/, \"\").split(/[\\s._-]+/).filter((w) => /\\p{L}|\\d/u.test(w));\n const letters = words\n .filter((w) => !/^(dr|mr|mrs|ms|prof)\\.?$/i.test(w))\n .slice(0, 2)\n .map((w) => (w.match(/[\\p{L}\\d]/u)?.[0] ?? \"\").toUpperCase());\n return letters.join(\"\") || \"?\";\n}\n\n/** The circle with a person's initials. */\nexport function PersonAvatar({ name, size = \"sm\" }: { name: string; size?: \"sm\" | \"md\" }) {\n return (\n <span\n aria-hidden=\"true\"\n data-records-person-avatar=\"\"\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded-full bg-foreground/10 font-medium text-foreground/80\",\n size === \"md\" ? \"size-5 text-[10px]\" : \"size-4 text-[9px]\",\n )}\n >\n {initialsOf(name)}\n </span>\n );\n}\n\n/** A person, as a cell, a list head and a record page show them: a round pill, their circle, their name. */\nexport function PersonChip({ name, onRemove, className }: { name: string; onRemove?: (() => void) | undefined; className?: string | undefined }) {\n return (\n <span\n data-records-person-chip=\"\"\n title={name}\n className={cn(\"inline-flex min-w-0 max-w-full items-center gap-1 rounded-full bg-muted py-0.5 pl-0.5 pr-2 text-[11px] text-foreground\", className)}\n >\n <PersonAvatar name={name} />\n <span className=\"min-w-0 truncate\">{name}</span>\n {onRemove ? (\n <button type=\"button\" onClick={onRemove} aria-label={`Remove ${name}`} className=\"shrink-0 opacity-60 hover:opacity-100\">\n ×\n </button>\n ) : null}\n </span>\n );\n}\n","\"use client\";\n\n// src/Refusal.tsx — @ai-matrx/records-ui\n//\n// THE ONE PLACE A REFUSAL IS SHOWN. It renders what `plainWords.ts` returns and\n// NOTHING ELSE — no `error.message`, no `error.hint`, no `error.sqlstate` in a\n// place a person reads. That is deliberate and it is the whole guard: a\n// formatter every screen has to go through is a formatter nobody bypasses, and\n// this component is the only door onto the screen a refusal has.\n//\n// The history, so it is not undone by accident. The fifth pass found the store's\n// HINT — written for whoever fixes the caller — printed at the person (\"FLD-11:\n// a lookup and a rollup both travel along a relation. config.via names a\n// relation Field of this same table, by its key.\"). The pass after it filtered\n// the hint and left the MESSAGE verbatim, on the reasonable grounds that the\n// store writes good messages. The sixth pass then found the machine identity\n// inside the MESSAGE — the access refusals are built by `format()` from the\n// door's own name — and printed at the person again, from the other half.\n//\n// So neither half is trusted by shape of ORIGIN any more. Both go through one\n// filter that judges by the shape of the TEXT, and what it drops is kept for an\n// engineer on the notice and in a screen-reader-only line, never deleted.\n\nimport type { ReactNode } from \"react\";\nimport type { RecordsError } from \"@ai-matrx/records\";\nimport { Alert, AlertDescription, AlertTitle, ErrorBox, cn } from \"@ai-matrx/design-system\";\n\nimport { isMachineIdentity, peopleHint, refusalForAPerson, refusalLineForAPerson } from \"./plainWords\";\n\n/**\n * Kept for callers outside this package that already ask the question. The\n * answer is `plainWords.ts`'s, so there is one shape list and not two.\n */\nexport function hintIsMachineIdentity(hint: string): boolean {\n return isMachineIdentity(hint);\n}\n\n/** The hint a PERSON should read, or null when it is written for an engineer. */\nexport function hintForAPerson(hint: string | null | undefined): string | null {\n const said = (hint ?? \"\").trim();\n if (said === \"\") return null;\n if (isMachineIdentity(said)) return null;\n return peopleHint(said) === null ? null : said;\n}\n\nexport function RefusalNotice({\n error,\n className,\n actions,\n onKeepEditing,\n onDiscard,\n}: {\n error: RecordsError;\n className?: string | undefined;\n actions?: ReactNode | undefined;\n /**\n * KEEP EDITING / DISCARD (lane REFUSAL-SWEEP, 2026-09-23). Pass these ONLY where\n * an editor is open holding what the person typed and the refusal is about that\n * text: the notice then owns the two doors out, so the notice — never a clock —\n * decides how long the typed text is kept. Keep editing hands the person back\n * to their text; Discard throws it away and puts back what was there. A surface\n * with nothing typed to keep passes neither and gets no buttons.\n */\n onKeepEditing?: (() => void) | undefined;\n onDiscard?: (() => void) | undefined;\n}) {\n const plain = refusalForAPerson(error);\n const doors =\n onKeepEditing || onDiscard ? (\n <div className=\"flex flex-wrap items-center gap-1 pt-0.5\" data-refusal-doors=\"\">\n {onKeepEditing ? (\n <button\n type=\"button\"\n data-refusal-keep-editing=\"\"\n className=\"rounded border px-2 py-0.5 text-xs hover:bg-muted\"\n onClick={onKeepEditing}\n >\n Keep editing\n </button>\n ) : null}\n {onDiscard ? (\n <button\n type=\"button\"\n data-refusal-discard=\"\"\n className=\"rounded border px-2 py-0.5 text-xs hover:bg-muted\"\n onClick={onDiscard}\n >\n Discard\n </button>\n ) : null}\n </div>\n ) : null;\n return (\n <Alert\n variant=\"destructive\"\n role=\"alert\"\n data-refusal-notice=\"\"\n className={cn(\"text-xs\", className)}\n // The host's error actions (copy for AI) get the store's own error — code,\n // SQLSTATE, hint — through the slot, never on the page (UI-FIX-19).\n errorFacts={{ message: plain.sentence, title: plain.title, error, origin: \"records-ui/RefusalNotice\" }}\n // 🚨 ENGINEER TEXT RIDES A DATA ATTRIBUTE, NEVER A TOOLTIP OR A HIDDEN LINE (UI-FIX-19,\n // VERIFIER-20 b). It was the notice's `title` and an `sr-only` paragraph: the Birchwood owner\n // hovering the refusal of her restore read \"SQLSTATE 23514. Hint: STORE-TAILS-3: …\", and a\n // copy of the page carried it. Whoever debugs it reads the attribute.\n {...(plain.forEngineers ? { \"data-for-engineers\": plain.forEngineers } : {})}\n {...(error.sqlstate ? { \"data-sqlstate\": error.sqlstate } : {})}\n >\n {/* THE STORE'S OWN SENTENCE IS THE HEADING when it gave one (UI-FIX-19): \"That value was not\n accepted\" over the real reason read as the reason. The generic title heads a notice only\n when nothing of the store's words survived. */}\n <AlertTitle className=\"text-xs font-medium\">{plain.storeSaid ? plain.sentence : plain.title}</AlertTitle>\n <AlertDescription className=\"space-y-1 text-xs\">\n {/* 🚨 A NOTICE NEVER SAYS THE SAME THING TWICE (lane LIMITS-FIX-UI, 2026-09-21).\n When every clause of the store's message was machine identity there is\n nothing of its own words left, and `refusalForAPerson` honestly falls back to\n the title — which this then printed AGAIN underneath it. A dental practice's\n owner read, on his own record: \"You do not have access to this. You do not\n have access to this. Ask somebody who administers this to share it with you\n at the level you need.\" Twice is not more true; it reads as a stutter, and it\n pushes the one useful line — the remedy — further down the box. */}\n {plain.storeSaid || plain.sentence.replace(/\\.$/, \"\") === plain.title ? null : <p>{plain.sentence}</p>}\n {/* NEVER A DEAD END: what happened, and then what to do about it. */}\n <p className=\"opacity-80\">{plain.remedy}</p>\n {actions}\n {doors}\n </AlertDescription>\n </Alert>\n );\n}\n\n/** A small inline one, for a cell or a field where a block would break the layout. */\nexport function RefusalLine({ error, className }: { error: RecordsError; className?: string | undefined }) {\n const plain = refusalForAPerson(error);\n return (\n <ErrorBox\n data-refusal-line=\"\"\n className={cn(\"text-xs text-destructive\", className)}\n message={refusalLineForAPerson(error)}\n error={error}\n origin=\"records-ui/RefusalLine\"\n // Engineer text on a data attribute, never a tooltip (UI-FIX-19).\n {...(plain.forEngineers ? { \"data-for-engineers\": plain.forEngineers } : {})}\n />\n );\n}\n","// src/plainWords.ts — @ai-matrx/records-ui\n//\n// THE ONE FORMATTER EVERY REFUSAL PASSES THROUGH.\n//\n// WHAT A PERSON READ (independent verdict, sixth pass, 19-20 September):\n//\n// \"You do not have access to this table, so custom.applicable_fields has\n// nothing to show you.\"\n// \"config.via names a relation Field of this same table, by its key… The\n// store's code for this was 23514.\"\n//\n// The verdict's third measured gap against Airtable, Notion and Linear was\n// exactly this: \"The machinery still shows through… two column types answer\n// with a contract row id and a SQL error number. Airtable, Notion and Linear\n// never show a person an internal name.\"\n//\n// WHY FILTERING THE HINT WAS NOT ENOUGH. The previous pass filtered the store's\n// HINT — the half written for whoever fixes the caller — and printed the\n// MESSAGE verbatim, because the store writes good messages. Most of them are\n// good. But the store's access refusals are built by `format()` from the DOOR'S\n// OWN NAME (`assert_client_may_change`: \"…so % may not write to it\", with the\n// door name substituted in), so the machine identity is IN the sentence a\n// person reads and no amount of hint-filtering reaches it.\n//\n// SO: ONE function, here, and every screen in this package renders what it\n// returns and nothing else. It does three things and refuses to do a fourth:\n//\n// 1. It KEEPS the store's own words wherever they are a person's words. The\n// store writes the best sentences in this feature (\"Being a member of the\n// organization is not by itself permission to rewrite somebody else's\n// row\") and this package does not rewrite them.\n// 2. It DROPS the clause that carries machine identity, by SHAPE — a\n// schema-qualified object, a document path, a contract row id, a SQLSTATE,\n// a uuid, a bare snake_case token. Dropped, never deleted: it joins the\n// SQLSTATE on the notice for whoever has to debug it.\n// 3. It ADDS a REMEDY — the sentence that says what to do now — keyed off the\n// store's own refusal code, because a refusal with nothing to do about it\n// is a dead end with an explanation.\n//\n// 4. It does NOT invent a diagnosis. When every clause of a message is\n// machine identity there is nothing honest left to say about the specifics,\n// so it says what happened in general terms and offers the remedy. Making\n// something up would be worse than the identifier it replaced.\n//\n// The guard for all of this is `demo/plain-words.test.tsx` plus the sweep in\n// `demo/honest.test.tsx`, which reads the RENDERED text of the real screens and\n// fails on any of the shapes below. A formatter nobody is forced through is a\n// formatter somebody bypasses next week.\n\nimport type { RecordsError } from \"@ai-matrx/records\";\n\n/**\n * MACHINE IDENTITY, BY SHAPE — never by a list of the sentences we happen to\n * have seen, because the next refusal is one nobody has read yet.\n *\n * `FLD-11:` / `REC-29:` / `AGT-7:` a contract row id\n * `custom.field_declare` a schema-qualified database object\n * `config.via` / `data.fields` a path inside a stored document\n * `retention_days` a document key, snake_case\n * `8f2c1b0a-…` a uuid\n * `23514` / `PT409` a SQLSTATE\n * `STORE-TAILS-3:` / `UI-FIX-19:` a build lane's tag (UI-FIX-19)\n */\nexport const MACHINE_IDENTITY: RegExp[] = [\n /\\b[A-Z]{2,4}-\\d{1,3}\\b/,\n // A build lane's tag: capital words joined by hyphens, then a colon (\"STORE-TAILS-3:\",\n // \"MOVE-AND-OUTSIDER:\"). A person never reads which lane wrote a sentence.\n /\\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+:/,\n /\\b(?:custom|platform|iam|history|public|auth|campaign_watch)\\.[a-z_]+/,\n /\\b(?:config|data|document|spec|patch)\\.[a-z_]+/,\n /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/i,\n /\\b[a-z][a-z0-9]*(?:_[a-z0-9]+)+\\b/,\n // Five characters of digits and capitals, at least one a digit — so `23514`\n // and `PT409` match and an emphatic `NEVER` does not.\n /\\b(?=[0-9A-Z]{5}\\b)(?=[0-9A-Z]*\\d)[0-9A-Z]{5}\\b/,\n];\n\n/** Whether any shape above appears in this text. */\nexport function isMachineIdentity(text: string): boolean {\n return MACHINE_IDENTITY.some((shape) => shape.test(text));\n}\n\n/**\n * Every fragment of `text` that a person should never have been shown. Used by\n * the suite to say WHAT it found rather than only that it found something.\n */\nexport function machineIdentityIn(text: string): string[] {\n const found: string[] = [];\n for (const shape of MACHINE_IDENTITY) {\n const all = new RegExp(shape.source, shape.flags.includes(\"g\") ? shape.flags : `${shape.flags}g`);\n for (const hit of text.matchAll(all)) if (hit[0]) found.push(hit[0]);\n }\n return [...new Set(found)];\n}\n\n/** What the notice is called. The store's code, in the words of what went wrong. */\nconst TITLE: Record<string, string> = {\n stale_write: \"Someone else wrote first\",\n door: \"You do not have access to this\",\n door_absent: \"That is not built yet\",\n refused_by_rule: \"That value was not accepted\",\n invalid_argument: \"That was not accepted\",\n not_found: \"Not there any more\",\n missing_reference: \"That points at something that is not there\",\n already_exists: \"That already exists\",\n not_supported: \"That cannot be done here\",\n store_limit: \"This has got as big as it can\",\n // 🚨 NOT \"THE SWITCH IS OFF\" (lane 7 W1 fix round 1). PGRST202 / PGRST205 land here, and the\n // commonest cause is a door this screen asks for that the database it talks to does not serve\n // YET — a release in flight. Telling the person her organization has its store switched off was\n // false (the switch is answered by its own door, `platform.unified_data_store_on`). Honest:\n // nothing happened, and it is ours, and it passes.\n store_not_served: \"This isn't available right now\",\n unreachable: \"We could not reach your data\",\n needs_approval: \"This is waiting on someone's approval\",\n stale_read: \"Your view of this is a moment behind\",\n timed_out: \"That took too long to answer\",\n internal: \"Something went wrong at our end\",\n};\n\n/**\n * WHAT TO DO NOW. One sentence per refusal code, and it is the whole reason\n * this file exists rather than a regular expression in `Refusal.tsx`: a\n * sentence that names what went wrong and nothing to do about it is a dead end.\n */\nconst REMEDY: Record<string, string> = {\n stale_write:\n \"Look at what they wrote. Keep theirs, or try again and yours goes on top.\",\n door:\n \"Ask somebody who administers this to share it with you at the level you need.\",\n door_absent:\n \"There is nothing to do here yet. It is on our list, not yours.\",\n refused_by_rule: \"Change the value so it passes, then try again.\",\n invalid_argument: \"Change what you entered, then try again.\",\n not_found:\n \"It may have been deleted. Go back to the list and open it again from there.\",\n missing_reference: \"Pick something that is still there.\",\n already_exists: \"Use a different name.\",\n not_supported: \"There is another way to do this — ask, and we will point you at it.\",\n store_limit: \"Split it up, or ask us to raise the ceiling for your organization.\",\n store_not_served: \"Nothing was changed. Try again in a few minutes.\",\n // 🚨 NOTHING WAS WRITTEN AND NOTHING WAS REFUSED (lane TAILS-6). The call\n // never arrived, so \"try again\" is the honest instruction rather than a\n // consolation — and saying nothing changed is the half a person actually\n // worries about.\n unreachable:\n \"Nothing was changed. Check your connection and open this again.\",\n needs_approval:\n \"Nothing was changed yet. The people who can approve it have been asked.\",\n stale_read: \"Open this again in a moment and it will be up to date.\",\n // 🚨 ONE REMEDY THAT IS TRUE OF EVERY DOOR (lane CHAIR-STORE-PERF, 2026-10-03). The store cancels the\n // WHOLE statement at its clock, so a timed-out door wrote nothing — a create, a column add and a page\n // read alike. \"Try a smaller page\" was written for the page read and was printed to a person adding\n // one row to a three-row table (clone walk, 2026-10-03; the clock was a lock another lane's\n // rehearsal held, not the row). A door whose page can shrink says so in its own hint, which wins here.\n timed_out: \"Nothing was changed. Try again in a moment.\",\n internal:\n \"Nothing you did caused this. Try again, and tell us if it keeps happening.\",\n};\n\n/**\n * 🚨 A HINT THIS PACKAGE OR ITS CLIENT WROTE IS NOT A PERSON'S REMEDY.\n *\n * `refusalForAPerson` prefers the DOOR's own hint over the table above, because\n * the door that refused knows more about the way out than a code does. That is\n * right — but it assumed every hint came from the store. It did not: until\n * `@ai-matrx/records` 0.47.0 the client appended its OWN note to `hint` when it\n * met a SQLSTATE it did not know, and the machine-identity filter let it\n * through whenever the code was not exactly five characters (an empty code from\n * a dropped connection, or an HTTP status like `404`). So the Checklists tab of\n * a plumbing company's jobs table told its owner:\n *\n * @ai-matrx/records did not recognise SQLSTATE from checklistTemplates\n *\n * The client no longer writes there. This is the guard on the other side, by\n * SHAPE and not by that one sentence: a hint that talks about a package, a\n * SQLSTATE, or a `camelCaseDoor` is engineer text wherever it came from, and it\n * joins the engineer's line instead of a person's screen.\n */\nexport const ENGINEER_TEXT: RegExp[] = [\n /@ai-matrx\\//,\n /\\bSQLSTATE\\b/i,\n /\\bPostgREST\\b/i,\n /\\bIndexedDB\\b/i,\n // `<RecordsUiProvider>` — a component, on a screen.\n /<\\/?[A-Z][A-Za-z0-9]*\\s*\\/?>/,\n // `savedViews`, `openRecords`, `onReask` — an identifier, however it is\n // quoted. English does not write camelCase; code does.\n /\\b[a-z][a-z0-9]*[A-Z][A-Za-z0-9]*\\b/,\n // A backticked token is a thing you type into an editor, not a thing you do.\n /`[A-Za-z_][A-Za-z0-9_.]*`/,\n // \"bind X on Y\", \"pass X\", \"import X\" — an instruction to whoever maintains\n // the app, arriving on the screen of somebody who cannot act on it.\n /\\bbind\\s+[`'\"A-Za-z]/i,\n];\n\n/**\n * THE ONE GUARD ON A DOOR'S HINT. True when the hint is developer text and must never be\n * printed at a person: engineer shapes (package, SQLSTATE, component, camelCase, backticked\n * token), a code fence, stack-like lines, or a block too long to be one remedy (over 600).\n * Machine clauses INSIDE an otherwise plain hint are cut by `plainSentence`, not by this.\n */\nexport function isDeveloperHint(hint: string): boolean {\n const text = hint.trim();\n if (text === \"\") return false;\n if (text.includes(\"```\")) return true;\n if (/\\n\\s+at\\s+\\S+/.test(text)) return true;\n if (text.length > 600) return true;\n return isEngineerText(text);\n}\n\n/** The hint a person may read: cleaned to people's sentences, or null. The one place that decides. */\nexport function peopleHint(hint: string | null | undefined): string | null {\n const said = (hint ?? \"\").trim();\n if (said === \"\" || isDeveloperHint(said)) return null;\n return plainSentence(said).kept;\n}\n\n/** Whether this sentence was written for whoever maintains the code. */\nexport function isEngineerText(text: string): boolean {\n return ENGINEER_TEXT.some((shape) => shape.test(text));\n}\n\n/** The one shape every screen in this package renders a refusal from. */\nexport interface PlainRefusal {\n /** The heading. Never the store's code. */\n title: string;\n /**\n * What happened, in the store's own words where they are a person's words\n * and in ours where they are not. Never empty.\n */\n sentence: string;\n /** What to do now. Never empty. */\n remedy: string;\n /**\n * TRUE when `sentence` is the store's own words (UI-FIX-19): a notice is then HEADED by that\n * sentence, never by the generic `title` over it.\n */\n storeSaid: boolean;\n /**\n * Everything a person should not read, kept for whoever has to debug it: the\n * SQLSTATE, the hint written for a caller, and any clause dropped above.\n * Kept on the notice's `data-for-engineers` attribute only (UI-FIX-19): never a\n * tooltip, never text a screen can copy or read aloud; never deleted.\n */\n forEngineers: string;\n}\n\n/**\n * A sentence with its machine clauses taken out — or null when nothing honest\n * is left. Clauses are split on the joins the store's own `format()` templates\n * use (\"…, so custom.x may not write to it\", \"… — FLD-11: …\").\n */\nfunction withoutMachineClauses(sentence: string): { kept: string | null; dropped: string[] } {\n const dropped: string[] = [];\n // 🚨 A PARENTHETICAL ID IS EXCISED, NOT A REASON TO BIN THE SENTENCE AROUND IT\n // (lane LIMITS-FIX-UI, 2026-09-21). The store's own way out for a colleague who\n // is not in the organization — \"Invite them to the organization, share with\n // their organization instead (VIS-23), or, if they are a client rather than a\n // colleague, put them in a portal\" — was thrown away WHOLE because of those\n // eight characters, so a plumbing company trying to show one customer her own\n // jobs was told nothing at all about what to do instead. A contract id in\n // brackets is a footnote: lift it out and the sentence around it is a person's\n // sentence. It is still kept for the engineer, below.\n const footnotes: string[] = [];\n const withoutFootnotes = sentence.replace(/\\s*\\((?:see\\s+)?[A-Z]{2,5}-[A-Z0-9-]{1,8}\\)/g, (hit) => {\n footnotes.push(hit.trim());\n return \"\";\n });\n dropped.push(...footnotes);\n const clauses = withoutFootnotes\n .split(/(?:,\\s+so\\s+|\\s+—\\s+|\\s+--\\s+|\\s*\\|\\s*)/)\n .map((clause) => clause.trim())\n .filter((clause) => clause !== \"\");\n const kept = clauses.filter((clause) => {\n if (!isMachineIdentity(clause)) return true;\n dropped.push(clause);\n return false;\n });\n if (kept.length === 0) return { kept: null, dropped };\n // 🚨 A CLEANER THAT DROPPED NOTHING CHANGES NOTHING (same lane, same day).\n //\n // The split above is on the joins the store's `format()` templates use, and\n // \", so \" is one of them — which is also how ordinary English joins two\n // clauses. So \"That person is not in this organization, so they cannot be\n // given access to this table yet.\" came back out as \"That person is not in\n // this organization. they cannot be given access to this table yet.\" — a\n // sentence nobody wrote, with a lower-case word after a full stop, shown to\n // every person every time. Nothing was dropped from it; there was nothing to\n // clean. When that is true the sentence is returned exactly as the store wrote\n // it, and this function's re-joining only ever runs on a sentence it actually\n // took something out of.\n if (dropped.length === 0) return { kept: sentence.trim(), dropped };\n let joined = kept.join(\". \").replace(/\\.\\.+/g, \".\").trim();\n if (!/[.!?]$/.test(joined)) joined = `${joined}.`;\n return { kept: joined, dropped };\n}\n\n/**\n * THE PEOPLE-FACING SENTENCE OF A STORE MESSAGE, AND NOTHING AFTER IT (lane\n * RECORDS-UI-REFUSAL-TEXT, 2026-10-01). A refusal's message is one plain sentence,\n * then ` — ` and developer detail, or a second sentence written for whoever fixes the\n * caller. A person reads the first sentence only; the rest rides `forEngineers`.\n */\nfunction peopleSentence(message: string): { kept: string | null; dropped: string[] } {\n const [lead = \"\", ...tail] = message.split(/\\s+—\\s+|\\s+--\\s+/);\n // A full stop after an abbreviation or an initial (\"Ask Dr. Whitfield\", \"e.g. a quote\") is not an end.\n const sentences = lead.trim().split(/(?<=(?<!\\b(?:Dr|Mr|Mrs|Ms|St|vs|No|e\\.g|i\\.e|etc|[A-Z]))[.!?])\\s+/);\n const first = sentences[0] ?? \"\";\n const rest = [...sentences.slice(1), ...tail].map((part) => part.trim()).filter((part) => part !== \"\");\n const cleaned = plainSentence(first);\n return { kept: cleaned.kept, dropped: [...cleaned.dropped, ...rest] };\n}\n\n/**\n * THE ONE SENTENCE A PERSON READS FOR A REFUSAL — the store's first sentence, or the\n * title when nothing of it is a person's words. Never the hint, details, code or\n * SQLSTATE. Every place that needs a refusal as a string (a toast, a cell, a banner)\n * calls this and nothing else; `check:records-ui-refusal-text` fails on a raw\n * `error.message` / `error.hint` render anywhere else.\n */\nexport function refusalSentence(error: Pick<RecordsError, \"message\"> & Partial<RecordsError>): string {\n return refusalForAPerson(error as RecordsError).sentence;\n}\n\n/** Every sentence of a message, cleaned; the ones that cannot be cleaned are dropped. */\nfunction plainSentence(message: string): { kept: string | null; dropped: string[] } {\n const dropped: string[] = [];\n const kept: string[] = [];\n for (const raw of message.split(/(?<=[.!?])\\s+/)) {\n const sentence = raw.trim();\n if (sentence === \"\") continue;\n const cleaned = withoutMachineClauses(sentence);\n dropped.push(...cleaned.dropped);\n if (cleaned.kept) kept.push(cleaned.kept);\n }\n return { kept: kept.length === 0 ? null : kept.join(\" \"), dropped };\n}\n\n/** The example a pattern refusal carries in its detail, when it carries one. */\nfunction exampleOf(error: RecordsError): string | null {\n const detail = (error as { detail?: unknown }).detail;\n if (!detail || typeof detail !== \"object\") return null;\n const example = (detail as { example?: unknown }).example;\n return typeof example === \"string\" && example.trim() !== \"\" ? example.trim() : null;\n}\n\n/**\n * THE FORMATTER. Every refusal a screen in this package shows goes through\n * here, and nothing in this package renders `error.message` directly.\n */\nexport function refusalForAPerson(error: RecordsError): PlainRefusal {\n const code = error.code ?? \"internal\";\n // A refusal THIS package wrote (`refusals.ts` marks it `ours`) is whole people-facing prose, a\n // count then a reason; only a door's message is cut after its first sentence.\n const ours = (error as { ours?: unknown }).ours === true;\n const hint = plainSentence(String(error.hint ?? \"\"));\n const message = ours ? plainSentence(String(error.message ?? \"\")) : peopleSentence(String(error.message ?? \"\"));\n\n const title = TITLE[code] ?? \"The store refused this\";\n\n // 🚨 ONE REMEDY, AND IT IS THE DOOR'S OWN WHEN THE DOOR HAS ONE (lane\n // LIMITS-FIX-UI, 2026-09-21).\n //\n // The table below is a FALLBACK, not an answer. `custom.share_grant` refuses a\n // colleague who is not in the organization with its own three ways forward —\n // *\"Invite them to the organization, share with their organization instead, or,\n // if they are a client rather than a colleague, put them in a portal\"* — and\n // this formatter used to print that AND then \"Change the value so it passes,\n // then try again\", which is not a thing anybody can do about a membership. Two\n // remedies, one of them wrong, is worse than one: a person follows the last\n // sentence they read. The door that refused knows more about the way out than\n // a table keyed on a code does, so its hint wins whenever it survived the\n // machine-identity filter, and the table answers when it did not.\n // 🚨 THE DOOR'S HINT IS THE REMEDY WHEN IT READS AS A PERSON'S SENTENCE (chair ruling,\n // 2026-10-01, restoring the 2026-09-21 one-remedy ruling). A hint that is developer text (a\n // SQL state, a snake_case name, a uuid, a code fence, a stack, a package or component name)\n // is never printed: it rides `forEngineers` and the code's table sentence is the remedy.\n const hintIsForEngineers = isDeveloperHint(String(error.hint ?? \"\"));\n // STORE-RULE-GAPS: a pattern that carries an example hands it over as DATA\n // (`detail.example`), because an example is the person's own shape of value.\n const example = exampleOf(error);\n const remedy =\n (example ? `Enter it like ${example}.` : null) ??\n (hintIsForEngineers ? null : hint.kept) ??\n REMEDY[code] ??\n REMEDY[\"internal\"]!;\n\n // The store's own sentence for what happened. Its hint is the REMEDY above\n // rather than more of this, so the two halves never say the same thing twice.\n // A STORE MESSAGE IS NEVER ENGINEER TEXT; a stand-in written by a client can\n // be, and a person must not read it. It still reaches the engineer's line.\n const messageIsForEngineers = isEngineerText(String(error.message ?? \"\"));\n const said = (messageIsForEngineers ? \"\" : (message.kept ?? \"\")).trim();\n\n const forEngineers = [\n error.sqlstate ? `SQLSTATE ${error.sqlstate}.` : null,\n // The client's own note about a class it did not recognise, or a call that\n // never reached the store. It is rendered out of sight, never as a sentence.\n error.diagnostic ? error.diagnostic : null,\n messageIsForEngineers ? `Message: ${error.message}` : null,\n error.hint && (hintIsForEngineers || hint.kept !== error.hint) ? `Hint: ${error.hint}` : null,\n message.dropped.length > 0 || hint.dropped.length > 0\n ? `Dropped from the person's view: ${[...message.dropped, ...hint.dropped].join(\" | \")}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return {\n title,\n // Nothing invented. When every clause was machine identity the title says\n // what happened and the remedy says what to do; a made-up diagnosis would\n // be worse than the identifier it replaced.\n sentence: said === \"\" ? `${title}.` : said,\n remedy,\n storeSaid: said !== \"\",\n forEngineers,\n };\n}\n\n/**\n * The same answer as one line, for a cell or a field where a block would break\n * the layout. Still one sentence and one remedy — never the sentence alone,\n * because half of this formatter's job is the thing to do next.\n */\nexport function refusalLineForAPerson(error: RecordsError): string {\n const plain = refusalForAPerson(error);\n // TWO SENTENCES, NOT ONE RUN-ON (VERIFIER-15/16): the store's rule message has no\n // full stop (\"Pressure (psi) has to be at least 0\"), and joining it to the remedy\n // read \"…at least 0 Send this column somewhere else\". A line ends its sentence.\n const sentence = plain.sentence.trim();\n const ended = sentence === \"\" || /[.!?…:]$/.test(sentence) ? sentence : `${sentence}.`;\n return `${ended} ${plain.remedy}`.trim();\n}\n","// src/refusals.ts — @ai-matrx/records-ui\n//\n// THE ONE BUILDER FOR A REFUSAL THIS PACKAGE WRITES ITSELF (lane REFUSAL-SWEEP,\n// 2026-09-23).\n//\n// `RefusalNotice` takes a `RecordsError`, and the store's own refusals arrive as\n// one. But twenty-six places in this package refused something IN THE BROWSER —\n// an answer not filled in, a file the browser could not read, a spreadsheet that\n// could not be written, a picker that could not list its choices — and each of\n// them held a bare string and printed it in red: no heading, no remedy, and in\n// five of them the store's `error.message` verbatim, straight past the\n// machine-identity filter every other screen goes through.\n//\n// So a refusal this package writes is built HERE, as the same object the store\n// hands back, and drawn by the same `RefusalNotice`. A person cannot tell which\n// half of the system said no and has no reason to care; `plainWords.ts` still\n// judges the sentence by shape, and the remedy is the one THIS call site knows\n// (the hint wins over the code's generic remedy — see `refusalForAPerson`).\n\nimport type { RecordsError, RecordsErrorCode } from \"@ai-matrx/records\";\n\n/**\n * A refusal in this package's own words.\n *\n * @param code what KIND of refusal — picks the notice's title and its fallback remedy.\n * @param sentence what happened, for a person.\n * @param remedy what to do now, when this call site knows better than the code's default.\n * @param diagnostic an engineer's note (a thrown message, a status) — rendered out of sight.\n */\nexport function refusal(\n code: RecordsErrorCode,\n sentence: string,\n remedy?: string | null,\n diagnostic?: string | null,\n): RecordsError {\n return {\n code,\n message: sentence,\n ours: true,\n ...(remedy ? { hint: remedy } : {}),\n ...(diagnostic ? { diagnostic } : {}),\n } as RecordsError;\n}\n\n/**\n * A refusal made from something THROWN in the browser. The thrown text is an\n * engineer's (a parser's \"Unexpected token } in JSON at position 14\", a\n * library's stack) and goes out of sight; the person reads `sentence`.\n */\nexport function refusalFromThrown(\n thrown: unknown,\n sentence: string,\n remedy?: string | null,\n code: RecordsErrorCode = \"internal\",\n): RecordsError {\n const said = thrown instanceof Error ? thrown.message : String(thrown ?? \"\");\n return refusal(code, sentence, remedy, said ? `Thrown: ${said}` : null);\n}\n\n/**\n * The store's refusal when there is one, otherwise this package's own sentence —\n * for the call sites whose answer MAY carry an error (`res.error?.message ?? \"…\"`\n * was the old shape, and it printed the store's message raw).\n */\nexport function refusalOr(error: RecordsError | null | undefined, code: RecordsErrorCode, sentence: string): RecordsError {\n return error ?? refusal(code, sentence);\n}\n\n/**\n * Whatever a host callback threw, as a refusal: the store's own `RecordsError`\n * when that is what arrived (it is drawn with its own words and remedy), and\n * otherwise `refusalFromThrown` — the thrown text out of sight, `sentence` in view.\n */\nexport function asRefusal(\n thrown: unknown,\n sentence: string,\n remedy?: string | null,\n code: RecordsErrorCode = \"internal\",\n): RecordsError {\n const t = thrown as Partial<RecordsError> | null | undefined;\n if (t && typeof t === \"object\" && typeof t.code === \"string\" && typeof t.message === \"string\" && !(thrown instanceof Error)) {\n return t as RecordsError;\n }\n return refusalFromThrown(thrown, sentence, remedy, code);\n}\n","// src/tellApart.ts — @ai-matrx/records-ui · lane RECORDS-UI-FIX (2026-09-23)\n//\n// TWO RECORDS WITH ONE NAME ARE TOLD APART, NEVER LISTED AS TWINS.\n//\n// 🚨 WHAT A PERSON MET (guide re-walk, VERIFIER-15/16 LOW): Rincon's linked-record\n// picker listed Patricia Marsh, Robert Marsh, Maria Chen \"and the rest\" twice each.\n// They are not duplicates: Rincon's Customers table holds two Patricia Marshes — 156\n// Willow Way and 261 Sunset Blvd — and the picker drew only the name, so a dispatcher\n// could not tell which one she was attaching to a job. Airtable's record picker shows\n// the record's other fields for exactly this reason.\n//\n// So when names collide, each colliding row gets ONE short line from its own document:\n// the first column whose values differ across the rows that share the name (an\n// address, a phone), and a second one only when the first still leaves two alike.\n// A name nobody else holds gets nothing — the list stays a list of names.\n\nimport type { ReadRow } from \"@ai-matrx/records\";\n\nfunction shown(value: unknown): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") return value.trim() === \"\" ? null : value.trim();\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return null;\n}\n\n/** For every row whose name another row also has: the words that tell it apart. */\nexport function tellApart(rows: ReadRow[], nameOf: (id: string) => string): Map<string, string> {\n const byName = new Map<string, ReadRow[]>();\n for (const row of rows) {\n const name = nameOf(row.id).trim().toLowerCase();\n byName.set(name, [...(byName.get(name) ?? []), row]);\n }\n const out = new Map<string, string>();\n for (const [name, group] of byName) {\n if (group.length < 2) continue;\n const keys = [\n ...new Set(\n group.flatMap((row) =>\n Object.keys(row.document ?? {}).filter((k) => !k.startsWith(\"_\") && shown(row.document?.[k]) !== null),\n ),\n ),\n ].filter((k) => group.some((row) => (shown(row.document?.[k]) ?? \"\").toLowerCase() !== name));\n const valuesOf = (k: string) => group.map((row) => shown(row.document?.[k]) ?? \"\");\n const differs = keys.filter((k) => new Set(valuesOf(k)).size > 1);\n const whole = differs.find((k) => new Set(valuesOf(k)).size === group.length);\n const chosen = whole ? [whole] : differs.slice(0, 2);\n if (chosen.length === 0) continue;\n for (const row of group) {\n const words = chosen.map((k) => shown(row.document?.[k])).filter((w): w is string => w !== null);\n if (words.length > 0) out.set(row.id, words.join(\" · \"));\n }\n }\n return out;\n}\n","\"use client\";\n\n// src/gridAttachments.tsx — @ai-matrx/records-ui · one-grid merge, host port `pickFiles`\n//\n// A FILE COLUMN: ITS CHIPS, AND HOW A FILE GETS INTO IT.\n//\n// An attachment column is a relation to the kernel File Table (REC-31). The store turns the id a\n// writer actually holds — a file from the host's file service — into that File record at every\n// write door (`custom.relation_kernel_record`), and the File record keeps the host's file id in\n// its own document (`file_id`). So:\n// · A CHIP names the File record and opens the host's page for its file (`hrefForFile`). Unbound,\n// the chip is plain words that say the file cannot be opened here — never a dead link.\n// · THE EDITOR adds files through the host's own file window (`pickFiles`, Airtable's \"Attach\"\n// over the person's own files) and/or a fresh upload (`upload`). Whatever the host returns is\n// written as the cell's value through the grid's one-cell write, so the store's attachment door\n// decides and refuses in its own words. With neither port bound the editor offers no chooser\n// at all and says so (`NO_UPLOAD_REASON`) — absent or honest, never dead.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Field, RecordDocument, Uuid } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { Badge, Button } from \"@ai-matrx/design-system\";\n\nimport { NO_UPLOAD_REASON, useRecordsUi } from \"./host\";\nimport { idsOf } from \"./labels\";\nimport { fieldName } from \"./names\";\nimport { FilePicker } from \"./FilePicker\";\nimport { RefusalLine } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** The ids an attachment cell holds, in order: File record ids (or a host file id not yet written). */\nexport function attachmentIdsOf(value: unknown): string[] {\n return idsOf(value);\n}\n\n/** What an attachment cell writes after adding `added` to what it holds. */\nexport function withAttached(field: Field, value: unknown, added: readonly string[]): unknown {\n const held = attachmentIdsOf(value);\n if (!field.multi) return added.length > 0 ? added[added.length - 1]! : (held[0] ?? null);\n const next = [...held];\n for (const id of added) if (!next.includes(id)) next.push(id);\n return next.length > 0 ? next : null;\n}\n\n/** What an attachment cell writes after taking `removed` out. */\nexport function withoutAttached(field: Field, value: unknown, removed: string): unknown {\n const next = attachmentIdsOf(value).filter((id) => id !== removed);\n if (!field.multi) return next[0] ?? null;\n return next.length > 0 ? next : null;\n}\n\n/**\n * THE APP'S FILE IDS THIS SCREEN WAS JUST HANDED (merged-grid review 2, fix lane F item 4). A cell\n * holds File record ids, but right after \"Attach files…\" / an upload it briefly holds the host's own\n * file ids — the store turns each into its File record at the write door. A chip must not ask the\n * record door about those (every attach logged a 403 \"You do not have access to this record\"): it\n * opens them as the host's files. Filled by the editor below; ids live for the page's lifetime.\n */\nconst handedHostFileIds = new Set<string>();\n\n/** Remember ids the host handed back as ITS file ids (`pickFiles`, `upload`). */\nexport function rememberHostFileIds(ids: readonly string[]): void {\n for (const id of ids) handedHostFileIds.add(id);\n}\n\n/** The words a chip reads while (or when) a File record cannot be read. */\nexport const FILE_CHIP_UNREAD = \"File\";\n/** A chip's hover when the host has no page for files. */\nexport const FILE_CHIP_NO_PAGE = \"This screen has no way to open files yet.\";\n\n/**\n * ONE FILE: the File record's own name, opening the host's page for its file. A File record the\n * reader may not open reads the store's refusal on hover, never a guessed name.\n */\nexport function AttachmentChip({ id, onRemove }: { id: string; onRemove?: (() => void) | undefined }) {\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [read, setRead] = useState<{ name: string | null; fileId: string | null; why: string | null } | null>(null);\n useEffect(() => {\n let cancelled = false;\n if (!client) {\n setRead({ name: null, fileId: null, why: null });\n return;\n }\n if (handedHostFileIds.has(id)) {\n // The host's own file id, not a File record yet: it opens as itself, and nobody asks the\n // record door about an id that is not a record.\n setRead({ name: null, fileId: id, why: null });\n return;\n }\n void client.recordRead({ record_id: id as Uuid }).then((answered) => {\n if (cancelled) return;\n if (!answered.ok) {\n // Not a File record (yet): a host file id written a moment ago opens as itself.\n setRead({ name: null, fileId: id, why: refusalSentence(answered.error) });\n return;\n }\n const doc = (answered.data.document ?? {}) as RecordDocument;\n const fileId = typeof doc[\"file_id\"] === \"string\" ? (doc[\"file_id\"] as string) : null;\n const name = typeof doc[\"name\"] === \"string\" && doc[\"name\"] !== \"\" ? (doc[\"name\"] as string) : null;\n setRead({ name, fileId, why: null });\n });\n return () => {\n cancelled = true;\n };\n }, [client, id]);\n\n const words = read?.name ?? (read ? FILE_CHIP_UNREAD : \"…\");\n const href = read?.fileId ? host.hrefForFile?.({ fileId: read.fileId as Uuid }) : undefined;\n const title = href ? `Open ${words}` : read?.why ?? FILE_CHIP_NO_PAGE;\n return (\n <Badge variant=\"secondary\" className=\"max-w-[14rem] gap-1 text-[11px]\" data-records-file-chip={id} title={title}>\n {href ? (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"truncate underline-offset-2 hover:underline\"\n data-records-file-link={read?.fileId ?? \"\"}\n onClick={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n >\n {words}\n </a>\n ) : (\n <span className=\"truncate\">{words}</span>\n )}\n {onRemove ? (\n <button\n type=\"button\"\n aria-label={`Remove ${words}`}\n className=\"shrink-0 rounded px-0.5 text-muted-foreground hover:text-foreground\"\n onClick={(event) => {\n event.stopPropagation();\n onRemove();\n }}\n >\n ×\n </button>\n ) : null}\n </Badge>\n );\n}\n\n/** Every file a cell holds, as chips. */\nexport function AttachmentChips({ value, onRemove }: { value: unknown; onRemove?: ((id: string) => void) | undefined }) {\n const ids = attachmentIdsOf(value);\n if (ids.length === 0) return null;\n return (\n <span className=\"flex flex-wrap gap-1\" data-records-file-chips=\"\">\n {ids.map((id) => (\n <AttachmentChip key={id} id={id} {...(onRemove ? { onRemove: () => onRemove(id) } : {})} />\n ))}\n </span>\n );\n}\n\n/** Does this host have any way to put a file into a cell? */\nexport function hostTakesFiles(host: { pickFiles?: unknown; upload?: unknown }): boolean {\n return Boolean(host.pickFiles || host.upload);\n}\n\n/**\n * THE ATTACHMENT EDITOR. `autoOpen` (a grid cell opened by a click or Enter): the host's file\n * window opens at once, and whatever is picked is the commit (`onClose`), exactly as a choice\n * cell's list does. A cancelled window closes the cell with nothing changed.\n */\nexport function AttachmentControl({\n field,\n value,\n onChange,\n disabled,\n id,\n autoOpen,\n onClose,\n}: {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n autoOpen?: boolean | undefined;\n onClose?: (() => void) | undefined;\n}) {\n const host = useRecordsUi();\n const [busy, setBusy] = useState(false);\n const [why, setWhy] = useState<string | null>(null);\n const latest = useRef(value);\n latest.current = value;\n const multiple = Boolean(field.multi);\n\n const pick = async () => {\n if (!host.pickFiles || disabled) return;\n setBusy(true);\n setWhy(null);\n try {\n const picked = await host.pickFiles({ multiple });\n if (picked && picked.length > 0) {\n rememberHostFileIds(picked);\n onChange(withAttached(field, latest.current, picked));\n }\n } catch (cause) {\n setWhy(cause instanceof Error ? cause.message : String(cause));\n setBusy(false);\n return;\n }\n setBusy(false);\n onClose?.();\n };\n\n const opened = useRef(false);\n useEffect(() => {\n if (!autoOpen || opened.current || !host.pickFiles) return;\n opened.current = true;\n void pick();\n // Once per opening of the cell.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoOpen]);\n\n if (!hostTakesFiles(host)) {\n return (\n <p id={id} className=\"rounded border border-dashed px-2 py-1 text-xs text-muted-foreground\" data-records-no-file-door=\"\">\n {NO_UPLOAD_REASON}\n </p>\n );\n }\n\n return (\n <span id={id} className=\"flex flex-col gap-1\" data-records-attachment-editor=\"\">\n <AttachmentChips\n value={value}\n {...(disabled ? {} : { onRemove: (removed: string) => onChange(withoutAttached(field, latest.current, removed)) })}\n />\n <span className=\"flex flex-wrap items-center gap-1\">\n {host.pickFiles ? (\n <Button size=\"sm\" variant=\"outline\" disabled={disabled || busy} onClick={() => void pick()} data-records-attach-files=\"\">\n {busy ? \"Choosing…\" : attachmentIdsOf(value).length > 0 ? \"Add files…\" : \"Attach files…\"}\n </Button>\n ) : null}\n {host.upload ? (\n <FilePicker\n label=\"Upload a file\"\n inputLabel={`Upload a file to ${fieldName(field)}`}\n disabled={disabled || busy}\n onFile={(file) => {\n setBusy(true);\n setWhy(null);\n void host.upload!(file).then((result) => {\n setBusy(false);\n if (result.ok) {\n rememberHostFileIds([result.fileId]);\n onChange(withAttached(field, latest.current, [result.fileId]));\n }\n else setWhy(result.reason);\n });\n }}\n />\n ) : null}\n </span>\n {why ? <RefusalLine error={refusalOf(\"invalid_argument\", why, \"Pick another file, or try this one again.\")} /> : null}\n </span>\n );\n}\n","\"use client\";\n\n// src/host.tsx — @ai-matrx/records-ui\n//\n// THE ONE BINDING POINT. A host mounts `<RecordsUiProvider>` once, inside\n// `<RecordsProvider>` from @ai-matrx/records, and every component in this\n// package reads what it needs from here. There is no module-level state: two\n// organizations in two tabs must never share one.\n//\n// WHAT A HOST BINDS, AND WHAT HAPPENS WHEN IT DOES NOT\n// ----------------------------------------------------\n// `rights` USED TO BE the only answer to \"may this person administer this\n// table?\" — a PORT, whose default was `false` with a reason and whose only\n// other honest setting was `storeDecidesRights`: yes to everything, let the door\n// refuse afterwards. The sixth-pass verdict measured what that second answer\n// costs a person: a colleague at viewer got a live cell editor, typed, pressed\n// Enter, and was refused only then.\n//\n// THE STORE ANSWERS THIS NOW, through the door this lane added:\n// `custom.my_levels` says what level the CALLER holds on the subjects they\n// name, one call for a whole page. `rights` stays a PORT for a host whose\n// authority is genuinely its own, but nothing is guessed when it is unbound:\n// the store's own answer is the default, and `rights.why(...)` says, for each\n// thing a person may not do, what level it would take and who can give it.\n//\n// IT IS NOT FREE, AND THE OBVIOUS FREE VERSION IS WRONG. `custom.read_records`\n// answers `level` on every row and `tableList` is a read — but of the Table\n// KERNEL, so that level is the caller's level on the kernel (viewer, for\n// everybody) and not on the table the row describes. Carrying it was measured\n// wrong within the hour: a table's own owner came back \"viewer\". A table is a\n// record, and its level is asked for like any other record's.\n//\n// ABSENT OR HONEST, NEVER DEAD — and never offered-then-refused, which is the\n// same lie with a longer fuse.\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { AggregateFilter, Field, PermissionLevel, RecordDocument, RecordRead, Table, Uuid } from \"@ai-matrx/records\";\nimport { useMyLevel, useMyLevels } from \"@ai-matrx/records/react\";\nimport type { ReversibleAnnouncement } from \"@ai-matrx/kit/reversible\";\nimport type { TableSettingsAgent } from \"./settingsAgent\";\n\nimport { NOT_ANSWERED_YET, whatYouMayDo, whatYouMayDoWithTable, type WhatYouMayDo } from \"./rights\";\nimport type { RecordChatContext } from \"./RecordChat\";\nimport type { EnrichAsk, EnrichOutcome } from \"./Enrich\";\nimport type { GridContextSnapshot } from \"./gridAgentContext\";\n\n/**\n * What a person may do to one table. The four words and the ladder are the\n * store's (`rights.ts`), not ours.\n *\n * `admin`, `comment` and `write` are kept with the names they have always had,\n * because every screen in this package and in the host apps reads them; they\n * are now the store's ANSWER rather than a host's guess.\n */\nexport interface TableRights extends WhatYouMayDo {\n /** SCR-2: holders of `admin` on the table see the \"+\" and the settings panel. */\n admin: boolean;\n /**\n * Why this answer, in one sentence. Kept for callers that show a single\n * reason; `why(what)` is the per-control sentence and is what the screens use.\n */\n reason: string;\n}\n\nfunction tableRights(may: WhatYouMayDo, overallReason?: string): TableRights {\n return {\n ...may,\n admin: may.structure,\n reason: overallReason ?? (may.structure ? \"\" : may.why(\"structure\")),\n };\n}\n\n/**\n * Kept so a host that imported it still compiles. It is no longer any screen's\n * default: the store answers this question now, and a package that said \"I\n * assume nothing\" while holding the answer would be hiding controls from the\n * people who hold them.\n */\nexport const NO_RIGHTS: TableRights = tableRights(NOT_ANSWERED_YET);\n\n/**\n * THE ONE WAY TO BUILD A `TableRights` BY HAND — for a host with its own\n * authority, and for a suite that wants to mount one seat's screen. It takes\n * the LEVEL, never six booleans, so nobody can hand a screen a combination the\n * ladder cannot produce (write without read, share without edit).\n */\nexport function tableRightsAt(level: PermissionLevel | null): TableRights {\n return tableRights(whatYouMayDo(level, true));\n}\n\n/**\n * The authored-text slots `renderText` is asked to draw. `cell`: a long-text cell of the merged\n * grid and the whole-text dialog's preview — the host may return block content there (the grid\n * clips it to the row); the form slots take phrasing content only.\n */\nexport type RenderTextSlot = \"form-intro\" | \"form-help\" | \"form-thank-you\" | \"cell\";\n\nexport type { GridContextSnapshot } from \"./gridAgentContext\";\n\n/** One reference a chip names (`renderReference`). `record` is a relation's value, read side only. */\n/** What a record page hands the host's rich editor (`editRichText`). */\nexport interface RichTextEditProps {\n /** The stored Markdown. A later value is the store's echo or a colleague's change. */\n value: string;\n /** Every change the person makes, as the whole Markdown text. Saving is the package's. */\n onChange: (text: string) => void;\n readOnly: boolean;\n placeholder: string;\n}\n\nexport interface ReferenceChipRef {\n token: string;\n id: Uuid;\n label: string | null;\n /** For `token: \"record\"`, the Table the relation points into. */\n tableId?: Uuid | undefined;\n /**\n * The record it names sits in Archived items. An archive keeps every reference to what it\n * archived (chair ruling B3-21), so the chip still names it and draws the archived state.\n */\n archived?: boolean | undefined;\n /** The record's (or its table's) icon — an emoji or short glyph — when the host knows one. */\n icon?: string | null | undefined;\n}\n\nexport interface RecordsUiHost {\n /**\n * Draws an icon kept as a NAME (\"Briefcase\" — how the store keeps an icon a person picked from the\n * icon list). A relation cell in an embedded table wears its record's icon; an emoji is drawn as\n * text and a name only through this port. Unbound (or `null` back), the page glyph stands in.\n */\n renderIcon?: ((name: string) => ReactNode) | undefined;\n /**\n * TEMPORARY (one-grid merge, steps 5-8). Which table grid draws: `classic` — the default Grid\n * as it shipped in 0.86; `merged` — the same grid with the older /data grid's control layer on\n * it (the column header menu, the right-click Cell / Row / Column / Table sections, column\n * settings, column order and hidden columns kept on the view). Left out: `classic`. Removed at\n * merge step 9, when `merged` is the only grid.\n */\n grid?: \"classic\" | \"merged\";\n /**\n * OPTIONAL. CLEAN A PASTED PIECE OF HTML INTO PLAIN TEXT (merge tranche 6m, inventory A7).\n *\n * A cell pasted from a web page or an email carries its tags, entities and inline styles. The\n * platform has ONE cleaner (the host's content-cleanup), so this is a port rather than a second\n * one here. The merged grid offers \"Clean HTML\" in a text cell's right-click Cell section and in\n * the whole-text editor; the cleaned text is written through the grid's own one-cell write (one\n * undo step). Unbound, the item is ABSENT, never dead.\n */\n cleanText?: (text: string) => string;\n /**\n * OPTIONAL. WHERE THE PERSON IS IN THE GRID, told as it changes (merge tranche 6l, inventory H1).\n *\n * An agent in the host's side chat is asked about \"this cell\", \"these rows\", \"the table\". Only\n * the grid knows the table, its columns, the cell the cursor is on, the selected block, the\n * ticked rows, the rows on screen and the search. The merged grid calls this after any of them\n * changes (identical snapshots are not repeated); the host builds its agent scope from it. The\n * snapshot carries the store's own `Field` records and the masked documents exactly as drawn.\n * Unbound, nothing is built.\n */\n onGridContext?: (snapshot: GridContextSnapshot) => void;\n /**\n * OPTIONAL. THE PLATFORM'S ONE ICON PICKER (merge tranche 6j, inventory G2). A row action's\n * button may carry an icon from the canonical icon set; that set and its picker are the host's\n * (this package carries no icon library). Unbound, the row-action editor draws no icon control\n * and keeps whatever icon an action already carries.\n */\n iconPicker?: (props: { value: string; label: string; onChange: (name: string) => void }) => ReactNode;\n /**\n * OPTIONAL. HELP WRITING A FORMULA (Sheet retirement). The formula box hands the host what it\n * holds — the text, the table's other columns and the store's reading of what is wrong — and the\n * host draws its own help control beside the box (matrx-frontend runs its formula-writing job).\n * Whatever formula the help arrives at goes back through `onFormula` into the box, unsaved, for\n * the person to keep or change. Unbound, nothing is drawn.\n */\n formulaHelp?: (ask: FormulaHelpAsk) => ReactNode;\n /**\n * OPTIONAL. AN AGENT OVER A TABLE'S SETTINGS (Sheet retirement). While the settings panel is open\n * it wraps itself in what this returns, handing the host a `TableSettingsAgent`: what the panel\n * can see (the description as edited, the row actions and the one being edited, what stops it\n * saving) and three staging calls (a whole row action, one step's formula, the description).\n * Staging never saves; the person presses Save. Unbound, the panel draws bare.\n */\n settingsAgent?: (args: { tableId: Uuid; agent: TableSettingsAgent; children: ReactNode }) => ReactNode;\n /** Answer the rights question for one table. Synchronous: a screen renders now. */\n rights?: (table: Table) => TableRights;\n /** Where a record's own page lives, when the host has one. A peek is used when it does not. */\n hrefForRecord?: (args: { table: Table; recordId: Uuid }) => string | undefined;\n /**\n * OPTIONAL. WHERE A FILE OPENS. A value too big for one cell is kept as a file and the cell\n * holds its first words (`@ai-matrx/records/core` `wholeValueOf`); this is the host's page for\n * that file. Unbound, the cell shows the words and says the whole text is kept as a file this\n * screen cannot open — never a dead link.\n */\n hrefForFile?: (args: { fileId: Uuid }) => string | undefined;\n /**\n * OPTIONAL. READ A FILE'S WHOLE TEXT, so an export writes a big value's whole content rather\n * than its first words. Unbound, the exported cell carries the words and one sentence naming\n * the file (`wholeValueNotRead`) — never the words passed off as the value.\n */\n readFileText?: (args: { fileId: Uuid }) => Promise<string>;\n /**\n * OPTIONAL. A FILE DRAWN AS A PICTURE — the gallery card's cover when the view's picture column\n * is a File column (lane DATA-V2-VIEWS-1). The host owns how a file becomes pixels (its media\n * lane, its auth), so this is a port: it returns the element that fills the cover box. Unbound,\n * the cover says in words that this screen cannot draw files, never a broken image.\n */\n fileImage?: (args: { fileId: Uuid; alt: string }) => ReactNode;\n /**\n * OPTIONAL. HOW AUTHORED TEXT READS. A form's intro, a question's help and the thank-you body\n * are written by a person and may carry markdown and math (`**bold**`, `\\\\(x^2\\\\)`, links).\n * This package does not parse markdown — the host owns its renderer — so this is a port: the\n * host returns phrasing content (valid inside a `<p>`). `where` names the slot. Unbound, the\n * text shows exactly as written.\n */\n renderText?: (text: string, where: RenderTextSlot) => ReactNode;\n /**\n * OPTIONAL. ONE REFERENCE, DRAWN AS A CHIP THAT OPENS WHAT IT NAMES (lane REFERENCE-CARRY).\n *\n * Every reference this package shows — a relation to a record (`token: \"record\"`, with the\n * Table it points into), an entity reference to a platform thing (`note`, `agent`, `workflow`…)\n * — is drawn through this port, so a person can always reach the thing (the host owns routes,\n * peeks and new tabs). `label` is the store's words, or null when they were withheld from this\n * reader. Unbound, the chip names the thing and opens nothing.\n */\n renderReference?: (ref: ReferenceChipRef) => ReactNode;\n /**\n * OPTIONAL. A VALUE THAT NAMES ITS OWN SHAPE, DRAWN THROUGH THE HOST'S KIND SYSTEM (lane\n * REFERENCE-CARRY). A cell holding `__kind` JSON — or a Matrx directive stored before the Kind\n * Directives merge (```matrx {\"matrx_version\":1,…}```) — is handed over whole (`kindValues.ts`);\n * the host decodes it with its one decoder and returns a compact rendering for `where` (a cell,\n * a panel row) that opens the real view. Unbound, the cell names the kind and shows the raw text\n * on hover — never the fence at eye level.\n */\n renderKind?: (args: { value: Record<string, unknown>; kind: string; where: \"cell\" | \"panel\"; title: string }) => ReactNode;\n /** The host's own link element, so routing stays the host's business. */\n Link?: (props: { href: string; children: ReactNode; className?: string }) => ReactNode;\n /** Toasts. Absent means the screen shows the sentence inline instead — never silence. */\n notify?: {\n /** `action`: one button on the toast (an Undo). A host without actions draws the sentence alone. */\n success: (message: string, action?: { label: string; run: () => void }) => void;\n error: (message: string) => void;\n /**\n * OPTIONAL. THE REVERSIBLE ACTION (`@ai-matrx/kit/reversible`): something this package did\n * that can be undone — a table archived — handed to the host's one announcer, which acts it\n * out at the person's level (taught the first time, a long Undo toast the next few, an ordinary\n * one after) and answers ⌘Z. The package says WHAT happened and HOW to undo it; where the\n * thing went (`foundAt`) is the host's routes. Unbound, the package falls back to `success`\n * with an Undo button.\n */\n reversible?: (announcement: ReversibleAnnouncement) => void;\n };\n /** Density for every table this package renders. */\n density?: \"condensed\" | \"normal\" | \"spacious\";\n /**\n * OPTIONAL. WHETHER A WITHHELD CONTROL SAYS WHAT LEVEL IT TAKES (\"You are Viewer here, and it takes\n * Editor to … Ask somebody who is Admin on it to move you up.\"). Default `true`. A host whose\n * person has no level to be moved up to — a template preview, a public look at a table — sets\n * `false`: the control stays absent exactly as before, without the sentence. It changes words\n * only, never what is offered.\n */\n sayLevelNeeded?: boolean;\n /**\n * OPTIONAL. Where a file a person attached actually goes. A File is a record\n * in the kernel File Table (REC-31), but the BYTES are the host's file\n * service, not this package's business — so this is a port.\n *\n * Unbound, an attachment question does NOT draw a file chooser that quietly\n * loses the file: it says, in one sentence, that no file store is bound and\n * names this port. Absent or honest, never dead.\n */\n upload?: (file: File) => Promise<{ ok: true; fileId: Uuid } | { ok: false; reason: string }>;\n /**\n * OPTIONAL. THE HOST'S OWN FILE WINDOW (one-grid merge, inventory: the older grid's\n * AttachmentInput). An attachment cell adds files the person already holds through the host's\n * file picker — Airtable's \"Attach\" over your own files — rather than a second browser this\n * package would invent. `multiple`: the column holds several files; `accept`: the native\n * `accept` list, when the column restricts types. Resolves the host's file ids (the store turns\n * each into its kernel File record at the write door), or `null` when the person cancelled.\n *\n * Unbound, the editor offers `upload` alone; with neither bound it says no file store is bound\n * (`NO_UPLOAD_REASON`) — never a dead button.\n */\n pickFiles?: (ask: { multiple: boolean; accept?: string }) => Promise<Uuid[] | null>;\n /**\n * Where this app serves its PUBLIC pages from, when that is not the origin\n * the screen is running on. A form's link is built here, so an owner copying\n * it from an admin host, a preview deployment or a desktop shell gets the\n * address a stranger can actually open — never `http://localhost:3000/f/…`\n * pasted into an email. Unbound, the browser's own origin is used.\n */\n publicOrigin?: string;\n /**\n * OPTIONAL. The organization's saved views as `platform.saved_view` holds\n * them — which is what a subscription points at (DOOR-18). The record store\n * has NO door onto that table, because it is the platform's and not the\n * store's, so this is a port rather than a read this package invents.\n *\n * Unbound, `NotifyRuleEditor` shows the subscriptions that exist and says, in\n * one sentence, that it cannot offer a view to subscribe to. It never renders\n * an empty picker that looks like \"you have no views\".\n */\n savedViews?: () => Promise<Array<{ id: Uuid; name: string }>>;\n /**\n * OPTIONAL. WHO IS IN THIS ORGANIZATION (FLD-11 `member`).\n *\n * A person field must offer PEOPLE. Who the people are is the platform's\n * answer — organization membership lives in `iam`, not in the record store —\n * and the store has no door onto it, so this is a port rather than a read\n * this package invents. `PersonPicker` resolves whoever is picked to their\n * record in the kernel Person Table, which is what the Field actually stores.\n *\n * Unbound, a person question is ABSENT with `NO_MEMBERS_REASON`. It never\n * falls back to listing the kernel Person Table's contents: that Table also\n * holds the Homes this package writes, and offering \"Comments Home\" as a\n * person is exactly what this port exists to stop.\n */\n members?: () => Promise<OrganizationMember[]>;\n /**\n * OPTIONAL. THE HOST'S OWN CHAT SURFACE (SCR-26).\n *\n * This package ships no chat UI, on purpose: AI Matrx has exactly one, it\n * lives in matrx-frontend (`AgentConversationColumn`), and it reads that app's\n * Redux store — so a second one here would drift within a month and a package\n * that imported the first would stop being a package. `RecordChat` therefore\n * builds the CONTEXT (the record, through the read door, with the masked\n * fields named) and hands it to this port.\n *\n * Unbound, the panel is ABSENT with that reason, never a composer that goes\n * nowhere.\n */\n chat?: (context: RecordChatContext) => ReactNode;\n /**\n * OPTIONAL. MORE SECTIONS ON AN OPEN RECORD — drawn in the record rail after its history,\n * one host-owned block about THIS record (e.g. \"What ran on this record\": the Workflow runs\n * stamped with it). Unbound, nothing is drawn.\n */\n recordSections?: (target: { tableId: Uuid; recordId: Uuid }) => ReactNode;\n /**\n * OPTIONAL. THE PLATFORM'S ONE RICH EDITOR, for a record page's body (lane TABLE-EXPERIENCE,\n * v7 item 1: a record is a page). The host draws its own editor — matrx-frontend's notes editor —\n * reporting every change through `onChange`; this package owns the saving. Unbound, the body is\n * drawn read-only and is edited through the record's form.\n */\n editRichText?: (props: RichTextEditProps) => ReactNode;\n /**\n * OPTIONAL. THE HOST DRAWS A RECORD PAGE'S WHOLE BODY (the \"Spaces\" page layer's block editor).\n * When bound and it returns non-null, the record page draws that in place of the package's own\n * body (the formatted-text column editor and its \"Write on this page\" offer); the host owns\n * saving. Returning `null` (or leaving it unbound) draws today's body unchanged.\n */\n renderRecordBody?: (args: {\n tableId: string;\n recordId: string;\n record: RecordRead;\n readOnly: boolean;\n /** Today's body as an element — return it (or null) where the host has no body of its own. */\n fallback: ReactNode;\n }) => ReactNode | null;\n /**\n * OPTIONAL. \"LINK A RECORD…\" — the HOST opens its one record picker pointed at this record and\n * writes the link through its own reference door; this package draws only the menu entry (a\n * card's ⋯ and right-click, the grid row's right-click). Unbound, the entry says it is not\n * available here.\n */\n linkRecord?: (target: { tableId: Uuid; recordId: Uuid; name: string }) => void;\n /**\n * OPTIONAL. \"TALK TO THIS RECORD\" — the HOST opens its own one chat surface\n * (AGT-N-9, PRODUCTS row 11).\n *\n * `chat` is the port that RENDERS a chat inside a panel this package draws.\n * This one is the other direction: a menu entry in the grid, the cell menu or\n * the record header says \"the person wants to talk about this record\", and the\n * host opens the chat where the host puts chats — full height, the platform's\n * own pattern — and binds the conversation to the record through\n * `conversationScopeBind`. Drawing a chat next to a grid row from inside this\n * package would be the parallel layer the canvas ruling forbids.\n *\n * ABSENT, NEVER DEAD: where neither this nor `chat` is bound, the entries do\n * not render at all.\n */\n talkToRecord?: (target: { tableId: Uuid; recordId: Uuid; title: string }) => void;\n /**\n * OPTIONAL. A TABLE'S AGENT BUTTON, PRESSED (TABLE-PARITY M3, lane DEFAULT-GRID-PARITY).\n *\n * A row action of kind `agent` (\"Ask Dr. Whitfield\") hands the row to an agent with the\n * action's own `prompt`. Only the host can start that conversation — this package ships no\n * chat — so the grid hands the row, the action's name and its prompt here, and the host\n * opens its one chat surface bound to the record with that prompt as the opening ask. It is\n * a separate port from `talkToRecord` because that one carries no prompt: a host that bound\n * only `talkToRecord` would open an empty chat and silently drop what the button was for.\n *\n * ABSENT, NEVER DEAD: unbound, agent buttons are not drawn.\n *\n * NO SECOND READ (lane GRID-TAILS, 2026-09-24). The grid already holds the table, its\n * columns, the row as this reader may see it and this reader's level on the row, so it hands\n * them over: a host needs no `tableList`, `fields`, `recordRead` or `myLevels` to start the\n * job, and the agent is handed exactly what the person was looking at.\n */\n runAgentAction?: (target: {\n tableId: Uuid;\n recordId: Uuid;\n title: string;\n action: string;\n prompt: string;\n /** The table's name, as the grid shows it. */\n tableName: string;\n /** The table's columns, as the grid drew them. */\n fields: readonly Field[];\n /** The row, masked for this reader exactly as the grid shows it. */\n document: RecordDocument;\n /** This reader's level on the row (`custom.read_records_matching`'s answer). */\n level: PermissionLevel | null;\n }) => void;\n /**\n * OPTIONAL. THE SERVER'S `records` TOOL (SCR-27).\n *\n * An AI fill must be written with actor `agent` on behalf of the person, and\n * only the server can honestly say that — a browser stamping itself `agent`\n * is a browser claiming to be one. So `EnrichPanel` asks here, and the host\n * calls the server's own `records` tool (`action: \"record_write\"`), which\n * stamps `_actor` and `_on_behalf_of` itself.\n *\n * Unbound, no Fill control is drawn at all and the reason names this port.\n */\n enrich?: (ask: EnrichAsk) => Promise<EnrichOutcome>;\n /**\n * OPTIONAL. WHERE AN OFFLINE CAPTURE WAITS (SCR-30).\n *\n * `CaptureSheet` mints the id for a capture BEFORE it tries to send it, so a\n * phone with no signal has already decided what the write will be called.\n * Where that queue physically lives is the host's business — IndexedDB in a\n * browser, a file in a desktop app — so it is a port. Unbound, the sheet\n * keeps its queue in memory for the life of the page AND SAYS SO, because a\n * queue that silently died with the tab is the failure this exists to avoid.\n */\n captureQueue?: CaptureQueuePort;\n /**\n * OPTIONAL. THE HOST'S OWN SHARE DIALOG (SCR-N-5).\n *\n * This package ships no share dialog, ON PURPOSE, and for the same reason it\n * ships no chat: AI Matrx has exactly ONE sharing surface — matrx-frontend's\n * `features/sharing` ShareModal, with its people picker, its level picker, its\n * grant list and its \"who can see this, and why\" panel — and a second one here\n * would be a parallel sharing UI within a month. Sharing is the access model's\n * front door, and two front doors is how a platform ends up with two answers\n * to \"who can see this\".\n *\n * So `ShareControl` draws the BUTTON (which belongs on the record and table\n * screens, beside everything else a person does to a thing) and hands the\n * subject to this port, which returns the host's own dialog.\n *\n * Unbound, the button is ABSENT and `NO_SHARE_REASON` says which port to bind.\n * Never a Share button that opens nothing.\n */\n share?: (subject: ShareSubject) => ReactNode;\n /**\n * APPLETS ON A PAGE (v7 APPS-ON-DATA item 3). The host's applet system: which applets this person\n * may place (`list`), and the applet itself drawn in place (`render`). Unbound, a page offers no\n * Applet block and an applet block already on the page says it opens inside the app.\n */\n applets?: {\n list: () => Promise<ReadonlyArray<{ id: string; name: string }>>;\n render: (appId: string) => ReactNode;\n };\n /**\n * OPTIONAL. OPEN THE RECORDS BEHIND A NUMBER (SCR-16).\n *\n * Every number on a dashboard is a count of real records, and the whole\n * product row is that a person can get from the number to them: click the\n * \"Awaiting parts\" column and the grid opens on the twenty-eight jobs it\n * counted, with the block's own filter still on. That is one navigation, and\n * WHERE the grid lives is the host's routing — so it is a port, like\n * `hrefForRecord`, rather than a route string this package invents.\n *\n * Unbound, the marks are NOT clickable and the canvas says so in one\n * sentence naming this port. A chart whose bars looked pressable and did\n * nothing is the dead control this package does not ship.\n */\n openRecords?: (ask: OpenRecordsAsk) => void;\n /**\n * OPTIONAL. WHERE A PAGE OPENS (v6 lane 11, wave D). A Page is a dashboard record whose\n * `presentation.kind` is `\"page\"` (`pages.ts`); the host owns its route, so this hands back the\n * address of an existing page, or of the screen that makes a new one on a Table. Unbound, the\n * Dashboards area lists no pages and offers no \"New page\" — absent, never dead.\n */\n pageHref?: (target: { pageId: Uuid } | { newOnTable: Uuid }) => string;\n /**\n * OPTIONAL. ASK THE AGENT TO CHANGE THIS DASHBOARD (SCR-16).\n *\n * \"break it down by owner\" is how a dashboard is actually built — the agent\n * calls `dashboard_propose` on the server's `records` tool with this\n * dashboard's id and re-states it. Only the server can do that honestly (a\n * browser stamping itself `agent` is a browser claiming to be one), which is\n * the same reason `enrich` is a port, so this is one too.\n *\n * Unbound, the box is drawn DISABLED with one sentence naming this port —\n * never a composer that goes nowhere and never silence.\n */\n onReask?: (question: string, context: ReaskContext) => Promise<void>;\n /**\n * OPTIONAL. ASK AN AGENT FOR A WHOLE FORM, BOOKING PAGE, PORTAL OR DIGEST.\n *\n * This is the FASTER of the two ways every builder offers (`BuildOrAsk`), and\n * it is a port for the same reason `onReask` is: the server's `records` tool\n * is what calls `form_propose`, `booking_propose`, `portal_propose` and\n * `subscription_propose`, and a browser stamping itself `agent` would be a\n * browser claiming to be one.\n *\n * `suggestion` is the sentence this package would put in the person's mouth —\n * a host normally opens its composer with it already typed, so the person\n * edits rather than starts.\n *\n * Unbound, the \"Ask an agent\" button is ABSENT — not greyed — and every\n * builder's empty state says so in one sentence naming this port, with the\n * hand-built way still right there. The product walk of 2026-09-21 found the\n * opposite arrangement (the agent named and no builder at all), which left a\n * person who did not know what to say with nothing to press.\n */\n onAskForOne?: (ask: AgentBuildAsk) => void;\n}\n\n/** What the formula box hands the host's help (`formulaHelp`). */\nexport interface FormulaHelpAsk {\n tableId: Uuid;\n /** The formula as it stands in the box (may be empty). */\n text: string;\n /** The table's other columns, the ones the formula may read as {Name}. */\n columns: readonly Field[];\n /** The store's reading of what is wrong with the text, when it does not parse. */\n mistake: string | null;\n /** The functions the store works out, as a person types them. */\n functions: readonly string[];\n /** Put a formula into the box (unsaved). */\n onFormula: (text: string) => void;\n}\n\n/** What a person is asking an agent to make, and where they were standing. */\nexport interface AgentBuildAsk {\n /**\n * `column`: a layout needs a column the table lacks (`ViewNeeds`, lane DATA-V2-VIEWS-1) — the\n * agent adds it through the store's field door, held for approval like every agent schema change.\n */\n kind: \"form\" | \"booking\" | \"portal\" | \"digest\" | \"column\";\n tableId: Uuid;\n /** The sentence this package would say. A host opens its composer with it. */\n suggestion: string;\n}\n\n/**\n * WHAT A CLICK ON A NUMBER ASKS FOR. The filter is already merged: the block's\n * own filter (which `custom.dashboard_run` echoes back with the canvas bar\n * folded under it) with the clicked group's key and value over the top. A host\n * that dropped a key would open the grid on more records than the number\n * counted, which is the one way this control can lie.\n */\nexport interface OpenRecordsAsk {\n tableId: Uuid;\n filter: Record<string, AggregateFilter>;\n /** What the person clicked, in words: \"Jobs by stage this month · Awaiting parts\". */\n label: string;\n}\n\n/** Which dashboard a re-ask is about, so the agent re-states it rather than making a second one. */\nexport interface ReaskContext {\n tableId: Uuid;\n /** Null while the canvas has no dashboard yet — the answer is the first one. */\n dashboardId: Uuid | null;\n dashboardName: string | null;\n}\n\n/**\n * What a host's share dialog is being opened ON. A Table is a record in this\n * store (a `custom.record` row whose table is the Table kernel), so ONE subject\n * shape covers both screens and `kind` is what the sentences say, not what the\n * store looks up.\n */\nexport interface ShareSubject {\n kind: \"record\" | \"table\";\n /** The store is keyed (organization_id, id); this package never guesses one. */\n organizationId: Uuid;\n subjectId: Uuid;\n /** What to call it on screen. Never empty — the id's first eight characters at worst. */\n name: string;\n /** Close the dialog. The control owns the open/closed state, the host owns the dialog. */\n onClose: () => void;\n}\n\n/** One member of the organization, in the words a person reads. */\nexport interface OrganizationMember {\n /** The platform's user id. This is what a Person record carries as `user_id`. */\n userId: string;\n /** Their display name, when the platform has one. */\n name?: string | null;\n email?: string | null;\n avatarUrl?: string | null;\n}\n\n/** The durable half of offline capture: read the queue, write it, that is all. */\nexport interface CaptureQueuePort {\n load: () => Promise<PendingCapture[]>;\n save: (pending: PendingCapture[]) => Promise<void>;\n}\n\n/** One capture waiting to be written, with the id the CLIENT minted for it. */\nexport interface PendingCapture {\n /**\n * The client key. Minted offline, before the first attempt, and never\n * re-minted on retry — that is exactly what lets the store's replay ledger\n * tell a retry from a second capture.\n */\n clientKey: string;\n tableId: Uuid;\n payload: Record<string, unknown>;\n capturedAt: string;\n device: string;\n /** How many times sending has been tried, and what the store last said. */\n attempts: number;\n lastRefusal?: string | null;\n}\n\n/**\n * The sentence the notify editor shows when no saved-view port is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `savedViews` on\n * `<RecordsUiProvider>` with the host's own list of `platform.saved_view` rows —\n * the record store has no door onto them — and the picker appears.\n */\nexport const NO_SAVED_VIEWS_REASON =\n \"There are no saved views here yet, so there is nothing to be told about. Save a view of this \" +\n \"table first and it will be offered here.\";\n\n/**\n * The sentence a person question shows when no membership port is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `members` on\n * `<RecordsUiProvider>` with the host's own roster. Who is in an organization is\n * the platform's answer, not the record store's, so this package will not guess.\n */\nexport const NO_MEMBERS_REASON =\n \"This app cannot offer the people in your organization on this screen yet, so there is nobody to \" +\n \"pick. Type the person's name into a text field for now, and tell us — it is on our list, not \" +\n \"yours.\";\n\n/**\n * The sentence shown when no share dialog is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `share` on\n * `<RecordsUiProvider>` with the app's own sharing dialog. AI Matrx has exactly\n * one, and this package deliberately does not ship a second.\n */\nexport const NO_SHARE_REASON =\n \"Sharing is not available on this screen, so there is no Share button here rather than one that \" +\n \"opens nothing. Share this table from the tables list instead.\";\n\n/**\n * The sentence a canvas shows when nothing is bound to open the records behind a number.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `openRecords` on\n * `<RecordsUiProvider>`. Where this app puts its grid is the host's routing, not\n * this package's, so it will not guess an address.\n */\nexport const NO_OPEN_RECORDS_REASON =\n \"These numbers do not click through yet. Every one of them is a count of real records — open the \" +\n \"records view and group it by the same field to see them. It is on our list, not yours.\";\n\n/**\n * The sentence the re-ask box shows when no agent is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `onReask` on\n * `<RecordsUiProvider>`; it drives `dashboard_propose` on the server's `records`\n * tool with this dashboard's id. Only the server can honestly speak as an agent.\n */\nexport const NO_REASK_REASON =\n \"Changing this dashboard by describing it is not switched on here yet, so this box is off rather \" +\n \"than one that goes nowhere. Add and remove the blocks by hand above. It is on our list, not \" +\n \"yours.\";\n\n/**\n * The sentence an attachment question shows when no file store is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `upload` on\n * `<RecordsUiProvider>` with the host's file service and the chooser appears.\n */\nexport const NO_UPLOAD_REASON =\n \"This screen cannot take a file yet, so there is no chooser here rather than one that loses what \" +\n \"you pick. Put a link to the file in a text field for now. It is on our list, not yours.\";\n\nconst HostContext = createContext<RecordsUiHost | null>(null);\n\nexport function RecordsUiProvider({ value, children }: { value: RecordsUiHost; children: ReactNode }) {\n const bound = useMemo(() => value, [value]);\n return <HostContext.Provider value={bound}>{children}</HostContext.Provider>;\n}\n\nexport function useRecordsUi(): RecordsUiHost {\n return useContext(HostContext) ?? {};\n}\n\n/**\n * WHAT THIS PERSON MAY DO TO THIS TABLE — asked, once per table.\n *\n * A host that binds `rights` still wins: a portal, an embed or an app with its\n * own authority is entitled to a narrower answer than the store's. An unbound\n * host no longer gets a guess in either direction — while the door is\n * answering, `known` is false and NOTHING is offered and nothing is claimed.\n */\n/** The same answer, with its level sentences silenced when the host says so (`sayLevelNeeded`). */\nfunction quiet<T extends WhatYouMayDo>(may: T, say: boolean | undefined): T {\n if (say !== false) return may;\n return { ...may, why: () => \"\", ...(\"reason\" in may ? { reason: \"\" } : {}) };\n}\n\nexport function useTableRights(table: Table | null | undefined): TableRights {\n const host = useRecordsUi();\n const asked = useTableRightsAsked(table, host);\n return useMemo(() => quiet(asked, host.sayLevelNeeded), [asked, host.sayLevelNeeded]);\n}\n\nfunction useTableRightsAsked(table: Table | null | undefined, host: RecordsUiHost): TableRights {\n const bound = Boolean(host.rights);\n // A table is a record in this store, so its level is the same question.\n const asked = useMyLevel(bound || !table ? null : table.id);\n return useMemo(() => {\n if (!table) return NO_RIGHTS;\n if (host.rights) return host.rights(table);\n if (asked.loading) return tableRights(NOT_ANSWERED_YET);\n // A refusal is an ANSWER: the door said no, so this person holds nothing.\n const level = asked.error ? null : asked.data;\n return tableRights(whatYouMayDoWithTable(table, level, true));\n }, [host, table, bound, asked.loading, asked.error, asked.data]);\n}\n\n/**\n * WHAT THIS PERSON MAY DO TO ONE RECORD — which is a different question from\n * the table's, and the sixth-pass verdict is the proof: a record shared with a\n * colleague at Editor inside a table she holds at Viewer. The grid used to\n * label that row \"viewer\" while the store let her write to it.\n */\nexport function useRecordRights(recordId: Uuid | null): WhatYouMayDo {\n const asked = useMyLevel(recordId);\n const say = useRecordsUi().sayLevelNeeded;\n return useMemo(() => {\n if (!recordId) return NOT_ANSWERED_YET;\n if (asked.loading) return NOT_ANSWERED_YET;\n // A refusal is an ANSWER: the door said no, so this person holds nothing.\n if (asked.error) return quiet(whatYouMayDo(null, true), say);\n return quiet(whatYouMayDo(asked.data, true), say);\n }, [recordId, asked.loading, asked.error, asked.data, say]);\n}\n\n/**\n * The same question for a whole page of records, in ONE call — the door takes a\n * list precisely so a grid never makes one call per row.\n *\n * `enabled` is how a grid avoids asking at all in the ordinary case: when the\n * table level already admits editing, every row it returned is editable and\n * there is nothing a per-record answer could add.\n */\nexport function useRowRights(\n rowIds: Uuid[],\n enabled: boolean,\n): (rowId: Uuid) => WhatYouMayDo | null {\n const asked = useMyLevels(enabled ? rowIds : []);\n const say = useRecordsUi().sayLevelNeeded;\n return useMemo(() => {\n if (!enabled) return () => null;\n if (asked.loading) return () => NOT_ANSWERED_YET;\n if (asked.error) return () => quiet(whatYouMayDo(null, true), say);\n const held = asked.data ?? {};\n return (rowId: Uuid) => quiet(whatYouMayDo((held[rowId] ?? null) as PermissionLevel | null, true), say);\n }, [enabled, asked.loading, asked.error, asked.data, say]);\n}\n","// src/rights.ts — @ai-matrx/records-ui\n//\n// THE ONE PLACE A LEVEL BECOMES A SCREEN.\n//\n// WHAT A PERSON HIT (independent verdict, sixth pass, 19-20 September). A\n// colleague who had been shared a table at viewer opened it, double-clicked a\n// cell, got a live editor, typed a value and pressed Enter — and only THEN was\n// told she may not write. \"The permission is right; the screen told her she\n// could.\" Measured against Airtable, Notion and Linear the verdict called it\n// out by name: \"None of these three products lets you start an action it\n// already knows it will reject.\"\n//\n// WHY THE SCREEN COULD NOT KNOW. The rights question was a PORT with two honest\n// answers and no third: `NO_RIGHTS` (every administering control absent, which\n// is useless for a host whose authority IS the store's) and\n// `storeDecidesRights` — `{admin: true, comment: true, write: true}` for every\n// non-kernel table, for everybody. That second one is the defect, written down:\n// it is the screen ASSUMING the answer and letting the door say no afterwards.\n//\n// WHAT REPLACES IT. The store already answers this, and the client now carries\n// it: `custom.read_records` returns the reader's level on the TABLE on every\n// row (so `Table.your_level` costs nothing), and `custom.my_levels` — the door\n// this lane added — answers the caller's level on any subject they name, one\n// call for a whole page. This file is the only place in the package that turns\n// one of those four words into what a screen may DRAW.\n//\n// THE LADDER IS THE STORE'S, NOT OURS: viewer < commenter < editor < admin, and\n// which rung each door requires is read from the doors themselves —\n// `custom.record_update` asserts `editor` on the record, `custom.field_declare`\n// asserts `admin` on the TABLE (\"the SHAPE of this table, which is an admin's\n// right and not an editor's\"), `custom.io_comment_write` admits a commenter.\n// Nothing here invents a rule; it mirrors the four assertions those doors make\n// and is wrong the moment they change, which is what the suite is for.\n//\n// ABSENT OR HONEST, NEVER DEAD. Every `false` here carries the sentence that\n// says why and what to do about it, so a control can be left out AND explained.\n// A screen that hid a control with nothing to say is the silent half of the\n// same defect.\n\nimport { atLeast, type PermissionLevel, type Table } from \"@ai-matrx/records\";\n\n/** The six things a person does to a record or a table, as the screens offer them. */\nexport type Capability = \"read\" | \"comment\" | \"write\" | \"organise\" | \"remove\" | \"share\" | \"structure\";\n\nexport interface WhatYouMayDo {\n /** The word the store answered, or null when it answered nothing. */\n level: PermissionLevel | null;\n /**\n * Whether the store has ANSWERED yet. `false` is a third state and not a\n * refusal: a screen that drew \"you may not\" while the answer was in flight\n * would blink every control off on every reload, which is its own lie.\n */\n known: boolean;\n read: boolean;\n comment: boolean;\n write: boolean;\n /** Duplicate, merge, restore, make a layout the default: the doors that ask `editor`, above content. */\n organise: boolean;\n remove: boolean;\n share: boolean;\n structure: boolean;\n /** Why this person may not do that, in one sentence naming the way in. */\n why: (what: Capability) => string;\n}\n\n/** What each rung of the ladder is called where a person reads it. */\nexport const LEVEL_WORD: Record<PermissionLevel, string> = {\n viewer: \"Viewer\",\n commenter: \"Commenter\",\n edit_content: \"Content editor\",\n editor: \"Editor\",\n admin: \"Admin\",\n};\n\n/**\n * WHICH RUNG EACH DOOR ASKS FOR. Read off the doors themselves, in one place,\n * so a screen never re-decides it and the suite has one thing to check.\n */\nconst NEEDS: Record<Capability, PermissionLevel> = {\n read: \"viewer\",\n // custom.io_comment_write\n comment: \"commenter\",\n // custom.record_update / custom.record_write — `edit_content` changes rows and page content;\n // columns, views and settings (structure) stay with admin below, and sharing with admin.\n write: \"edit_content\",\n // custom.view_designate / view_declare / migrate_merge / record_restore — all ask `editor`: more than\n // changing content (`edit_content`), less than changing columns (`admin`).\n organise: \"editor\",\n // custom.record_delete\n remove: \"editor\",\n // custom.share_grant — passing your access on is an administrator's right\n share: \"admin\",\n // custom.field_declare / field_update / field_retire / table settings\n structure: \"admin\",\n};\n\n/** The rung a capability asks for — so a short \"Needs Admin access\" never re-decides the ladder. */\nexport function levelNeededFor(what: Capability): PermissionLevel {\n return NEEDS[what];\n}\n\nconst NOT_YET =\n \"Still asking the store what you may do here. Nothing is offered until it has answered.\";\n\nconst NOTHING_AT_ALL =\n \"You have not been given this. Ask somebody who administers it to share it with you.\";\n\n/** The sentence for one refusal: what the level is, what it would have to be. */\nfunction sentenceFor(what: Capability, level: PermissionLevel | null): string {\n if (level === null) return NOTHING_AT_ALL;\n const need = LEVEL_WORD[NEEDS[what]];\n const have = LEVEL_WORD[level];\n const doing: Record<Capability, string> = {\n read: \"open this\",\n comment: \"leave a comment\",\n write: \"change anything here\",\n organise: \"organise this\",\n remove: \"delete this\",\n share: \"pass this on to somebody else\",\n structure: \"change the columns of this table\",\n };\n return `You are ${have} here, and it takes ${need} to ${doing[what]}. Ask somebody who is Admin on it to move you up.`;\n}\n\n/**\n * WHAT ONE LEVEL LETS A PERSON DO. `level` null and `known` true means the\n * store said \"nothing\" — a real answer. `known` false means it has not said.\n */\nexport function whatYouMayDo(level: PermissionLevel | null, known = true): WhatYouMayDo {\n const may = (what: Capability) => known && atLeast(level, NEEDS[what]);\n return {\n level: known ? level : null,\n known,\n read: may(\"read\"),\n comment: may(\"comment\"),\n write: may(\"write\"),\n organise: may(\"organise\"),\n remove: may(\"remove\"),\n share: may(\"share\"),\n structure: may(\"structure\"),\n why: (what) => (known ? sentenceFor(what, level) : NOT_YET),\n };\n}\n\n/** Nothing offered, because nothing is known yet. */\nexport const NOT_ANSWERED_YET: WhatYouMayDo = whatYouMayDo(null, false);\n\n/**\n * REC-27. The nine Tables the platform ships are not administered from a\n * person's screen whatever level they hold on them — so the structure controls\n * are absent for a kernel Table and say why, and everything else follows the\n * level as usual.\n */\nexport const KERNEL_REASON =\n \"This is one of the tables the platform ships, so its columns are not changed from a screen. \" +\n \"Make your own table to change columns.\";\n\nexport function whatYouMayDoWithTable(\n table: Table | null | undefined,\n level: PermissionLevel | null,\n known: boolean,\n): WhatYouMayDo {\n const base = whatYouMayDo(level, known);\n if (!table?.is_kernel) return base;\n return {\n ...base,\n structure: false,\n why: (what) => (what === \"structure\" ? KERNEL_REASON : base.why(what)),\n };\n}\n","\"use client\";\n\n// src/labels.tsx — @ai-matrx/records-ui\n//\n// WHAT AN ID IS CALLED, ONCE, FOR EVERY SCREEN THAT DRAWS A VALUE.\n//\n// A choice field stores the ID of an option record and a relation field stores\n// the ID of the record it points at (FLD-5 / FLD-6, REL-1) — that is the store\n// being right, and it is also why the 19 September verdict saw a bare\n// 36-character identifier in a relation cell, in a choice cell, and as the\n// HEADING OF EVERY KANBAN COLUMN. The pickers resolved those ids because each\n// one loaded its own list; the read-only surfaces never did, so the same value\n// read as a name in the form and as a machine id in the grid.\n//\n// One resolver, provided once inside the mount, so every surface gets the same\n// answer and asks the store once per Field rather than once per cell:\n//\n// · a list field → `custom.field_options`, which resolves the options Table\n// from the Field's own config, so no screen has to know which Table it is\n// · a relation field → the read door on the Field's declared target\n//\n// WHAT IT DOES WHILE IT IS LOOKING. It returns `null`, and every caller draws\n// the word \"Loading…\" rather than the id. Showing the id \"until it resolves\" is\n// how the defect got shipped in the first place: it looks like a value.\n\nimport { fieldOptionsOnce } from \"./askOnce\";\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { useRecordsClient, type Field, type Uuid } from \"@ai-matrx/records/react\";\nimport { newerKindExportWords, optionKey, type RecordDocument, type StoredRecord } from \"@ai-matrx/records\";\nimport { UNREAD_RECORD_LABEL, WITHHELD_RECORD_LABEL, recordName } from \"./names\";\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\nimport { isSignatureField } from \"./docs\";\nimport { signatureWords } from \"./signature\";\n\n/**\n * Answers \"what is the record with this id called\", for one Field's values. The resolver the mount\n * provides also answers `archived` — whether a referenced record sits in Archived items (an archive\n * keeps every reference to it, chair ruling B3-21) — so a chip can draw that state.\n */\nexport type LabelLookup = ((field: Field, id: string) => string | null) & {\n archived?: (field: Field, id: string) => boolean;\n /** The linked record's own icon, and its table's icon for one that has none (same call as the words). */\n icons?: (field: Field, id: string) => { icon: string | null; tableIcon: string | null } | undefined;\n};\n\nconst LabelContext = createContext<{\n lookup: LabelLookup;\n want: (field: Field) => void;\n waiting: (field: Field) => string | null;\n}>({\n // With no provider the resolver is ABSENT, not silently empty: a caller gets\n // null and says \"Loading…\" forever, which is visible. The mount always\n // provides one, so this is only ever a bare unit test.\n lookup: () => null,\n want: () => {},\n waiting: () => null,\n});\n\n/**\n * HOW LONG A CELL MAY SAY \"Loading…\" BEFORE IT HAS TO SAY WHAT IT IS WAITING\n * FOR. One second is the span at which a person stops reading a word as \"this\n * is about to happen\" and starts reading it as \"this is stuck\" — the same line\n * Nielsen's response-time work draws and the one Linear and Stripe design to.\n */\nexport const SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS = 1000;\n\n/**\n * WHAT THIS COLUMN IS WAITING FOR, in a person's words.\n *\n * 🚨 WHY A CELL MAY NOT JUST SAY \"Loading…\" (lane FRONT-DOOR, 2026-09-21;\n * VERIFIER-8 MEDIUM-1). On records-ui 0.57 the whole CUSTOMER column of a\n * 40-row Jobs grid read \"Loading…\" for 10–13 seconds with the rest of the grid\n * drawn and readable behind it. The bulk resolver below has since made that ~0.1 s\n * on the same real table — but \"Loading…\" is a word with no remedy in it, and\n * the moment a target table is big, a network is slow or a reader holds fewer\n * rows than the column points at, it is back to being a dead column that tells\n * nobody anything. A stand-in announces itself: after one second this column\n * says what it went to read.\n */\nfunction waitingLineFor(field: Field, target: string | null): string {\n return field.type === \"list\"\n ? \"Reading this column’s list of choices…\"\n : `Reading the ${target ?? \"records\"} this column points at…`;\n}\n\n/** Which ids a Field's stored value refers to. */\nexport function idsOf(value: unknown): string[] {\n if (Array.isArray(value)) return value.map(String).filter(isId);\n if (typeof value === \"string\" && isId(value)) return [value];\n return [];\n}\n\n/** Where a choice's words are kept under its KEY (ids and keys never collide: a key is no uuid). */\nexport function choiceKeyName(fieldId: string, key: string): string {\n return `${fieldId}\\u0000key\\u0000${key}`;\n}\n\nexport function isId(value: unknown): boolean {\n return typeof value === \"string\" && isUuidShape(value);\n}\n\n/** Whether the grid's own cell copy resolves this column through `shownValue` rather than the raw value. */\nexport function copiesAsWords(field: Field): boolean {\n return pointsAtRecords(field) || isSignatureField(field);\n}\n\n/** True when this Field's values are ids of other records rather than values. */\nexport function pointsAtRecords(field: Field): boolean {\n return field.type === \"list\" || field.type === \"relation\";\n}\n\n/**\n * WHAT THE PERSON SEES, NOT WHAT THE STORE KEEPS (GRID-PORT finding, 2026-09-24). A relation or a\n * choice stores the ID of the record it points at; the grid draws that record's words (\"Ojeda\n * residence\", \"Scheduled\"), and the older grid's export wrote those words too. So an exported,\n * copied or Copy-for-AI cell carries the same words the grid shows: each id resolved through the one label resolver the\n * grid uses (`useRecordLabels`). An id nobody could resolve stays the id, rather than a blank that\n * would claim the cell was empty. A worked-out column already holds the store's worked-out value.\n */\nexport function shownValue(field: Field, value: unknown, labels?: LabelLookup): unknown {\n // A DRAWN SIGNATURE is \"Signed\" wherever words are copied or exported — never its image data\n // (a spreadsheet cell cannot show it, and Excel cuts a cell at 32,767 characters). A name a\n // sealed document wrote stays the name (`signature.tsx`).\n if (isSignatureField(field)) return signatureWords(value);\n // An address, a length of time, who made it — copied and exported in words (lane 10 P4).\n const newerWords = value === null || value === undefined ? null : newerKindExportWords(field, value);\n if (newerWords !== null) return newerWords;\n if (!labels || !pointsAtRecords(field)) return value;\n const ids = idsOf(value);\n if (ids.length === 0) return value;\n const words = ids.map((id) => labels(field, id) ?? id);\n return Array.isArray(value) ? words : words[0];\n}\n\nexport function RecordLabelProvider({ children }: { children: ReactNode }) {\n const client = useRecordsClient();\n const [names, setNames] = useState<Record<string, string>>({});\n /** `${field.id}:${id}` of every referenced record the store says is archived. */\n const [archivedRefs, setArchivedRefs] = useState<Record<string, true>>({});\n /** id → the record's icon and its table's icon, learned with its words. */\n const [iconsOf, setIconsOf] = useState<Record<string, { icon: string | null; tableIcon: string | null }>>({});\n // Which Fields have FINISHED looking. Until a Field is in here its ids are\n // still loading; once it is in here, an id that is still missing is missing\n // for a reason, and the reason is asked for rather than waited out.\n const [settled, setSettled] = useState<Record<string, true>>({});\n /** Per Field: the sentence a cell shows once it has waited long enough to owe one. */\n const [waitingLines, setWaitingLines] = useState<Record<string, string>>({});\n const asked = useRef<Set<string>>(new Set());\n const chased = useRef<Set<string>>(new Set());\n const timers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n /** Start this Field's one-second clock. Cleared the moment it settles. */\n const startWaitClock = useCallback((field: Field, target: string | null) => {\n if (timers.current.has(field.id)) return;\n timers.current.set(\n field.id,\n setTimeout(() => {\n timers.current.delete(field.id);\n setWaitingLines((current) =>\n current[field.id] ? current : { ...current, [field.id]: waitingLineFor(field, target) },\n );\n }, SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS),\n );\n }, []);\n\n const stopWaitClock = useCallback((fieldId: string) => {\n const timer = timers.current.get(fieldId);\n if (timer) {\n clearTimeout(timer);\n timers.current.delete(fieldId);\n }\n setWaitingLines((current) => {\n if (!current[fieldId]) return current;\n const next = { ...current };\n delete next[fieldId];\n return next;\n });\n }, []);\n\n useEffect(\n () => () => {\n for (const timer of timers.current.values()) clearTimeout(timer);\n timers.current.clear();\n },\n [],\n );\n\n const want = useCallback(\n (field: Field) => {\n if (!pointsAtRecords(field)) return;\n if (asked.current.has(field.id)) return;\n asked.current.add(field.id);\n startWaitClock(field, null);\n\n void (async () => {\n if (field.type === \"list\") {\n const result = await fieldOptionsOnce(client, field.id);\n if (result.ok) {\n setNames((current) => {\n const next = { ...current };\n for (const option of result.data ?? []) {\n const words = recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n next[option.id] = words;\n // A CHOICE HELD BY ITS KEY READS AS ITS WORDS TOO (DATA-V2-BASICS-2): a moved list\n // and the enum nudge's Add keep `backordered`, and the grid printed the key.\n const key = optionKey(option as unknown as StoredRecord);\n if (key) next[choiceKeyName(field.id, key)] = words;\n }\n return next;\n });\n }\n setSettled((current) => ({ ...current, [field.id]: true }));\n stopWaitClock(field.id);\n return;\n }\n // ── A RELATION'S WORDS ARE THE STORE'S ANSWER, NOT THIS FILE'S (lane\n // RELATION-DISPLAY-2, 2026-09-21). ───────────────────────────────────────────\n // This branch used to read 200 rows of the target Table plus `tableList()`, find\n // the Table's `title_field` and name every row itself. That was one of three\n // copies of the same derivation, and it had three faults nobody could fix here:\n //\n // · IT COULD NOT SEE A DISPLAY SPEC. REL-DISP lets a column say it shows\n // `first_name` + \" \" + `last_name`; this code knew only `title_field`, so\n // Rincon Plumbing's two Maria Chens stayed two identical chips no matter\n // what the column was configured to show.\n // · A 200-ROW CEILING. The 201st customer was never in the prefetch and fell\n // through to the per-id chase, so a big table quietly changed how it resolved.\n // · IT NAMED WHAT IT COULD READ. The read-access ladder runs inside the store's\n // `custom._words_for`; a name assembled out here has already been read.\n //\n // So the relation branch fetches NOTHING up front. It settles immediately, and\n // the ids the page actually draws go through the queue below into ONE\n // `relation_words_many` call per Field per tick — the store's own resolver,\n // this column's own display spec, the ladder asked before the name is read.\n if (!field.relation_target) {\n setSettled((current) => ({ ...current, [field.id]: true }));\n stopWaitClock(field.id);\n return;\n }\n setSettled((current) => ({ ...current, [field.id]: true }));\n })();\n },\n [client, startWaitClock, stopWaitClock],\n );\n\n // ── WHAT AN ID IS CALLED IS THE STORE'S QUESTION (RELATION-DECLARE 2026-09-20 ·\n // FRONT-DOOR 2026-09-21 · RELATION-DISPLAY-2 2026-09-21). ────────────────────────────\n //\n // A relation joins two records in two tables, and holding one end says nothing about\n // the other: a Job shared with you may point at a Client nobody shared. The three\n // possible answers for such a chip are the target's TITLE (a leak), a bare id (a bug\n // with a hex number in it) and a permanent \"Loading…\" (a lie with a spinner on it) —\n // and picking between them is not a decision a screen is entitled to make, because the\n // screen does not know the ladder.\n //\n // So the screen does not decide. Every id a cell draws is asked of the store's ONE\n // resolver through `relation_words_many`, which:\n // · applies THIS column's display spec — one column, or several joined by its own\n // separator, which is the whole of REL-DISP and which nothing out here could do;\n // · asks the read-access ladder BEFORE it reads a name, so a record this reader may\n // not open comes back withheld rather than named;\n // · answers a WHOLE PAGE in one round trip, with no 200-row ceiling anywhere.\n //\n // 🚨 ONE ROUND FOR THE WHOLE PAGE, NOT ONE PER CELL (FRONT-DOOR). The first version of\n // this chase fired the moment a cell asked and committed its own `setNames`, so forty\n // rows cost forty round trips AND forty re-renders of every cell on the page. The ids\n // therefore still GATHER and flush once a tick — that part was right and is kept. What\n // changes is that the flush is now ONE call per Field instead of one per id: the batch\n // door this file's own comment recorded as missing (\"there is still no batch door on\n // the store\") exists as of REL-DISP, so the per-id lane is gone entirely.\n //\n // AN ID THE DOOR GAVE NO WORDS FOR is not a missing name, it is a withheld one: the\n // door answered, and the answer was nothing. It reads the SAME SENTENCE the store\n // itself gives (`platform.relation_withheld_label()`), never the title, never the id,\n // and never a \"Loading…\" that resolves for nobody.\n const queued = useRef<Map<string, { field: Field; ids: Set<string> }>>(new Map());\n const flushing = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const flush = useCallback(() => {\n flushing.current = null;\n const batch = [...queued.current.values()];\n queued.current.clear();\n if (batch.length === 0) return;\n void (async () => {\n const learned: Record<string, string> = {};\n const archivedNow: Record<string, true> = {};\n const iconsNow: Record<string, { icon: string | null; tableIcon: string | null }> = {};\n // One call per FIELD — each one carries that field's whole page of ids. Several\n // relation columns on one grid are several calls, which is the number of distinct\n // display specs in play and cannot be fewer.\n await Promise.all(\n batch.map(async ({ field, ids }) => {\n const wanted = [...ids];\n const result = await client.relationWordsMany({\n field_id: field.id,\n record_ids: wanted as Uuid[],\n });\n for (const id of wanted) {\n const words = result.ok ? result.data[id] : undefined;\n // A FAILED read is unread, never withheld — only an answer of nothing is withheld.\n learned[id] = !result.ok\n ? UNREAD_RECORD_LABEL\n : typeof words === \"string\" && words !== \"\"\n ? words\n : WITHHELD_RECORD_LABEL;\n }\n if (result.ok) for (const id of result.archived ?? []) archivedNow[`${field.id}:${id}`] = true;\n if (result.ok) for (const [id, pair] of Object.entries(result.icons ?? {})) iconsNow[id] = pair;\n }),\n );\n // ONE commit for the whole page.\n setNames((current) => ({ ...current, ...learned }));\n if (Object.keys(archivedNow).length > 0) setArchivedRefs((current) => ({ ...current, ...archivedNow }));\n if (Object.keys(iconsNow).length > 0) setIconsOf((current) => ({ ...current, ...iconsNow }));\n for (const { field } of batch) stopWaitClock(field.id);\n })();\n }, [client, stopWaitClock]);\n\n const chase = useCallback(\n (field: Field, id: string) => {\n const key = `${field.id}:${id}`;\n if (chased.current.has(key)) return;\n chased.current.add(key);\n // Grouped BY FIELD, because the door's question is \"what does THIS column call\n // these records\" — the display spec belongs to the column, so two columns pointing\n // at the same table can legitimately give the same id two different answers. The\n // old map was keyed by id alone and would have collapsed exactly that case.\n const pending = queued.current.get(field.id);\n if (pending) pending.ids.add(id);\n else queued.current.set(field.id, { field, ids: new Set([id]) });\n startWaitClock(field, null);\n if (flushing.current === null) flushing.current = setTimeout(flush, 0);\n },\n [flush, startWaitClock],\n );\n\n useEffect(\n () => () => {\n if (flushing.current !== null) clearTimeout(flushing.current);\n },\n [],\n );\n\n /** A choice key this page has not seen yet asks the Field's options again, once per key. */\n const rereadFor = useRef<Set<string>>(new Set());\n const lookupWords = useCallback(\n (field: Field, id: string): string | null => {\n if (field.type === \"list\" && !isId(id)) {\n const named = names[choiceKeyName(field.id, id)];\n if (named !== undefined) return named;\n const once = choiceKeyName(field.id, id);\n if (settled[field.id] && !rereadFor.current.has(once)) {\n // A choice added after the options were read (the nudge's Add): read them again.\n rereadFor.current.add(once);\n asked.current.delete(field.id);\n want(field);\n }\n return null;\n }\n const known = names[id];\n if (known !== undefined) return known;\n if (settled[field.id]) chase(field, id);\n return null;\n },\n [names, settled, chase, want],\n );\n const lookup = useMemo<LabelLookup>(\n () => {\n const answer = ((field: Field, id: string) => lookupWords(field, id)) as LabelLookup;\n answer.archived = (field: Field, id: string) => archivedRefs[`${field.id}:${id}`] === true;\n answer.icons = (_field: Field, id: string) => iconsOf[id];\n return answer;\n },\n [lookupWords, archivedRefs, iconsOf],\n );\n\n const waiting = useCallback((field: Field) => waitingLines[field.id] ?? null, [waitingLines]);\n\n const value = useMemo(() => ({ lookup, want, waiting }), [lookup, want, waiting]);\n return <LabelContext.Provider value={value}>{children}</LabelContext.Provider>;\n}\n\n/**\n * The hook a surface uses: it declares the Fields it is about to draw, and gets\n * back the lookup. Declaring is what makes one request per Field instead of one\n * per cell, and it is why a grid of 200 rows asks the store twice.\n */\nexport function useRecordLabels(fields: readonly Field[] | undefined): LabelLookup {\n const { lookup, want } = useContext(LabelContext);\n useEffect(() => {\n for (const field of fields ?? []) want(field);\n }, [fields, want]);\n return lookup;\n}\n\n/**\n * WHAT THIS COLUMN IS STILL WAITING FOR, or null while \"Loading…\" is still an\n * honest word. A cell draws this INSTEAD of \"Loading…\" once the resolver has\n * been looking for a second — see `SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS`.\n */\nexport function useLabelWait(field: Field | undefined): string | null {\n const { waiting } = useContext(LabelContext);\n return field ? waiting(field) : null;\n}\n","\"use client\";\n\n// src/signature.tsx — @ai-matrx/records-ui · lane 10 VIEWS-AND-FIELDS W1-A\n//\n// A SIGNATURE IS DRAWN, AND IT IS SEEN AS A DRAWING.\n//\n// The store keeps a Signature column as `type: text, format: signature`\n// (`custom.doc_signature_field_ok`). Through a form, the value it takes is a string, and the\n// drawing travels as the same `data:image/(png|jpeg);base64,…` URL `custom.sign_request_sign`\n// already validates for its drawn mark — one image format for every signature on the platform.\n// A signature the document door sealed (`custom.doc_sign`) is the signer's NAME instead; both\n// read back here: a drawing as an image, a name as the name.\n//\n// THE PAD was lifted from matrx-frontend's `/sign/[token]` DrawPad (canvas + pointer events, no\n// library, `touch-none` so a phone draws instead of scrolling) so there is one pad, here, that\n// every host and every form shares. Ink is always dark on a white sheet (a stored image must read in\n// both themes — cells invert it in dark mode).\n//\n// 🚨 SIZE. A drawing's encoded size depends on what is drawn, not on the canvas: a dense signature\n// measured ~310 kB as a 600-px PNG (verifier, 2026-10-02) against the store's `value_max_bytes`\n// default of 100,000 — and over the ceiling the store keeps a cell's first 1,000 characters, which\n// is a broken image. So `fitDrawing` re-encodes down a ladder (smaller PNGs, then JPEG on white)\n// until the value is under `SIGNATURE_BUDGET_BYTES`; when nothing fits the pad sends nothing and\n// says so, so a form can never submit a signature the store would cut.\n//\n// WHERE THE DRAWING GOES is decided in ONE place, `fitDrawing`'s caller (`end` below) handing a data\n// URL to `onChange`. A form sends that data URL as the answer, and `custom.form_submit` (CHAIR-DOORS-1,\n// live 2026-10-02) turns it into a File record: the record keeps the word \"Signed\" and its value's\n// source names the File (`{kind: 'signature', mark: 'drawn', signature_file_id, signed_at, via:\n// 'form', form_id}`). The ladder still guards a FORM too: the File keeps the drawing inline as its\n// `content`, and one value is capped at 100,000 bytes there as anywhere (measured on the clone,\n// 2026-10-02: a 312,024-byte drawing was refused by `custom._value_envelope`).\n//\n// READING IT BACK. A drawing kept inline (every value written before the File door, a sign-link,\n// an offline capture) is drawn as it is. \"Signed\" whose source names a File is drawn from that File\n// (`SignatureDrawing`): the source through `recordValuesVersioned` (the read doors give the value\n// without its envelope), then the File record's `content`; a File the host keeps elsewhere draws\n// through the host's `fileImage` port, the gallery's picture renderer. Until it is read, and when it\n// cannot be, the cell says \"Signed\" — never a broken image.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Button, ErrorBox, cn } from \"@ai-matrx/design-system\";\nimport type { RecordDocument, Uuid } from \"@ai-matrx/records\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { isSignatureField } from \"./docs\";\nimport { useRecordsUi } from \"./host\";\n\n/** The exact shape `custom.sign_request_sign` accepts for a drawn mark. */\nconst DRAWN = /^data:image\\/(png|jpeg);base64,[A-Za-z0-9+/=]{64,}$/;\n\n/** Whether this column is a Signature column — the one test, `docs.ts` (VAL-10). */\nexport { isSignatureField };\n\n/** The drawing a signature value holds, or null when it holds none (empty, or a signer's name). */\nexport function drawnSignatureOf(value: unknown): string | null {\n return typeof value === \"string\" && DRAWN.test(value) ? value : null;\n}\n\n/** The word a text-only place (a card title, a sentence, an export) writes for a drawn signature. */\nexport const SIGNED_WORD = \"Signed\";\n\n/** A signature value in words: a drawing is \"Signed\"; a sealed name stays the name. */\nexport function signatureWords(value: unknown): string | null {\n if (value === null || value === undefined || value === \"\") return null;\n return drawnSignatureOf(value) ? SIGNED_WORD : String(value);\n}\n\n/** The File a signature value's source names (`custom.form_submit`, `custom.sign_request_sign`). */\nexport function signatureFileOf(source: unknown): string | null {\n if (!source || typeof source !== \"object\") return null;\n const src = source as Record<string, unknown>;\n const id = src[\"signature_file_id\"];\n return src[\"kind\"] === \"signature\" && typeof id === \"string\" && id !== \"\" ? id : null;\n}\n\n/**\n * The File a stored document's envelope names for one key, when the document carries its envelope\n * (`_values.<key>.src`, inline or a pointer into `_sources`). The read doors strip both, so a\n * screen usually has to ask (`SignatureDrawing`); a document that has them is answered here.\n */\nexport function signatureFileIn(document: RecordDocument | null | undefined, key: string): string | null {\n const values = document?.[\"_values\"] as Record<string, { src?: unknown }> | undefined;\n const src = values?.[key]?.src;\n if (typeof src === \"string\") {\n const sources = document?.[\"_sources\"] as Record<string, unknown> | undefined;\n return signatureFileOf(sources?.[src]);\n }\n return signatureFileOf(src);\n}\n\n/** What one record's signature File holds, as a picture: an inline drawing, or a host file id. */\ntype Drawing = { src: string | null; hostFileId: string | null };\n\nconst SOURCES = new WeakMap<RecordsClient, Map<string, Promise<Record<string, string | null>>>>();\nconst FILES = new WeakMap<RecordsClient, Map<string, Promise<Drawing>>>();\n\n/** Every signature File one record's values name, by field key — one read per record. */\nfunction signatureFilesOf(client: RecordsClient, recordId: string): Promise<Record<string, string | null>> {\n let held = SOURCES.get(client);\n if (!held) SOURCES.set(client, (held = new Map()));\n let asked = held.get(recordId);\n if (!asked) {\n asked = client.recordValuesVersioned({ record_id: recordId as Uuid }).then((answered) => {\n if (!answered.ok) return {};\n return Object.fromEntries(answered.data.map((v) => [v.field_key, signatureFileOf(v.source)]));\n });\n held.set(recordId, asked);\n }\n return asked;\n}\n\n/** The picture a signature File holds — one read per File. */\nfunction drawingOf(client: RecordsClient, fileId: string): Promise<Drawing> {\n let held = FILES.get(client);\n if (!held) FILES.set(client, (held = new Map()));\n let asked = held.get(fileId);\n if (!asked) {\n asked = client.recordRead({ record_id: fileId as Uuid }).then((answered) => {\n if (!answered.ok) return { src: null, hostFileId: null };\n const doc = (answered.data.document ?? {}) as RecordDocument;\n const content = drawnSignatureOf(doc[\"content\"]);\n const hostFileId = typeof doc[\"file_id\"] === \"string\" && doc[\"file_id\"] !== \"\" ? (doc[\"file_id\"] as string) : null;\n return { src: content, hostFileId };\n });\n held.set(fileId, asked);\n }\n return asked;\n}\n\nfunction DrawnImage({ src, inCell }: { src: string; inCell?: boolean | undefined }) {\n return (\n <img\n src={src}\n alt={SIGNED_WORD}\n data-records-signature=\"\"\n className={cn(\"max-w-[12rem] object-contain object-left dark:invert\", inCell ? \"h-7\" : \"h-12\")}\n />\n );\n}\n\n/** \"Signed\" whose drawing is a File: read the File, draw it; say \"Signed\" until then. */\nfunction SignatureDrawing({\n recordId,\n fieldKey,\n fileId: knownFile,\n value,\n inCell,\n}: {\n recordId: string | null;\n fieldKey: string | null;\n fileId: string | null;\n value: unknown;\n inCell?: boolean | undefined;\n}) {\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [drawing, setDrawing] = useState<Drawing | null>(null);\n useEffect(() => {\n let cancelled = false;\n setDrawing(null);\n if (!client) return;\n void (async () => {\n const fileId = knownFile ?? (recordId && fieldKey ? (await signatureFilesOf(client, recordId))[fieldKey] ?? null : null);\n if (!fileId || cancelled) return;\n const read = await drawingOf(client, fileId);\n if (!cancelled) setDrawing(read);\n })();\n return () => {\n cancelled = true;\n };\n }, [client, recordId, fieldKey, knownFile]);\n if (drawing?.src) return <DrawnImage src={drawing.src} inCell={inCell} />;\n if (drawing?.hostFileId && host.fileImage) {\n return (\n <span className={cn(\"inline-block max-w-[12rem] dark:invert\", inCell ? \"h-7\" : \"h-12\")} data-records-signature=\"\">\n {host.fileImage({ fileId: drawing.hostFileId as Uuid, alt: SIGNED_WORD })}\n </span>\n );\n }\n return <span className=\"font-serif italic\">{String(value)}</span>;\n}\n\n/**\n * A signature as it reads anywhere a value is shown: the drawing, or the signer's name. A drawing\n * kept as a File (a form's, `custom.form_submit`) needs to know whose value this is: `recordId` and\n * `fieldKey`, or the `document` when it carries its envelope.\n */\nexport function SignatureValue({\n value,\n inCell,\n recordId,\n fieldKey,\n document,\n}: {\n value: unknown;\n inCell?: boolean | undefined;\n recordId?: string | null | undefined;\n fieldKey?: string | null | undefined;\n document?: RecordDocument | null | undefined;\n}) {\n const drawn = drawnSignatureOf(value);\n if (drawn) return <DrawnImage src={drawn} inCell={inCell} />;\n const fileId = fieldKey ? signatureFileIn(document, fieldKey) : null;\n if (value === SIGNED_WORD && (fileId || (recordId && fieldKey))) {\n return <SignatureDrawing recordId={recordId ?? null} fieldKey={fieldKey ?? null} fileId={fileId} value={value} inCell={inCell} />;\n }\n return <span className=\"font-serif italic\">{String(value)}</span>;\n}\n\nconst INK = \"#111827\";\n\n/** The most a drawn signature may weigh as a value — well under the store's 100,000-byte default. */\nexport const SIGNATURE_BUDGET_BYTES = 60_000;\n\n/** Said on the pad when even the smallest encoding of a drawing is over the budget. */\nexport const SIGNATURE_TOO_DETAILED = \"Too detailed to save — clear and sign again.\";\n\n/**\n * THE ONE SIGNATURE PAD. Draw with a finger, a pen or a mouse; Clear starts again. `onChange`\n * receives the drawing as a PNG data URL when a stroke ends, and `null` when cleared.\n */\nexport function SignaturePad({\n value,\n onChange,\n disabled,\n id,\n className,\n}: {\n value: unknown;\n onChange: (value: string | null) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n}) {\n const kept = drawnSignatureOf(value);\n const named = !kept && typeof value === \"string\" && value !== \"\" ? value : null;\n // A value already there when the control opens is shown as itself until somebody chooses to\n // sign again; once the pad is open it stays open while they draw (their own strokes come back\n // as `value` and must not swap the pad for a picture mid-signature).\n const [showPad, setShowPad] = useState(() => !kept && !named);\n\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const drawing = useRef(false);\n const [dirty, setDirty] = useState(false);\n const [tooBig, setTooBig] = useState(false);\n\n useEffect(() => {\n if (!showPad) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n // Backed at device resolution so the strokes are not blurred squares on the phone.\n const ratio = window.devicePixelRatio || 1;\n const rect = canvas.getBoundingClientRect();\n canvas.width = Math.round(rect.width * ratio);\n canvas.height = Math.round(rect.height * ratio);\n const context = canvas.getContext(\"2d\");\n if (!context) return;\n context.scale(ratio, ratio);\n context.lineWidth = 2.2;\n context.lineCap = \"round\";\n context.lineJoin = \"round\";\n context.strokeStyle = INK;\n }, [showPad]);\n\n const point = (event: React.PointerEvent<HTMLCanvasElement>) => {\n const rect = event.currentTarget.getBoundingClientRect();\n return { x: event.clientX - rect.left, y: event.clientY - rect.top };\n };\n\n const start = (event: React.PointerEvent<HTMLCanvasElement>) => {\n if (disabled) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n const context = canvasRef.current?.getContext(\"2d\");\n if (!context) return;\n const { x, y } = point(event);\n context.beginPath();\n context.moveTo(x, y);\n drawing.current = true;\n };\n\n const move = (event: React.PointerEvent<HTMLCanvasElement>) => {\n if (!drawing.current) return;\n const context = canvasRef.current?.getContext(\"2d\");\n if (!context) return;\n const { x, y } = point(event);\n context.lineTo(x, y);\n context.stroke();\n if (!dirty) setDirty(true);\n };\n\n const end = () => {\n if (!drawing.current) return;\n drawing.current = false;\n const canvas = canvasRef.current;\n if (!canvas) return;\n // THE ONE PLACE the drawing becomes a value (see the header: CHAIR-DOORS-1 changes this line).\n const fitted = fitDrawing(canvas);\n setTooBig(fitted === null);\n onChange(fitted);\n setDirty(true);\n };\n\n const clear = () => {\n const canvas = canvasRef.current;\n const context = canvas?.getContext(\"2d\");\n if (canvas && context) {\n context.save();\n context.setTransform(1, 0, 0, 1, 0, 0);\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.restore();\n }\n setDirty(false);\n setTooBig(false);\n setShowPad(true);\n onChange(null);\n };\n\n if (!showPad) {\n return (\n <div id={id} className={cn(\"flex items-center justify-between gap-2 rounded-md border px-3 py-2\", className)}>\n <SignatureValue value={value} />\n {!disabled ? (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={clear}>\n Sign again\n </Button>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className={cn(\"flex w-full flex-col gap-1\", className)}>\n <div className=\"relative\">\n <canvas\n id={id}\n ref={canvasRef}\n role=\"img\"\n aria-label=\"Signature pad\"\n data-records-signature-pad=\"\"\n onPointerDown={start}\n onPointerMove={move}\n onPointerUp={end}\n onPointerLeave={end}\n onPointerCancel={end}\n // `touch-none` or a phone scrolls the page instead of drawing.\n className={cn(\n \"block h-36 w-full touch-none rounded-md border border-border bg-white\",\n disabled ? \"cursor-not-allowed opacity-60\" : \"cursor-crosshair\",\n )}\n />\n {!dirty ? (\n <span className=\"pointer-events-none absolute inset-x-0 bottom-3 text-center text-xs text-neutral-400\">\n Sign here\n </span>\n ) : null}\n </div>\n <div className=\"flex items-center justify-end gap-2\">\n {tooBig ? (\n <ErrorBox\n as=\"span\"\n className=\"mr-auto text-xs text-destructive\"\n message={SIGNATURE_TOO_DETAILED}\n operation=\"Save a signature\"\n origin=\"records-ui/signature\"\n />\n ) : null}\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={clear} disabled={disabled || !dirty}>\n Clear\n </Button>\n </div>\n </div>\n );\n}\n\n/** The encodings tried in order, smallest-loss first: [format, max width, JPEG quality]. */\nconst LADDER: Array<[\"image/png\" | \"image/jpeg\", number, number]> = [\n [\"image/png\", 600, 1],\n [\"image/png\", 400, 1],\n [\"image/jpeg\", 600, 0.7],\n [\"image/jpeg\", 400, 0.6],\n [\"image/jpeg\", 300, 0.5],\n];\n\n/**\n * The drawing as the smallest-loss data URL under `SIGNATURE_BUDGET_BYTES`, or null when none\n * fits. JPEG has no transparency, so it is drawn on white (the pad's own sheet).\n */\nexport function fitDrawing(canvas: HTMLCanvasElement): string | null {\n for (const [type, maxWidth, quality] of LADDER) {\n const encoded = encodeAt(canvas, type, maxWidth, quality);\n if (encoded && encoded.length <= SIGNATURE_BUDGET_BYTES) return encoded;\n }\n return null;\n}\n\nfunction encodeAt(canvas: HTMLCanvasElement, type: \"image/png\" | \"image/jpeg\", maxWidth: number, quality: number): string | null {\n const width = Math.min(maxWidth, canvas.width || maxWidth);\n const scale = canvas.width > 0 ? width / canvas.width : 1;\n const out = document.createElement(\"canvas\");\n out.width = width;\n out.height = Math.max(1, Math.round((canvas.height || 1) * scale));\n const context = out.getContext(\"2d\");\n if (!context) return null;\n if (type === \"image/jpeg\") {\n context.fillStyle = \"#ffffff\";\n context.fillRect(0, 0, out.width, out.height);\n }\n context.drawImage(canvas, 0, 0, out.width, out.height);\n return out.toDataURL(type, quality);\n}\n","\"use client\";\n\n// src/FilePicker.tsx — @ai-matrx/records-ui · FIX-10C F10\n//\n// CHOOSING A FILE, DRAWN THE WAY THIS PLATFORM DRAWS EVERY OTHER CONTROL.\n//\n// WHAT THIS REPLACES, measured (VERIFIER-10 F10, 2026-09-22): pressing Import\n// produced `Import Jobs [Choose File] No file chosen` — the browser's own\n// unstyled control, in the browser's own font, with no instruction, no example\n// of what the file should look like and no way out. Airtable and Notion both\n// open an EXPLAINED import screen at this exact moment; a raw `<input\n// type=file>` is the one control on the screen that did not come from the\n// design system.\n//\n// AND IT IS A CLASS, NOT A SCREEN. Four components in this package drew their\n// own bare file input — the import wizard, the public form runner, the capture\n// sheet and the capture run. Four spellings of \"pick a file\", four different\n// accept lists, four different (absent) instructions. This is the one control,\n// built on `@ai-matrx/design-system`'s Button so it inherits focus rings, sizes,\n// disabled styling and dark mode like everything else, and exported so a host\n// app can use it too.\n//\n// WHAT IT PROMISES:\n// · it says what a good file looks like BEFORE the person opens their finder;\n// · it names the file once chosen, and offers to choose a different one —\n// never a control that silently keeps the old file;\n// · drag and drop works, because the file is usually already in a folder the\n// person is looking at;\n// · the native input is still the mechanism (it is the only thing that can\n// open a file dialog) — it is visually hidden and reached by label, so\n// keyboard and screen readers get the real control, not a div pretending.\n\nimport { useCallback, useId, useRef, useState, type DragEvent, type ReactNode } from \"react\";\nimport { Button, cn } from \"@ai-matrx/design-system\";\n\nexport interface FilePickerProps {\n /** What the button says when nothing is chosen yet. */\n label: string;\n /** The `accept` list, exactly as the native input takes it. */\n accept?: string | undefined;\n /**\n * The accessible name of the file input itself, when it must differ from the\n * button's word — an import screen's input has been called \"Choose a file to\n * import\" since it existed, and every automation and screen-reader script\n * that knows this screen resolves that sentence. A name is a contract.\n */\n inputLabel?: string | undefined;\n /**\n * One sentence describing a good file — the thing the bare input never said.\n * Shown under the control, before anything is chosen.\n */\n hint?: ReactNode;\n disabled?: boolean | undefined;\n /** The chosen file. Called once per choice; re-choosing calls it again. */\n onFile: (file: File) => void;\n /** Forget the chosen file and go back to the empty state. */\n onClear?: (() => void) | undefined;\n /** The name of the file currently in play, when the owner is holding one. */\n chosenName?: string | null | undefined;\n className?: string | undefined;\n}\n\nexport function FilePicker({\n label,\n accept,\n inputLabel,\n hint,\n disabled = false,\n onFile,\n onClear,\n chosenName,\n className,\n}: FilePickerProps) {\n const inputId = useId();\n const input = useRef<HTMLInputElement | null>(null);\n const [over, setOver] = useState(false);\n\n const take = useCallback(\n (file: File | undefined | null) => {\n if (!file || disabled) return;\n onFile(file);\n },\n [disabled, onFile],\n );\n\n const onDrop = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n setOver(false);\n take(e.dataTransfer?.files?.[0]);\n },\n [take],\n );\n\n return (\n <div\n data-matrx-file-picker\n className={cn(\"flex min-w-0 flex-col gap-1\", className)}\n onDragOver={(e) => {\n if (disabled) return;\n e.preventDefault();\n setOver(true);\n }}\n onDragLeave={() => setOver(false)}\n onDrop={onDrop}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-dashed px-2 py-1.5\",\n over ? \"border-primary bg-primary/5\" : \"border-border\",\n disabled && \"opacity-60\",\n )}\n >\n {/* The real control — the only thing that can open a file dialog.\n Visually hidden rather than `display:none`, so it keeps its own\n accessible name and can still be driven; the Button beside it is the\n keyboard and pointer control, so this one is out of the tab order\n rather than a second stop that does the same thing. */}\n <input\n ref={input}\n id={inputId}\n type=\"file\"\n aria-label={inputLabel ?? label}\n tabIndex={-1}\n {...(accept ? { accept } : {})}\n disabled={disabled}\n className=\"sr-only\"\n onChange={(e) => {\n take(e.target.files?.[0]);\n // Choosing THE SAME file twice has to fire again — a person who\n // fixed the file and picked it again would otherwise press a\n // control that does nothing.\n e.target.value = \"\";\n }}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => input.current?.click()}\n >\n {chosenName ? \"Choose a different file\" : label}\n </Button>\n {chosenName ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\" title={chosenName}>\n {chosenName}\n </span>\n ) : (\n <span className=\"text-xs text-muted-foreground\">or drop it here</span>\n )}\n {chosenName && onClear ? (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={disabled} onClick={onClear}>\n Cancel\n </Button>\n ) : null}\n </div>\n {hint && !chosenName ? <p className=\"text-xs text-muted-foreground\">{hint}</p> : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/EntityReferenceControl.tsx — @ai-matrx/records-ui · lane SC-R (P12), REFERENCE-CARRY\n//\n// A CELL THAT POINTS AT A PLATFORM THING — the intake note of a client matter, the client's web\n// site, the agent a row runs — drawn as what it names, never as `[object Object]` in a text box,\n// and edited with a PICKER, never by typing ids.\n//\n// Every read door answers an entity-reference value as `{token, id, label}`, the label withheld\n// (null) from a reader who may not open the thing. This control draws one chip per reference with\n// the store's label (or, for a value not yet saved, the words `useEntityReferenceWords` reads for\n// THIS person), lets a person take a reference off, and — since lane REFERENCE-CARRY — ADD one:\n// the store's search door (`custom.entity_reference_search`) lists the things of the column's kinds\n// this person may point a record at, each one the store's own write check would accept.\n\nimport { useMemo, useState, type ReactNode } from \"react\";\nimport { entityRefsOf, entityRefsToWrite, type EntityRefWithWords, type Field } from \"@ai-matrx/records\";\nimport { useEntityReferenceKinds, useEntityReferenceSearch, useEntityReferenceWords, useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { Badge, Button, cn } from \"@ai-matrx/design-system\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { RefusalLine } from \"./Refusal\";\nimport { PickOne } from \"./PickOne\";\n\n/** What a chip says when the store withheld the thing's words from this reader. */\nexport const WITHHELD_ENTITY_LABEL = \"Something you have not been given access to\";\n\n/** What an empty entity-reference cell says where nothing can be added (a signed-out form). */\nexport const ENTITY_REFERENCE_EMPTY = \"Nothing is pointed at yet.\";\n\n/** The words of an entity-reference value for a sentence or a plain-text cell. */\nexport function entityReferenceText(value: unknown): string {\n const refs = entityRefsOf(value);\n if (refs.length === 0) return \"—\";\n return refs.map((r) => r.label ?? WITHHELD_ENTITY_LABEL).join(\", \");\n}\n\n/** The kinds a column may point at (`config.allowed_types`), in the order it names them. */\nexport function allowedKindsOf(field: Field): string[] {\n const config = (field.config ?? {}) as Record<string, unknown>;\n const kinds = Array.isArray(config.allowed_types) ? config.allowed_types : [];\n return kinds.map((k) => String(k).trim().toLowerCase()).filter(Boolean);\n}\n\nexport interface EntityReferenceControlProps {\n field: Field;\n value: unknown;\n onChange: (next: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n}\n\n/**\n * A signed-out public form mounts no store client, so there is nobody to ask for words or search:\n * the chips there draw what the value already carries and nothing can be added. Inside a client the\n * unlabelled ones are read and the picker is offered.\n */\nexport function EntityReferenceControl(props: EntityReferenceControlProps) {\n const client = useOptionalRecordsClient();\n return client ? <WithWords {...props} /> : <Chips {...props} words={null} picker={null} />;\n}\n\ntype Words = { data: { token: string; id: string; label: string | null }[] | null; loading: boolean } | null;\n\nfunction WithWords(props: EntityReferenceControlProps) {\n const refs = useMemo(() => entityRefsOf(props.value), [props.value]);\n // Picked in this editing session: their words are known, so nobody is asked for them again.\n const [known, setKnown] = useState<EntityRefWithWords[]>([]);\n const withKnown = refs.map((r) => (r.label === null ? (known.find((k) => k.token === r.token && k.id === r.id) ?? r) : r));\n // Only the references that arrived WITHOUT words (a value not yet saved) are asked about.\n const unlabelled = useMemo(\n () => withKnown.filter((r) => r.label === null).map((r) => ({ token: r.token, id: r.id })),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(withKnown)],\n );\n const words = useEntityReferenceWords(unlabelled);\n const picker = props.disabled ? null : (\n <EntityReferencePicker\n field={props.field}\n refs={withKnown}\n onPick={(picked) => {\n setKnown((k) => [...k.filter((x) => !(x.token === picked.token && x.id === picked.id)), picked]);\n const multi = Boolean(props.field.multi);\n const next = multi ? [...withKnown.filter((x) => !(x.token === picked.token && x.id === picked.id)), picked] : [picked];\n props.onChange(entityRefsToWrite(next, multi));\n }}\n />\n );\n return <Chips {...props} value={withKnown} words={words} picker={picker} />;\n}\n\n/**\n * THE PICKER: which kind (when the column allows more than one), a search box, the things found.\n * Built from the one pick-or-add builder (`PickOrAdd.tsx`), so it keeps the keys every picker keeps.\n * There is no add line: a platform thing is made where it lives, never from a table cell.\n */\nfunction EntityReferencePicker({\n field,\n refs,\n onPick,\n}: {\n field: Field;\n refs: EntityRefWithWords[];\n onPick: (picked: EntityRefWithWords) => void;\n}) {\n const allowed = allowedKindsOf(field);\n const kinds = useEntityReferenceKinds();\n const labelOfKind = (token: string) => kinds.data?.find((k) => k.token === token)?.label ?? token.replace(/_/g, \" \");\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n // \"Any of them\" first; one kind narrows the list.\n const [only, setOnly] = useState<string | null>(null);\n const tokens = only ? [only] : allowed;\n const found = useEntityReferenceSearch(tokens, search, open);\n const multi = Boolean(field.multi);\n const items = (found.data ?? []).map((r) => ({\n id: `${r.token}:${r.id}`,\n label: r.label ?? WITHHELD_ENTITY_LABEL,\n detail: allowed.length > 1 ? labelOfKind(r.token) : null,\n picked: refs.some((x) => x.token === r.token && x.id === r.id),\n attrs: { \"data-entity-reference-candidate\": `${r.token}:${r.id}` },\n }));\n const kindChoice =\n allowed.length > 1 ? (\n allowed.length <= 4 ? (\n <div className=\"mb-1 flex flex-wrap gap-1\" role=\"group\" aria-label={`Which kind — ${field.label}`}>\n {[null, ...allowed].map((token) => (\n <Button\n key={token ?? \"any\"}\n type=\"button\"\n size=\"sm\"\n variant={only === token ? \"secondary\" : \"ghost\"}\n className=\"h-6 px-2 text-[11px]\"\n aria-pressed={only === token}\n onClick={() => setOnly(token)}\n >\n {token ? labelOfKind(token) : \"Any\"}\n </Button>\n ))}\n </div>\n ) : (\n <PickOne\n label={`Which kind — ${field.label}`}\n className=\"mb-1 w-full\"\n value={only ?? \"\"}\n onChange={(picked) => setOnly(picked || null)}\n options={[{ value: \"\", label: \"Any kind\" }, ...allowed.map((token) => ({ value: token, label: labelOfKind(token) }))]}\n />\n )\n ) : null;\n const notice = (\n <>\n {kindChoice}\n {found.error ? <RefusalLine error={found.error} className=\"px-2 py-1 text-[11px]\" /> : null}\n {found.loading && !found.data ? <p className=\"px-2 py-1 text-[11px] text-muted-foreground\">Searching…</p> : null}\n </>\n );\n const kindWords = allowed.length === 1 ? labelOfKind(allowed[0]!).toLowerCase() : \"thing\";\n return (\n <PickOrAdd\n triggerLabel={`Pick for ${field.label}`}\n triggerText={refs.length > 0 && !multi ? \"Change\" : \"Pick\"}\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearch(\"\");\n }}\n search={search}\n onSearch={setSearch}\n items={items}\n notice={notice}\n empty={\n found.loading ? null : (\n <p className=\"px-2 py-1 text-[11px] text-muted-foreground\">\n {search.trim() ? `No ${kindWords} you can open is called “${search.trim()}”.` : `There is no ${kindWords} you can open yet.`}\n </p>\n )\n }\n onPick={(key) => {\n const r = (found.data ?? []).find((x) => `${x.token}:${x.id}` === key);\n if (!r) return;\n onPick(r);\n if (!multi) setOpen(false);\n }}\n />\n );\n}\n\nfunction Chips({\n field,\n value,\n onChange,\n disabled,\n id,\n className,\n words,\n picker,\n}: EntityReferenceControlProps & { words: Words; picker: ReactNode }) {\n const refs = useMemo(() => entityRefsOf(value), [value]);\n const labelOf = (token: string, refId: string, own: string | null): string => {\n if (own) return own;\n const read = words?.data?.find((w) => w.token === token && w.id === refId)?.label;\n if (read) return read;\n if (words === null) return \"A linked item (its name is read when you are signed in)\";\n if (words.loading) return \"Reading…\";\n return WITHHELD_ENTITY_LABEL;\n };\n const multi = Boolean(field.multi);\n\n return (\n <div id={id} className={cn(\"flex flex-wrap items-center gap-1\", className)} aria-label={`What ${field.label} points at`}>\n {refs.length === 0 && !picker ? <span className=\"text-[11px] text-muted-foreground\">{ENTITY_REFERENCE_EMPTY}</span> : null}\n {refs.map((r) => {\n const label = labelOf(r.token, r.id, r.label);\n return (\n <Badge key={`${r.token}:${r.id}`} variant=\"secondary\" className=\"gap-1 text-[11px]\" data-entity-reference-chip={`${r.token}:${r.id}`}>\n {label}\n {disabled ? null : (\n <button\n type=\"button\"\n className=\"ml-0.5 rounded-sm px-0.5 opacity-70 hover:opacity-100\"\n aria-label={`Take ${label} off`}\n onClick={() => {\n const rest = refs.filter((x) => !(x.token === r.token && x.id === r.id));\n onChange(entityRefsToWrite(rest, multi));\n }}\n >\n ×\n </button>\n )}\n </Badge>\n );\n })}\n {picker}\n </div>\n );\n}\n","\"use client\";\n\n// src/PickOne.tsx — @ai-matrx/records-ui · THE ONE \"PICK ONE OF THESE\" CONTROL (lane VIEWS-AND-FIELDS\n// W1-B, verifier item 4, 2026-10-02 — Airtable, Linear).\n//\n// The package drew about forty-five native <select>s: an OS menu that ignores the theme, cannot be\n// searched, and reads differently from every picker beside it. Every pick of one value from a list\n// now goes through here: the design system's Select for a short list, and past\n// `PICK_ONE_SEARCH_AFTER` options the package's own searchable list (`PickOrAdd`), so a table with\n// thirty columns is typed into, never scrolled. Guard: `no-native-select-in-the-package.test.ts`.\n//\n// An empty value (\"\" — \"no sort\", \"count only\", \"any kind\") is a real option here: Radix refuses an\n// empty item value, so it travels as a sentinel inside and comes back out as \"\".\n\nimport { useState } from \"react\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, cn } from \"@ai-matrx/design-system\";\n\nimport { PickOrAdd } from \"./PickOrAdd\";\n\n/** One option: its value (may be \"\") and the words it reads as. */\nexport interface PickOneOption {\n value: string;\n label: string;\n /** The heading it sits under (a short list draws headings; a searchable one shows it under the item). */\n group?: string | undefined;\n}\n\n/** More options than this and the list is searchable. */\nexport const PICK_ONE_SEARCH_AFTER = 7;\n\nconst EMPTY = \"__records_pick_one_empty__\";\nconst inner = (v: string) => (v === \"\" ? EMPTY : v);\nconst outer = (v: string) => (v === EMPTY ? \"\" : v);\n\nexport function PickOne({\n value,\n onChange,\n options,\n label,\n placeholder,\n id,\n className,\n disabled,\n attrs,\n}: {\n value: string;\n onChange: (value: string) => void;\n options: readonly PickOneOption[];\n /** The control's accessible name. */\n label: string;\n /** What the trigger reads when the value is none of the options. */\n placeholder?: string | undefined;\n id?: string | undefined;\n className?: string | undefined;\n disabled?: boolean | undefined;\n /** Attributes a caller's tests and walks select by (`data-…`), put on the trigger. */\n attrs?: Record<string, string> | undefined;\n}) {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const current = options.find((o) => o.value === value);\n\n if (options.length > PICK_ONE_SEARCH_AFTER) {\n const q = search.trim().toLowerCase();\n const shown = q === \"\" ? options : options.filter((o) => o.label.toLowerCase().includes(q));\n return (\n <span className={cn(\"inline-flex min-w-0\", className)} data-records-pick-one=\"search\" data-pick-value={value} {...(attrs ?? {})}>\n <PickOrAdd\n triggerSize=\"compact\"\n triggerLabel={label}\n triggerText={current?.label ?? placeholder ?? \"\"}\n triggerId={id}\n open={open && !disabled}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearch(\"\");\n }}\n search={search}\n onSearch={setSearch}\n items={shown.map((o) => ({\n id: inner(o.value),\n label: o.label,\n detail: o.group,\n picked: o.value === value,\n attrs: { \"data-pick-value\": o.value, ...(o.group ? { \"data-pick-group\": o.group } : {}) },\n }))}\n onPick={(picked) => {\n onChange(outer(picked));\n setOpen(false);\n setSearch(\"\");\n }}\n empty={<p className=\"p-2 text-xs text-muted-foreground\">No match</p>}\n />\n </span>\n );\n }\n return (\n <Select value={current ? inner(current.value) : \"\"} onValueChange={(v) => onChange(outer(v))} disabled={disabled ?? false}>\n <SelectTrigger\n id={id}\n size=\"sm\"\n aria-label={label}\n className={cn(\"h-7 w-auto min-w-[7rem] text-xs\", className)}\n data-records-pick-one=\"list\"\n data-pick-value={value}\n {...(attrs ?? {})}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {groupsOf(options).map(([group, items]) =>\n group ? (\n <SelectGroup key={group}>\n <SelectLabel>{group}</SelectLabel>\n {items.map((o) => (\n <SelectItem key={inner(o.value)} value={inner(o.value)} data-pick-value={o.value} data-pick-group={group}>\n {o.label}\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n items.map((o) => (\n <SelectItem key={inner(o.value)} value={inner(o.value)} data-pick-value={o.value}>\n {o.label}\n </SelectItem>\n ))\n ),\n )}\n </SelectContent>\n </Select>\n );\n}\n\n/** Options in their own order, cut into runs that share a heading. */\nfunction groupsOf(options: readonly PickOneOption[]): Array<[string | undefined, PickOneOption[]]> {\n const out: Array<[string | undefined, PickOneOption[]]> = [];\n for (const o of options) {\n const last = out[out.length - 1];\n if (last && last[0] === o.group) last[1].push(o);\n else out.push([o.group, [o]]);\n }\n return out;\n}\n","\"use client\";\n\n// src/PersonPicker.tsx — @ai-matrx/records-ui · FLD-11 (`member`)\n//\n// PICKING A PERSON MEANS PICKING A PERSON.\n//\n// What it replaced, measured on the real screen (independent verdict, 19\n// September): the \"Owner\" field — which the settings panel itself calls a\n// Person field — offered \"Comments Home\", \"Saved views Home\" and \"V78 Home\".\n// Those are not people. They are the Home records this package writes into the\n// kernel Person Table so that its own Tables have somewhere to live (REC-1),\n// and the generic relation picker was listing the Table's contents, which is\n// exactly right for a relation and exactly wrong for a person.\n//\n// SO A PERSON FIELD ASKS A DIFFERENT QUESTION. The list is the ORGANIZATION'S\n// MEMBERS — who those are is the platform's answer and not the record store's,\n// so it arrives through the `members` port on the host, the same way saved\n// views and file uploads do. The record store has no door onto organization\n// membership and this package does not invent one.\n//\n// WHAT IS STORED IS STILL A RECORD ID, because a member field is a relation to\n// the kernel Person Table and the store's foreign key is real. So picking a\n// member resolves that member to their Person record — by the `user_id` the\n// record carries — and writes one when the organization has not got one yet.\n// That write is the same `record_write` everything else in this package uses;\n// there is no second storage path, and a Home (a Person record with no\n// `user_id`) is never offered and never picked.\n//\n// Unbound port: the control is ABSENT with its reason, never a dead box and\n// never a list of the wrong things.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { Field, ReadRow, RecordsError, Uuid } from \"@ai-matrx/records\";\nimport { rankTypedMatches } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { cn } from \"@ai-matrx/design-system\";\n\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { PersonChip } from \"./personChip\";\nimport { useRecordsUi, type OrganizationMember } from \"./host\";\nimport { NO_MEMBERS_REASON } from \"./host\";\nimport { fieldName } from \"./names\";\nimport { RefusalLine } from \"./Refusal\";\n\nexport interface PersonPickerProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n /** A grid cell's picker opens at once (`FieldEditorControlProps.autoOpen`). */\n autoOpen?: boolean | undefined;\n /** The list closed: the cell commits who is picked. */\n onClose?: (() => void) | undefined;\n /** Escape in a grid cell's list: the cell's cancel — nothing is written (`PickOrAdd.onEscape`). */\n onCancel?: (() => void) | undefined;\n /** What was typed to open a grid cell's list: its first search (`FieldEditorControlProps.initialSearch`). */\n initialSearch?: string | undefined;\n}\n\n/** A Person record in the kernel Table, as this picker needs to read it. */\ninterface PersonRecord {\n id: Uuid;\n userId: string | null;\n name: string;\n}\n\nfunction personFromRow(row: ReadRow): PersonRecord {\n const data = (row.document ?? {}) as Record<string, unknown>;\n const userId = data[\"user_id\"];\n return {\n id: row.id,\n userId: typeof userId === \"string\" && userId !== \"\" ? userId : null,\n name: String(data[\"full_name\"] ?? data[\"name\"] ?? data[\"email\"] ?? \"\").trim(),\n };\n}\n\n/** The member's own name, as a person reads it. Never a uuid. */\nexport function memberName(member: OrganizationMember): string {\n const display = (member.name ?? \"\").trim();\n if (display !== \"\") return display;\n const email = (member.email ?? \"\").trim();\n if (email !== \"\") return email;\n return \"A member with no name set\";\n}\n\n/**\n * Find (or write) the kernel Person record for one member. Exported because\n * an agent filling a person field server-side needs exactly the same answer,\n * and two implementations of \"which record is this person\" is two answers.\n */\nexport async function personRecordForMember(\n client: RecordsClient,\n personTableId: Uuid,\n people: PersonRecord[],\n member: OrganizationMember,\n): Promise<{ ok: true; data: Uuid } | { ok: false; error: RecordsError }> {\n const held = people.find((p) => p.userId === member.userId);\n if (held) return { ok: true, data: held.id };\n const written = await client.recordWrite({\n table_id: personTableId,\n data: {\n user_id: member.userId,\n full_name: memberName(member),\n ...(member.email ? { email: member.email } : {}),\n },\n });\n return written;\n}\n\nexport function PersonPicker({ field, value, onChange, disabled, id, className, autoOpen, onClose, onCancel, initialSearch }: PersonPickerProps) {\n // NOT `useRecordsClient`. This control is drawn by `FieldControl`, and\n // `FieldControl` is drawn by the PUBLIC arm of `FormRunner`, which mounts no\n // store client at all — the hook that throws turned a stranger's form into an\n // HTTP 500 (VERIFIER-10, F1). With no client there is nobody to offer, which\n // is the same answer this control already gives an unbound `members` port.\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [members, setMembers] = useState<OrganizationMember[] | null>(null);\n const [people, setPeople] = useState<PersonRecord[]>([]);\n const [error, setError] = useState<RecordsError | null>(null);\n const [search, setSearch] = useState(initialSearch ?? \"\");\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Closing the list — a pick, Escape, a click away — is what a grid cell commits on.\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n const [busy, setBusy] = useState(false);\n\n const membersPort = host.members;\n const personTable = field.relation_target;\n\n const picked = useMemo<string[]>(\n () => (Array.isArray(value) ? value.map(String) : value === null || value === undefined ? [] : [String(value)]),\n [value],\n );\n\n const load = useCallback(async () => {\n if (!membersPort || !client) return;\n const [roster, records] = await Promise.all([\n membersPort(),\n personTable ? client.list({ table_id: personTable, limit: 500 }) : Promise.resolve(null),\n ]);\n setMembers(roster);\n if (records && !records.ok) {\n setError(records.error);\n return;\n }\n setPeople(records ? records.data.rows.map(personFromRow).filter((p) => p.userId !== null) : []);\n }, [membersPort, client, personTable]);\n\n useEffect(() => {\n if (!open) return;\n void load();\n }, [open, load]);\n\n // The names of the records that are already picked, whether or not the list\n // has been opened — a chip that read `8f2c1b0a` is the defect this closes.\n useEffect(() => {\n if (picked.length === 0 || !personTable || people.length > 0 || !client) return;\n let cancelled = false;\n void client.list({ table_id: personTable, limit: 500 }).then((result) => {\n if (cancelled || !result.ok) return;\n setPeople(result.data.rows.map(personFromRow).filter((p) => p.userId !== null));\n });\n return () => {\n cancelled = true;\n };\n }, [client, personTable, picked.length, people.length]);\n\n // THE ONE RANKING (`rankTypedMatches`, grids review 3): exact, starts with, a word starts with, contains.\n const listed = rankTypedMatches(members ?? [], search, memberName);\n\n if (!membersPort || !client) {\n // ABSENT AND HONEST. A person question with nobody to offer is not a box\n // that silently does nothing — it names the port that fills it.\n return <p className={cn(\"text-xs text-muted-foreground\", className)}>{NO_MEMBERS_REASON}</p>;\n }\n\n if (!personTable) {\n return (\n <p className={cn(\"text-xs text-muted-foreground\", className)}>\n {fieldName(field)} is a person field, but it does not say which Table the people are\n records of yet, so there is nothing to pick from. A table admin sets its target in the field\n editor.\n </p>\n );\n }\n\n // ONE PERSON, ONE NAME (lane CELL-EDITORS, 2026-10-06): the chip read \"admin\" (the Person record)\n // while the list read \"admin@admin.com\" (a member with no display name). The display name is the\n // member's own, else the Person record's; the email is shown beside it, and alone only when there is\n // no name at all.\n const displayNameOf = (userId: string | null, recordName?: string): string | null => {\n const member = userId ? (members ?? []).find((m) => m.userId === userId) : undefined;\n const own = (member?.name ?? \"\").trim();\n if (own !== \"\") return own;\n const kept = (recordName ?? people.find((p) => p.userId === userId)?.name ?? \"\").trim();\n const email = (member?.email ?? \"\").trim();\n return kept !== \"\" && kept !== email ? kept : null;\n };\n const nameOfRecord = (recordId: string) => {\n const person = people.find((p) => p.id === recordId);\n if (!person) return \"Loading…\";\n const member = (members ?? []).find((m) => m.userId === person.userId);\n return displayNameOf(person.userId, person.name) ?? (member ? memberName(member) : person.name || \"A member with no name set\");\n };\n\n const pick = async (member: OrganizationMember) => {\n setBusy(true);\n setError(null);\n const resolved = await personRecordForMember(client, personTable, people, member);\n setBusy(false);\n if (!resolved.ok) {\n setError(resolved.error);\n return;\n }\n // Keep the newly written record so the chip can be named at once.\n if (!people.some((p) => p.id === resolved.data)) {\n setPeople((held) => [...held, { id: resolved.data, userId: member.userId, name: memberName(member) }]);\n }\n if (!field.multi) {\n onChange(picked[0] === resolved.data ? null : resolved.data);\n setOpen(false);\n return;\n }\n const next = new Set(picked);\n if (next.has(resolved.data)) next.delete(resolved.data);\n else next.add(resolved.data);\n onChange(next.size === 0 ? null : [...next]);\n };\n\n const drop = (recordId: string) => {\n const next = picked.filter((id) => id !== recordId);\n onChange(next.length === 0 ? null : field.multi ? next : (next[0] ?? null));\n };\n\n const visible = listed;\n const pickedUserIds = new Set(\n picked.map((recordId) => people.find((p) => p.id === recordId)?.userId).filter(Boolean),\n );\n\n const anchored = autoOpen === true;\n const cellChips = picked.map((recordId) => (\n <PersonChip key={recordId} name={nameOfRecord(recordId)} {...(disabled || anchored ? {} : { onRemove: () => drop(recordId) })} />\n ));\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-1\", className)}>\n {anchored && !disabled ? null : cellChips}\n {disabled ? null : (\n // THE ONE \"PICK OR ADD\" BUILDER (lane CELL-EDITORS, 2026-10-06): the person list used to carry\n // its own copy of the list's layout and keys; it now draws the same rows, ticks, highlight and\n // head chips as every other picker, and in a grid cell hangs from the cell.\n <PickOrAdd\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n anchored={anchored}\n multi={field.multi}\n triggerId={id}\n triggerLabel={`Pick a person for ${fieldName(field)}`}\n triggerText={picked.length === 0 ? \"Pick a person\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={setSearch}\n chips={picked.map((recordId) => ({ id: recordId, label: nameOfRecord(recordId), person: true, onRemove: () => drop(recordId) }))}\n items={visible.map((member) => ({\n id: member.userId,\n label: displayNameOf(member.userId) ?? memberName(member),\n // A name and an email with nothing between them read as one run-on string (verdict,\n // 19 September). They are two facts, so they are drawn as two.\n detail: displayNameOf(member.userId) !== null && member.email ? member.email : null,\n picked: pickedUserIds.has(member.userId),\n person: true,\n disabled: busy,\n }))}\n onPick={(userId) => {\n const member = visible.find((m) => m.userId === userId);\n if (member && !busy) void pick(member);\n }}\n notice={\n <>\n {error ? <RefusalLine error={error} className=\"p-2\" /> : null}\n {members === null ? <p className=\"p-2 text-xs text-muted-foreground\">Reading the members…</p> : null}\n </>\n }\n empty={\n members !== null ? (\n <p className=\"p-2 text-xs text-muted-foreground\">\n {members.length === 0\n ? \"This organization has no other members yet, so there is nobody to assign.\"\n : \"Nobody in this organization matches.\"}\n </p>\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n","/**\n * A TYPED VALUE'S REFUSAL FLOATS WHERE IT CAN BE READ (walk 4, 2026-10-07).\n *\n * \"Enter a valid phone number\" was in the DOM but clipped inside a 114 px grid cell (the cell, the\n * sticky header and the scroller all clip what an absolutely placed note tries to draw past them),\n * and on the record page the same note covered the Email value under Phone. The note is now drawn\n * in a layer on <body>, anchored to the open editor, so nothing clips it and it moves nothing:\n * · in a grid cell — directly above the cell, left-aligned with it (below it when there is no\n * room above), the way every other note an open cell says floats;\n * · in a record's field — inside the field's own box, at its right end, so it covers no other field.\n * The anchor is the open editor (`data-matrx-cell-editor`), else the note's own parent.\n */\nimport { useLayoutEffect, useRef, useState, type CSSProperties } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nconst GAP = 4;\n\nfunction placeFor(anchor: Element, note: HTMLElement | null): CSSProperties {\n const a = anchor.getBoundingClientRect();\n const inGrid = anchor.closest(\"td\") !== null;\n const height = note?.offsetHeight ?? 20;\n const width = note?.offsetWidth ?? 0;\n if (inGrid) {\n const above = a.top - GAP - height;\n const top = above >= 0 ? above : a.bottom + GAP;\n const left = Math.max(GAP, Math.min(a.left, window.innerWidth - width - GAP));\n return { position: \"fixed\", top, left };\n }\n // A record's field: inside its own box, right end, vertically centred.\n return { position: \"fixed\", top: a.top + (a.height - height) / 2, left: Math.max(a.left, a.right - width - 8) };\n}\n\nexport function FloatingRefusal({ text, why }: { text: string; why?: string | undefined }) {\n const spot = useRef<HTMLSpanElement | null>(null);\n const note = useRef<HTMLSpanElement | null>(null);\n const [style, setStyle] = useState<CSSProperties | null>(null);\n // Only an OPEN CELL'S editor (a grid cell, a record's field in place) floats its note; a form's\n // box keeps it in flow under the box, as it always did.\n const [floating, setFloating] = useState(false);\n useLayoutEffect(() => {\n const here = spot.current;\n if (!here) return;\n const anchor = here.closest(\"[data-matrx-cell-editor]\");\n setFloating(anchor !== null);\n if (!anchor) return;\n const place = () => setStyle(placeFor(anchor, note.current));\n place();\n // Measured once more after the note has its own size, then on every scroll or resize.\n const frame = requestAnimationFrame(place);\n window.addEventListener(\"scroll\", place, true);\n window.addEventListener(\"resize\", place);\n return () => {\n cancelAnimationFrame(frame);\n window.removeEventListener(\"scroll\", place, true);\n window.removeEventListener(\"resize\", place);\n };\n }, [text]);\n if (!floating) {\n return (\n <span ref={spot} data-records-typed-refusal=\"\" role=\"status\" title={why} className=\"text-[11px] leading-snug text-amber-700 dark:text-amber-400\">\n {text}\n </span>\n );\n }\n return (\n <>\n <span ref={spot} data-records-refusal-anchor=\"\" hidden />\n {typeof document === \"undefined\"\n ? null\n : createPortal(\n <span\n ref={note}\n data-records-typed-refusal=\"\"\n data-records-floating-refusal=\"\"\n role=\"status\"\n title={why}\n style={{ ...(style ?? { position: \"fixed\", top: -9999, left: -9999 }), zIndex: 60 }}\n className=\"pointer-events-none w-max max-w-[24rem] rounded-md border bg-popover px-1.5 py-0.5 text-[11px] leading-snug text-amber-700 shadow-md dark:text-amber-400\"\n >\n {text}\n </span>,\n document.body,\n )}\n </>\n );\n}\n","/**\n * HOW A TABLE LOOKS — colors, formats and the frozen column.\n *\n * THE SPLIT, AND WHY IT IS THIS ONE. A Field declares WHAT it holds: a\n * currency, a percent, a date, a person. A VIEW declares HOW that reads and\n * what it is worth looking at: two decimal places or none, tint the row when\n * Status is Blocked, keep Name in place while the rest scrolls. Airtable draws\n * the line in exactly this place, and it has to be here: two people read one\n * table two different ways, and neither reading is a fact about the records.\n *\n * So nothing in this module is a new column on a Field and nothing here needed\n * a migration. A presentation lives on the saved-view record (`views.ts`), which\n * is an ordinary record of an ordinary Table — which means an agent sets it\n * through the same `records` tool it uses for everything else, and it travels\n * with the table the way every other record does.\n *\n * A FIELD STILL GETS ITS MONEY RIGHT WITH NO CONFIGURATION. `formatForField`\n * reads the Field's OWN declaration — a `currency` parity type with unit `$`, a\n * `percent`, a `datetime` with `config.kind` — and returns the format that\n * follows from it. The view's `formats` map only OVERRIDES that. A table nobody\n * has ever styled still shows `$1,250.50` and `45%`.\n */\n\n// The style parser from its own client-free subpath (lane SSR-ROWS): `@ai-matrx/records-ui/first-page`\n// runs in a host's SERVER component, and every export of the \"use client\" `data-table` entry is a\n// client reference there — calling `parseTableStyle` through it threw on the server.\nimport { parseTableStyle, tableStyleIsEmpty } from \"@ai-matrx/design-system/data-table/table-style\";\nimport {\n COLOR_ROTATION,\n type ChoiceColorLookup,\n type GroupAggregateKind,\n type GroupAggregateSpec,\n type GroupOrder,\n type StyleColor,\n type TableStyle,\n} from \"@ai-matrx/design-system/data-table\";\nimport { getFieldFormat, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { ColorRule } from \"@ai-matrx/design-system/data-table\";\nimport { newerKindOf, ratingMaxOf, type Field, type TableDecorations } from \"@ai-matrx/records\";\n\nimport { editorKindFor } from \"./parity\";\nimport { dateFormatFor } from \"./dates\";\n\n/**\n * SECTIONS BY A FIELD — the view's own grouping.\n *\n * `field` is a Field KEY, exactly like `frozen` and the keys of `formats`,\n * because a view is written against the Table's declaration and never against\n * whatever id a screen happened to build its columns with.\n *\n * `aggregates` is keyed by Field key too, and `collapsed` holds the data\n * table's own group keys (`s:Blocked`, `n:3`, `empty`), which is what the\n * primitive emits and the only thing that survives a value rendering the same\n * text as another.\n *\n * NOTHING HERE IS EVER CALLED `valueOf`, `toString` or `hasOwnProperty`: every\n * object in JavaScript already has all three, so an optional field by one of\n * those names is NEVER absent and a `config.valueOf ? … : …` check silently\n * reads `Object.prototype`. It cost the primitive a whole grouping once.\n */\nexport type GridGrouping = {\n /** The Field key whose value makes the sections. */\n field: string;\n /** Per-Field-key subtotal on every section header. */\n aggregates?: Record<string, GroupAggregateSpec>;\n /** Section order. The primitive's default is `value-asc`; blanks sort last. */\n order?: GroupOrder;\n /** The sections this view keeps shut, by the primitive's own group key. */\n collapsed?: string[];\n /** The grouped column drawn as a column too. Absent = it steps aside (the headers name its value). */\n showColumn?: boolean;\n /**\n * SUB-GROUPS (lane S1-PRIME VIEW-KEYS; ui-bench LISTS \"sub-grouping\"): up to two more levels\n * inside each section, by Field key. At most three levels in all — the store refuses a fourth\n * (`custom.view_declare`). A layout that draws one level ignores the rest; it never drops them,\n * because this list is parsed and written back whole with the rest of the look.\n */\n then?: GridSubGroup[];\n /**\n * DRILL (lane DRILL-TABLE-PRIMITIVE): the Dimension pivoted across the top — a Field key, or\n * `<key>:<grain>` for a date cut into periods.\n */\n across?: string;\n /** DRILL: the period `field` is cut into when it is a date (`month`); the store keeps `field` a Field key. */\n grain?: string;\n /** The Measures shown (\"what to display\"), by the store's own keys (`count`, `sum_quantity`). */\n show?: string[];\n /** The drill trail, in order: each crumb a Dimension reference and the value it narrowed to. */\n trail?: GridDrillStep[];\n};\n\n/** One crumb of a saved drill trail. `value: null` is \"no value\". */\nexport type GridDrillStep = { dim: string; value: string | null };\n\n/** One sub-group level: a Field key and its section order. */\nexport type GridSubGroup = { field: string; order?: GroupOrder; grain?: string };\n\n/** Everything a view says about how its table LOOKS. */\nexport type GridPresentation = {\n /** Color-by-a-column, rules and manual highlights. */\n style?: TableStyle;\n /** Per-column format overrides, by the Field's key. */\n formats?: Record<string, FieldFormatConfig>;\n /**\n * The columns that stay in place while the table scrolls sideways, by Field\n * key. Only the LEADING run of the view's column order can actually freeze —\n * the data table decides that, and declines rather than pinning a column at a\n * guessed offset.\n */\n frozen?: string[];\n /** Collapsible sections by one Field, with subtotals on each header. */\n grouping?: GridGrouping;\n /**\n * The width a person dragged a column to, by Field key. SPARSE on purpose —\n * a view saved before widths existed carries none and still parses, and a\n * column nobody resized is left to the table's own measurement.\n */\n widths?: Record<string, number>;\n /** The body row height this view remembers, in px. */\n rowHeight?: number;\n /**\n * Field keys hidden from this view — the SAME hidden-column list the grid's\n * own column picker holds, now given a place on the view so it survives a\n * reload and a layout switch reads the identical set gallery and grid agree\n * on, rather than a second \"fields shown\" list nobody kept in sync.\n */\n hiddenFields?: string[];\n /**\n * THE FIELDS A CARD LEAVES OFF (board, list, gallery, calendar, timeline), by Field key — the\n * card's own choice, kept apart from `hiddenFields` so a board's \"Card fields\" never hides the\n * grid's columns when the view switches layout (v7 TABLE-EXPERIENCE, walk 2026-10-05). An empty\n * list is a choice (every field shown); absent means the card never chose.\n */\n cardHidden?: string[];\n /**\n * THE ORDER A PERSON DRAGGED THE COLUMNS INTO, by Field key (merge tranche 6a). Sparse like\n * `widths`: a key it does not name keeps its Field's own place after the named ones, and a key\n * whose Field is gone is skipped — a column order can never hide or invent a column.\n */\n columnOrder?: string[];\n /**\n * The gallery's card size, remembered the same way the grid remembers its\n * row height — a per-view look, not a global default.\n */\n gallerySize?: \"small\" | \"medium\" | \"large\";\n /**\n * THIS VIEW'S OWN LAYOUT CHOICES, over the organization's `custom/grid_layout` knob (lane\n * DEFAULT-GRID-PARITY, TABLE-PARITY D1 D5 D6). Absent means \"whatever the organization\n * says\"; present is the view's word. `freezeFirst: false` is an explicit NO over an\n * organization that freezes the first column — an empty `frozen` cannot say that.\n */\n wrap?: boolean;\n /** NOTION'S \"WRAP COLUMN\" (N5): the columns that wrap their text when the view as a whole does not. */\n wrapColumns?: string[];\n fit?: \"auto\" | \"fit\" | \"scroll\";\n freezeFirst?: boolean;\n /**\n * THE SUMMARY BAR (TABLE-PARITY F1): Field key → the store measure shown under that column\n * (`count`, `sum`, `avg`, `min`, `max`, `median`, `filled`, `empty`, `unique`), worked out\n * by `custom.record_aggregate` over the whole table.\n */\n summaries?: Record<string, string>;\n /**\n * WHERE THE FOOTER SITS (lane TABLE-PAGE-CHROME, owner 2026-09-25) — the row count and the\n * pages: `sticky`, pinned to the bottom of the screen while the rows scroll (the older grid's\n * way, and the default when a view says nothing), or `inline`, right after the last row with\n * the page scrolling. Read by the Grid and a host's Sheet.\n */\n footer?: FooterPlacement;\n};\n\n/** Where a grid's footer sits. */\nexport type FooterPlacement = \"sticky\" | \"inline\";\n\n/** What a view that says nothing gets — the older grid's pinned footer. */\nexport const DEFAULT_FOOTER: FooterPlacement = \"sticky\";\n\n/** Where THIS view's footer sits, said or defaulted. */\nexport function footerOf(p: GridPresentation | null | undefined): FooterPlacement {\n return p?.footer ?? DEFAULT_FOOTER;\n}\n\nexport const EMPTY_PRESENTATION: GridPresentation = {};\n\n/** A frozen column needs a known width, or the table declines to freeze at all. */\nexport const FROZEN_COLUMN_WIDTH = 200;\n\n/**\n * WHAT A ROW HEIGHT IS ALLOWED TO BE. Below the floor the text is clipped and\n * no editor fits; above the ceiling one record fills the screen. A view asking\n * for anything outside it is DROPPED rather than obeyed, because a saved look\n * must not be able to make a table unreadable — and the Fields' own heights\n * still draw, which is the tolerant half.\n */\nexport const MIN_ROW_HEIGHT = 24;\nexport const MAX_ROW_HEIGHT = 96;\n\n/**\n * The aggregate kinds and orders the primitive actually implements. Listed here\n * because they are the tolerant parser's allow-list and a view is hostile input:\n * `satisfies` ties them to the primitive's own union, so a kind it renames stops\n * this file compiling instead of quietly parsing into a subtotal nobody draws.\n */\nconst AGGREGATE_KINDS = [\n \"count\",\n \"sum\",\n \"average\",\n \"min\",\n \"max\",\n \"empty\",\n \"filled\",\n \"unique\",\n \"checked\",\n \"unchecked\",\n \"percentFilled\",\n] as const satisfies readonly GroupAggregateKind[];\n\nconst GROUP_ORDERS = [\n \"value-asc\",\n \"value-desc\",\n \"count-desc\",\n \"first-seen\",\n] as const satisfies readonly GroupOrder[];\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Read a presentation out of whatever the view record holds — an object, or the\n * JSON string a text field stores.\n *\n * Tolerant in exactly the way `parseTableStyle` is: an unreadable half is\n * dropped and the rest still applies, because a table must keep drawing when\n * one piece of its styling goes out of date.\n */\nexport function parseGridPresentation(raw: unknown): GridPresentation {\n let value = raw;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed === \"\") return {};\n try {\n value = JSON.parse(trimmed);\n } catch {\n return {};\n }\n }\n if (!isRecord(value)) return {};\n\n const out: GridPresentation = {};\n\n const style = parseTableStyle(value[\"style\"]);\n if (!tableStyleIsEmpty(style)) out.style = style;\n\n if (isRecord(value[\"formats\"])) {\n const formats: Record<string, FieldFormatConfig> = {};\n for (const [key, cfg] of Object.entries(value[\"formats\"])) {\n if (!isRecord(cfg)) continue;\n const id = cfg[\"id\"];\n if (typeof id !== \"string\") continue;\n const options = cfg[\"options\"];\n formats[key] = isRecord(options)\n ? {\n id: id as FieldFormatConfig[\"id\"],\n options: options as NonNullable<FieldFormatConfig[\"options\"]>,\n }\n : { id: id as FieldFormatConfig[\"id\"] };\n }\n if (Object.keys(formats).length > 0) out.formats = formats;\n }\n\n if (Array.isArray(value[\"frozen\"])) {\n const frozen = value[\"frozen\"].filter((k): k is string => typeof k === \"string\");\n if (frozen.length > 0) out.frozen = frozen;\n }\n\n const grouping = parseGrouping(value[\"grouping\"]);\n if (grouping) out.grouping = grouping;\n\n if (isRecord(value[\"widths\"])) {\n const widths: Record<string, number> = {};\n for (const [key, raw] of Object.entries(value[\"widths\"])) {\n // A width that is not a usable number is one column's loss, never the\n // view's: the rest of the widths still apply and that column is measured.\n if (typeof raw !== \"number\" || !Number.isFinite(raw) || raw <= 0) continue;\n widths[key] = Math.round(raw);\n }\n if (Object.keys(widths).length > 0) out.widths = widths;\n }\n\n const rowHeight = value[\"rowHeight\"];\n if (\n typeof rowHeight === \"number\" &&\n Number.isFinite(rowHeight) &&\n rowHeight >= MIN_ROW_HEIGHT &&\n rowHeight <= MAX_ROW_HEIGHT\n ) {\n out.rowHeight = Math.round(rowHeight);\n }\n\n if (Array.isArray(value[\"hiddenFields\"])) {\n const hiddenFields = value[\"hiddenFields\"].filter((k): k is string => typeof k === \"string\");\n if (hiddenFields.length > 0) out.hiddenFields = hiddenFields;\n }\n if (Array.isArray(value[\"cardHidden\"])) {\n out.cardHidden = value[\"cardHidden\"].filter((k): k is string => typeof k === \"string\");\n }\n\n if (Array.isArray(value[\"columnOrder\"])) {\n const columnOrder = value[\"columnOrder\"].filter((k): k is string => typeof k === \"string\");\n if (columnOrder.length > 0) out.columnOrder = columnOrder;\n }\n\n const gallerySize = value[\"gallerySize\"];\n if (gallerySize === \"small\" || gallerySize === \"medium\" || gallerySize === \"large\") {\n out.gallerySize = gallerySize;\n }\n\n if (typeof value[\"wrap\"] === \"boolean\") out.wrap = value[\"wrap\"];\n if (Array.isArray(value[\"wrapColumns\"])) {\n const wrapColumns = value[\"wrapColumns\"].filter((k): k is string => typeof k === \"string\");\n if (wrapColumns.length > 0) out.wrapColumns = wrapColumns;\n }\n const fit = value[\"fit\"];\n if (fit === \"auto\" || fit === \"fit\" || fit === \"scroll\") out.fit = fit;\n if (typeof value[\"freezeFirst\"] === \"boolean\") out.freezeFirst = value[\"freezeFirst\"];\n const footer = value[\"footer\"];\n if (footer === \"sticky\" || footer === \"inline\") out.footer = footer;\n if (isRecord(value[\"summaries\"])) {\n const summaries: Record<string, string> = {};\n for (const [key, op] of Object.entries(value[\"summaries\"])) {\n // A measure name is judged by the store when it is asked; a non-string is nobody's.\n if (typeof op === \"string\" && op.trim() !== \"\") summaries[key] = op;\n }\n if (Object.keys(summaries).length > 0) out.summaries = summaries;\n }\n\n return out;\n}\n\n/**\n * A grouping, or nothing. A grouping with no Field to group BY is not a partial\n * grouping — it is no grouping at all, so it is dropped whole; an unreadable\n * subtotal or a section order this primitive does not have costs only itself.\n */\nfunction parseGrouping(raw: unknown): GridGrouping | undefined {\n if (!isRecord(raw)) return undefined;\n const field = raw[\"field\"];\n if (typeof field !== \"string\" || field.trim() === \"\") return undefined;\n\n const out: GridGrouping = { field };\n\n if (isRecord(raw[\"aggregates\"])) {\n const aggregates: Record<string, GroupAggregateSpec> = {};\n for (const [key, spec] of Object.entries(raw[\"aggregates\"])) {\n if (!isRecord(spec)) continue;\n const kind = spec[\"kind\"];\n if (typeof kind !== \"string\") continue;\n if (!(AGGREGATE_KINDS as readonly string[]).includes(kind)) continue;\n const label = spec[\"label\"];\n aggregates[key] =\n typeof label === \"string\"\n ? { kind: kind as GroupAggregateKind, label }\n : { kind: kind as GroupAggregateKind };\n }\n if (Object.keys(aggregates).length > 0) out.aggregates = aggregates;\n }\n\n const order = raw[\"order\"];\n if (typeof order === \"string\" && (GROUP_ORDERS as readonly string[]).includes(order)) {\n out.order = order as GroupOrder;\n }\n\n if (Array.isArray(raw[\"collapsed\"])) {\n const collapsed = raw[\"collapsed\"].filter((k): k is string => typeof k === \"string\");\n if (collapsed.length > 0) out.collapsed = collapsed;\n }\n\n if (raw[\"showColumn\"] === true) out.showColumn = true;\n\n if (Array.isArray(raw[\"then\"])) {\n const then: GridSubGroup[] = [];\n for (const level of raw[\"then\"]) {\n if (!isRecord(level)) continue;\n const sub = level[\"field\"];\n if (typeof sub !== \"string\" || sub.trim() === \"\") continue;\n const subOrder = level[\"order\"];\n const subGrain = level[\"grain\"];\n then.push({\n field: sub,\n ...(typeof subOrder === \"string\" && (GROUP_ORDERS as readonly string[]).includes(subOrder)\n ? { order: subOrder as GroupOrder }\n : {}),\n ...(typeof subGrain === \"string\" && subGrain !== \"\" ? { grain: subGrain } : {}),\n });\n }\n if (then.length > 0) out.then = then.slice(0, 2);\n }\n\n const grain = raw[\"grain\"];\n if (typeof grain === \"string\" && grain !== \"\") out.grain = grain;\n const across = raw[\"across\"];\n if (typeof across === \"string\" && across.trim() !== \"\") out.across = across;\n if (Array.isArray(raw[\"show\"])) {\n const show = raw[\"show\"].filter((k): k is string => typeof k === \"string\" && k !== \"\");\n if (show.length > 0) out.show = show;\n }\n if (Array.isArray(raw[\"trail\"])) {\n const trail: GridDrillStep[] = [];\n for (const step of raw[\"trail\"]) {\n if (!isRecord(step) || typeof step[\"dim\"] !== \"string\" || step[\"dim\"] === \"\") continue;\n const value = step[\"value\"];\n if (value !== null && typeof value !== \"string\") continue;\n trail.push({ dim: step[\"dim\"], value });\n }\n if (trail.length > 0) out.trail = trail;\n }\n\n return out;\n}\n\n/** True when nothing here would change how anything looks. */\nexport function presentationIsEmpty(p: GridPresentation): boolean {\n return (\n (p.style === undefined || tableStyleIsEmpty(p.style)) &&\n Object.keys(p.formats ?? {}).length === 0 &&\n (p.frozen?.length ?? 0) === 0 &&\n p.grouping === undefined &&\n Object.keys(p.widths ?? {}).length === 0 &&\n p.rowHeight === undefined &&\n (p.hiddenFields?.length ?? 0) === 0 &&\n p.cardHidden === undefined &&\n (p.columnOrder?.length ?? 0) === 0 &&\n p.gallerySize === undefined &&\n p.wrap === undefined &&\n p.fit === undefined &&\n p.freezeFirst === undefined &&\n p.footer === undefined &&\n Object.keys(p.summaries ?? {}).length === 0\n );\n}\n\n/** The string a view record stores. Empty string for \"this view styles nothing\". */\nexport function presentationDocument(p: GridPresentation): string {\n return presentationIsEmpty(p) ? \"\" : JSON.stringify(p);\n}\n\n/** Kinds whose value is a control the record renderer draws, never a formatter's string. */\nconst DRAWN_KINDS = new Set([\"select\", \"multi_select\", \"relation\", \"member\", \"person\", \"attachment\", \"file\", \"entity_reference\", \"checkbox\", \"boolean\", \"signature\", \"json\"]);\n\n/**\n * The display format a column's settings chose for it, when it is one the platform registry\n * knows and the column is not one the record renderer draws itself. `undefined` otherwise.\n */\nexport function shownAsOf(field: Field): FieldFormatConfig | undefined {\n if (DRAWN_KINDS.has(String(editorKindFor(field)))) return undefined;\n const raw = (field as unknown as { display_format?: unknown }).display_format;\n if (!raw || typeof raw !== \"object\") return undefined;\n const id = (raw as { id?: unknown }).id;\n // `formula` is the column's KIND, never a look: a worked-out column shows as its result format.\n if (typeof id !== \"string\" || id === \"formula\" || !getFieldFormat(id)) return undefined;\n const options = (raw as { options?: unknown }).options;\n return options && typeof options === \"object\" && Object.keys(options).length > 0\n ? ({ id, options } as FieldFormatConfig)\n : ({ id } as FieldFormatConfig);\n}\n\n/**\n * The format a Field's OWN declaration implies, before any view says anything.\n *\n * Returns `undefined` for a Field whose value the record renderer already draws\n * better than a formatter could — a relation chip, a person, an attachment, a\n * choice — because handing those to a text formatter would REPLACE a working\n * control with a string.\n */\nexport function formatForField(field: Field): FieldFormatConfig | undefined {\n // \"SHOWS AS\" — THE FORMAT THE COLUMN'S OWN SETTINGS CHOSE (merge tranche 6a/6e). The column\n // keeps it on the Field (`display_format`, written by `custom.field_update`), so the grid, the\n // record panel and the export read one answer. A column the record renderer draws better than\n // a formatter (a choice, a link, a person, a file) keeps its own drawing.\n const shownAs = shownAsOf(field);\n // A RATING'S TOP STAR IS ITS MAX RULE (lane 10 P4), so changing the rule changes the stars.\n if (newerKindOf(field) === \"rating\" && (!shownAs || shownAs.id === \"rating\")) {\n return { id: \"rating\", options: { ...(shownAs?.options ?? {}), ratingMax: ratingMaxOf(field) } };\n }\n if (shownAs) return shownAs;\n // THE STORE'S OWN STAMPS (Created time, Last changed time) are instants and print like\n // every other date-and-time cell — `dates.ts` answers, the same helper every card reads.\n const stamp = dateFormatFor(field);\n if (stamp && editorKindFor(field) !== \"datetime\") return stamp;\n switch (editorKindFor(field)) {\n case \"currency\":\n return {\n id: \"currency\",\n options: { currency: currencyCodeFor(field.unit) },\n };\n case \"percent\":\n return { id: \"percent\" };\n case \"datetime\":\n // The COLUMN's declaration: a `kind: \"date\"` column is a date column, anything else can\n // hold a moment. Each VALUE is still printed in its own shape (`RecordValue` →\n // `dates.dateFormatFor(field, value)`), so a bare date in a datetime column reads as a date.\n return String(field.config?.[\"kind\"] ?? \"\") === \"date\" ? { id: \"date\" } : { id: \"datetime\" };\n case \"email\":\n return { id: \"email\" };\n case \"url\":\n return { id: \"url\" };\n case \"phone\":\n return { id: \"phone\" };\n case \"number\":\n return { id: \"number\" };\n default:\n return undefined;\n }\n}\n\n/**\n * THE FORMAT ONE CELL OF A COLUMN IS DRAWN IN — the grid's cell and the gallery's card alike\n * (guard G4 \"one format\", lane VIEWS-AND-FIELDS W1-B): the view's own format for the column when\n * it set one, else the Field's own (`formatForField`). One function, so no layout formats money\n * (or a date, or a percent) its own way.\n */\nexport function cellFormatFor(field: Field, viewFormat?: FieldFormatConfig | undefined): FieldFormatConfig | undefined {\n return viewFormat ?? formatForField(field);\n}\n\n/**\n * The store lets a person type the SYMBOL they think in (`$`, `€`), and\n * `Intl.NumberFormat` wants the ISO code. The symbols people actually enter are\n * mapped; anything else is passed straight through, because a real ISO code is\n * the other thing that lands in this field, and an unknown code still renders\n * (`1,234.00 XYZ`) rather than blanking — THE FALLBACK LAW.\n */\nconst SYMBOL_TO_CODE: Record<string, string> = {\n $: \"USD\",\n \"£\": \"GBP\",\n \"€\": \"EUR\",\n \"¥\": \"JPY\",\n \"₹\": \"INR\",\n \"₽\": \"RUB\",\n \"₩\": \"KRW\",\n \"R$\": \"BRL\",\n \"C$\": \"CAD\",\n \"A$\": \"AUD\",\n};\n\nexport function currencyCodeFor(unit: string | null | undefined): string {\n const raw = (unit ?? \"\").trim();\n if (raw === \"\") return \"USD\";\n return SYMBOL_TO_CODE[raw] ?? raw.toUpperCase();\n}\n\n/**\n * The color a value paints with when a view colors BY a column.\n *\n * NOTHING FAILS SILENTLY, so this never returns \"no color\" for a value that\n * exists. The store keeps a list column's choices as records of another Table,\n * and this grid has not read that Table's option colors, so the color is\n * derived from the value's own text: the same word always gets the same color,\n * different words get different ones, and `true` is green the way every\n * checklist reads. When those option colors do land, this is the ONE function\n * that changes and every screen follows.\n */\nexport const colorFromTheValue: ChoiceColorLookup = (_fieldKey, value) => {\n if (value === true) return \"green\";\n if (value === false || value === null || value === undefined) return undefined;\n const text = String(value).trim().toLowerCase();\n if (text === \"\") return undefined;\n let hash = 0;\n for (let i = 0; i < text.length; i += 1) {\n hash = (hash * 31 + text.charCodeAt(i)) >>> 0;\n }\n return COLOR_ROTATION[hash % COLOR_ROTATION.length] as StyleColor;\n};\n\n/**\n * G1's TABLE-LEVEL COLORS (`custom.table_decorations` / `client.tableDecorations`),\n * TRANSLATED INTO A `TableStyle` — the same document a saved view's own `presentation.style`\n * is, so one resolver (`resolveTableStyle`, below) can treat \"the table's colors\" and \"this\n * view's colors\" as two layers of the SAME thing instead of two unrelated systems.\n *\n * THE TRANSLATION IS NECESSARY AND IT IS THE ONLY ONE. G1 addresses a Field by its ID\n * (REC-17 — a column renamed keeps its color), because it is the STORE's own door; a\n * `TableStyle` addresses a Field by its KEY, because it reads straight off `row.document`,\n * which is keyed by Field key. A rule or a color-by whose Field has been deleted (its id no\n * longer resolves to a key) is dropped rather than crashing the whole style — a defect in\n * one rule costs that rule, never the read.\n */\nexport function styleFromDecorations(\n decorations: TableDecorations | null | undefined,\n fields: readonly Field[],\n): TableStyle {\n if (!decorations) return { version: 1 };\n const keyOf = (id: string) => fields.find((f) => f.id === id)?.key;\n const style: TableStyle = { version: 1 };\n\n if (decorations.color_by?.field) {\n const field = keyOf(decorations.color_by.field);\n if (field) style.colorBy = { field, target: decorations.color_by.target };\n }\n\n if (Array.isArray(decorations.rules) && decorations.rules.length > 0) {\n const rules: ColorRule[] = [];\n decorations.rules.forEach((rule, index) => {\n const field = keyOf(rule.field);\n if (!field) return;\n rules.push({\n id: rule.id ?? `decoration:${index}`,\n field,\n op: rule.op,\n color: rule.color,\n target: rule.target,\n ...(rule.value === undefined || rule.value === null ? {} : { value: String(rule.value) }),\n });\n });\n if (rules.length > 0) style.rules = rules;\n }\n\n if (decorations.rows && Object.keys(decorations.rows).length > 0) {\n style.rows = { ...decorations.rows };\n }\n\n const columns: Record<string, StyleColor> = {};\n for (const [id, color] of Object.entries(decorations.columns ?? {})) {\n const key = keyOf(id);\n if (key) columns[key] = color;\n }\n if (Object.keys(columns).length > 0) style.columns = columns;\n\n const cells: Record<string, Record<string, StyleColor>> = {};\n for (const [rowId, byField] of Object.entries(decorations.cells ?? {})) {\n for (const [id, color] of Object.entries(byField ?? {})) {\n const key = keyOf(id);\n if (!key) continue;\n (cells[rowId] ??= {})[key] = color;\n }\n }\n if (Object.keys(cells).length > 0) style.cells = cells;\n\n return style;\n}\n\n/**\n * THE ONE PRESENTATION RESOLVER every colored surface in this package reads —\n * `Grid`, and (via `Card`) the kanban board, the calendar and the gallery.\n *\n * THE CLASS THIS CLOSES (lane UI-QUICK-1, TABLE-PARITY review, 2026-09-24). Threading\n * `view.presentation.style` into `Card` closed the instance the CALENDAR-GALLERY bench\n * found — a VIEW that had its own color-by looked right everywhere — but it left the\n * class open: a table whose colors are the ORGANIZATION's decorations (G1's\n * `custom.table_decorations` — \"color rows by Account Type\", \"MAXED and NEAR rules\" on\n * Arman's own Coding Accounts table) and whose views never set a `presentation.style` of\n * their own drew NOTHING, on the grid exactly as much as on every other layout, because\n * nothing in this package had ever read G1's door at all.\n *\n * TWO LAYERS, ONE DOCUMENT. The table's decorations are the base coat — what every view\n * of this table shows until a view says otherwise. A view's OWN `presentation.style` is\n * an override, piece by piece: a view that only ever set manual row highlights still\n * inherits the table's color-by and rules for everything it never touched, and a view\n * that fully redecorated (its own `colorBy` AND its own `rules`) is not haunted by a\n * table rule it meant to replace. Per-piece, never all-or-nothing, because a view is a\n * LOOK on top of the table, not a wholesale substitute for it.\n */\nexport function resolveTableStyle(\n decorations: TableDecorations | null | undefined,\n fields: readonly Field[],\n viewStyle: TableStyle | undefined,\n): TableStyle {\n const base = styleFromDecorations(decorations, fields);\n if (!viewStyle) return base;\n const colorBy = viewStyle.colorBy ?? base.colorBy;\n const rules = viewStyle.rules ?? base.rules;\n const rows = viewStyle.rows ?? base.rows;\n const columns = viewStyle.columns ?? base.columns;\n const cells = viewStyle.cells ?? base.cells;\n return {\n version: 1,\n ...(colorBy !== undefined ? { colorBy } : {}),\n ...(rules !== undefined ? { rules } : {}),\n ...(rows !== undefined ? { rows } : {}),\n ...(columns !== undefined ? { columns } : {}),\n ...(cells !== undefined ? { cells } : {}),\n };\n}\n","\"use client\";\n\n// src/formatControls.tsx — @ai-matrx/records-ui · merge tranche 6e (formats)\n//\n// THE FORMAT-AWARE EDITOR — the older /data grid's `FormatAwareInput` and `RatingInput`,\n// rewritten onto the platform registry. A column that shows as money takes \"$1,250.50\"; a percent\n// kept as a fraction is typed as the percent a person reads (45, or \"45%\") and kept as 0.45; a\n// rating is its stars; a time of day, a colour, an email, a link, a phone number get the input\n// that fits them. Parsing is the registry's own (`parseFieldInput`), so what the cell shows and\n// what the editor reads are one vocabulary.\n//\n// `formatControl` answers `null` for a format with no opinion about its input — the caller keeps\n// the kind's own control (THE FALLBACK LAW applied to editing: a format may add a better input,\n// never take a working one away).\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { BasicInput, BasicTextarea } from \"@ai-matrx/design-system\";\nimport { getFieldFormat, parseFieldInput, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\n\nimport { RatingStars } from \"./formattedValue\";\n\ninterface FormatControlArgs {\n format: FieldFormatConfig;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id: string;\n label: string;\n /** A page nobody is signed into: the browser may offer the person's own email and phone. */\n ownDetails?: boolean | undefined;\n}\n\n/** Number formats typed as text, so a symbol, a comma or a percent sign is read, never refused by the browser. */\nconst TYPED_NUMBERS = new Set([\"currency\", \"percent\", \"progress\", \"decimal\", \"duration\", \"file_size\", \"integer\"]);\n\n/** A percent kept as a fraction is shown and typed ×100. */\nfunction scaled(format: FieldFormatConfig): boolean {\n return (format.id === \"percent\" || format.id === \"progress\") && format.options?.percentScale === \"fraction\";\n}\n\n/** What the box starts holding for a stored value. */\nexport function typedText(format: FieldFormatConfig, value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" && scaled(format)) return String(Math.round(value * 100 * 1e6) / 1e6);\n return String(value);\n}\n\n/** What a typed text is kept as, in this format. Null for an empty box. */\nexport function keptValue(format: FieldFormatConfig, raw: string): unknown {\n if (raw.trim() === \"\") return null;\n const parsed = parseFieldInput(raw, format);\n if (typeof parsed === \"number\" && scaled(format)) return Math.round((parsed / 100) * 1e9) / 1e9;\n return parsed;\n}\n\nfunction NumberInFormat({ format, value, onChange, disabled, id }: FormatControlArgs) {\n const [text, setText] = useState(() => typedText(format, value));\n // A value that moves under the box (a reload, a seed) is shown — unless it is what was just typed.\n const lastSent = useRef<unknown>(undefined);\n useEffect(() => {\n if (value === lastSent.current) return;\n setText(typedText(format, value));\n }, [value, format]);\n return (\n <BasicInput\n id={id}\n inputMode=\"decimal\"\n className=\"tabular-nums\"\n value={text}\n disabled={disabled}\n placeholder={format.id === \"currency\" ? \"$0.00\" : format.id === \"percent\" || format.id === \"progress\" ? \"45%\" : undefined}\n onChange={(e) => {\n setText(e.target.value);\n const next = keptValue(format, e.target.value);\n lastSent.current = next;\n onChange(next);\n }}\n />\n );\n}\n\n/** The input a format supplies, or null when the kind's own control is the right one. */\nexport function formatControl(args: FormatControlArgs): ReactNode | null {\n const def = getFieldFormat(args.format.id);\n if (!def) return null;\n const { format, value, onChange, disabled, id, label, ownDetails } = args;\n const text = value === null || value === undefined ? \"\" : String(value);\n const commit = (raw: string) => onChange(raw === \"\" ? null : parseFieldInput(raw, format));\n\n if (def.id === \"rating\") {\n return disabled ? (\n <RatingStars value={value} max={format.options?.ratingMax ?? 5} label={label} />\n ) : (\n <span id={id} className=\"inline-flex\">\n <RatingStars value={value} max={format.options?.ratingMax ?? 5} label={label} onRate={(n) => onChange(n)} />\n </span>\n );\n }\n if (TYPED_NUMBERS.has(def.id)) return <NumberInFormat {...args} />;\n switch (def.editor) {\n // A TIME OF DAY is not this file's: `FieldControl` draws the typed box and its helper\n // (`TypedWordsControl`), never the browser's time control (grids review 3, 2026-09-30).\n case \"email\":\n case \"url\":\n case \"tel\":\n return (\n <BasicInput\n id={id}\n type={def.editor}\n // THE RIGHT KEYBOARD (TYPEFORM-2): @ for an email, the dial pad for a phone, .com for a link.\n inputMode={def.editor}\n {...(ownDetails ? { autoComplete: def.editor } : {})}\n value={text}\n disabled={disabled}\n onChange={(e) => commit(e.target.value)}\n />\n );\n case \"color\":\n return (\n <span className=\"flex items-center gap-2\">\n <BasicInput\n id={`${id}-swatch`}\n type=\"color\"\n aria-label={`${label} — pick a colour`}\n className=\"h-8 w-12 p-1\"\n value={/^#[0-9a-fA-F]{6}$/.test(text) ? text : \"#000000\"}\n disabled={disabled}\n onChange={(e) => commit(e.target.value)}\n />\n <BasicInput id={id} value={text} placeholder=\"#3b82f6\" disabled={disabled} onChange={(e) => commit(e.target.value)} />\n </span>\n );\n case \"textarea\":\n return <BasicTextarea id={id} rows={4} value={text} disabled={disabled} onChange={(e) => commit(e.target.value)} />;\n default:\n return null;\n }\n}\n","\"use client\";\n\n// src/formattedValue.tsx — @ai-matrx/records-ui · merge tranche 6e (formats)\n//\n// A VALUE IN THE FORMAT ITS COLUMN SHOWS AS — the older /data grid's `FormattedFieldValue`,\n// rewritten onto the platform registry (`@ai-matrx/design-system/field-formats`) with no app\n// import: a star rating is stars, a progress column is a bar, an email is a mail link, an\n// address opens in maps, a colour is its swatch, tags are chips. Everything else is the\n// registry's own text, through the design-system's `FormattedCell`, so the fallback law rides\n// along: a value that does not fit its format is shown as stored, in amber, with the reason.\n//\n// A rating is ONE click from the read view (THE CLICK LAW, inventory A2): given `onRate`, each\n// star is a button that writes its number; without it the stars are a picture.\n\nimport { useRef, type ReactNode } from \"react\";\nimport { FormattedCell } from \"@ai-matrx/design-system/data-table\";\nimport { formatFieldValue, formatPhone, getFieldFormat, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport { cn } from \"@ai-matrx/design-system\";\n\nconst LINK = \"inline-flex min-w-0 items-center gap-1 text-primary hover:underline\";\n\n/** Stop a link's click from also opening the cell or the row behind it. */\nconst own = (event: { stopPropagation: () => void }) => event.stopPropagation();\n\n/** The number a rating or a bar reads, or null. */\nfunction numberOf(value: unknown): number | null {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"string\" && value.trim() !== \"\") {\n const n = Number(value.replace(/[,\\s%]/g, \"\"));\n return Number.isFinite(n) ? n : null;\n }\n return null;\n}\n\n/** A star rating. `onRate` makes each star a control; a second press on the chosen star clears it. */\nexport function RatingStars({\n value,\n max = 5,\n onRate,\n label,\n selectFirst,\n}: {\n value: unknown;\n max?: number;\n onRate?: ((next: number | null) => void) | undefined;\n label?: string;\n /**\n * IN A GRID, A CLICK SELECTS (grids review 3, 2026-09-30: one click on a rating cell wrote 4\n * stars). A press on a star of a cell that is not yet the grid's cursor reaches the grid, which\n * selects the cell, and writes nothing; once the cell is selected a star press rates it (Airtable).\n * A keyboard press on a star (`detail === 0`) always rates.\n */\n selectFirst?: boolean | undefined;\n}) {\n // Was this star's cell already the grid's cursor when the pointer came down? Read at the press,\n // before the grid's own mousedown moves the cursor there.\n const armed = useRef(true);\n const score = numberOf(value) ?? 0;\n const shown = Math.round(score);\n const said = `${shown} out of ${max}`;\n return (\n <span\n data-records-rating=\"\"\n role={onRate ? \"radiogroup\" : \"img\"}\n aria-label={label ? `${label}: ${said}` : said}\n title={said}\n className=\"inline-flex items-center gap-0.5\"\n {...(onRate ? { \"data-matrx-cell-control\": \"\" } : {})}\n >\n {Array.from({ length: max }, (_, i) => {\n const n = i + 1;\n const lit = n <= shown;\n const star = (\n <span aria-hidden className={cn(\"text-sm leading-none\", lit ? \"text-amber-400\" : \"text-muted-foreground/40\")}>\n ★\n </span>\n );\n return onRate ? (\n <button\n key={n}\n type=\"button\"\n role=\"radio\"\n aria-checked={n === shown}\n aria-label={`${n} out of ${max}`}\n data-records-rating-star={n}\n className=\"rounded px-px focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onMouseDown={(event) => {\n if (!selectFirst) {\n own(event);\n return;\n }\n // The press goes on to the grid, which selects the cell and keeps the keyboard.\n armed.current = event.currentTarget.closest(\"td\")?.hasAttribute(\"data-matrx-cell-active\") === true;\n }}\n onDoubleClick={own}\n onClick={(event) => {\n event.stopPropagation();\n if (selectFirst && event.detail !== 0 && !armed.current) return;\n onRate(n === shown ? null : n);\n }}\n >\n {star}\n </button>\n ) : (\n <span key={n}>{star}</span>\n );\n })}\n </span>\n );\n}\n\n/** The rich drawing for a format that has one, or undefined for the registry's text. */\nfunction rich(id: string, text: string, raw: unknown, format: FieldFormatConfig): ReactNode | undefined {\n switch (id) {\n case \"email\":\n return (\n <a href={`mailto:${text}`} className={LINK} onClick={own}>\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"url\":\n return (\n <a href={text.includes(\"://\") ? text : `https://${text}`} target=\"_blank\" rel=\"noopener noreferrer\" className={LINK} onClick={own}>\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"phone\":\n return (\n <a href={`tel:${text.replace(/[^\\d+]/g, \"\")}`} className={LINK} onClick={own} title={text}>\n <span className=\"truncate tabular-nums\">{formatPhone(text)}</span>\n </a>\n );\n case \"address\":\n return (\n <a\n href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(text)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={LINK}\n title=\"Open in maps\"\n onClick={own}\n >\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"progress\": {\n const n = numberOf(raw);\n if (n === null) return undefined;\n const pct = format.options?.percentScale === \"fraction\" ? n * 100 : n;\n const clamped = Math.max(0, Math.min(100, pct));\n return (\n <span className=\"inline-flex w-full min-w-0 items-center gap-2\" title={text}>\n <span\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(clamped)}\n className=\"h-1.5 min-w-8 flex-1 overflow-hidden rounded-full bg-muted\"\n >\n <span className={cn(\"block h-full rounded-full\", pct >= 100 ? \"bg-emerald-500\" : \"bg-primary\")} style={{ width: `${clamped}%` }} />\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">{text}</span>\n </span>\n );\n }\n case \"color\":\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"h-4 w-4 shrink-0 rounded border border-border\" style={{ backgroundColor: text }} />\n <code className=\"font-mono text-xs\">{text}</code>\n </span>\n );\n case \"tags\": {\n const items = Array.isArray(raw) ? raw.map(String) : text.split(\",\").map((s) => s.trim()).filter(Boolean);\n if (items.length === 0) return undefined;\n return (\n <span className=\"flex flex-wrap items-center gap-1\">\n {items.map((item, i) => (\n <span key={`${item}-${i}`} className=\"inline-flex items-center rounded-md border border-border bg-muted px-1.5 py-0.5 text-xs\">\n {item}\n </span>\n ))}\n </span>\n );\n }\n case \"rating\":\n return numberOf(raw) === null ? undefined : <RatingStars value={raw} max={format.options?.ratingMax ?? 5} />;\n default:\n return undefined;\n }\n}\n\n/**\n * ONE VALUE, DRAWN IN ITS FORMAT. `null` when there is no format (the caller keeps its own\n * drawing); otherwise never blank and never a throw.\n */\nexport function FormattedValue({\n value,\n format,\n onRate,\n selectFirst,\n}: {\n value: unknown;\n format: FieldFormatConfig;\n /** A rating's one-click write, when this person may change the value. */\n onRate?: ((next: number | null) => void) | undefined;\n /** In a grid: the first press selects the cell, a press on the selected cell rates (`RatingStars`). */\n selectFirst?: boolean | undefined;\n}): ReactNode {\n const def = getFieldFormat(format.id);\n // A rating a person may change is stars even when empty — the empty stars ARE the control.\n // (A stored score outside 0…max is not a rating: it falls to the registry's amber below, so a\n // 1250 never draws as five lit stars.)\n const score = numberOf(value);\n const max = format.options?.ratingMax ?? 5;\n if (def?.id === \"rating\" && onRate && (value === null || value === undefined || value === \"\" || (score !== null && score >= 0 && score <= max))) {\n return <RatingStars value={value} max={format.options?.ratingMax ?? 5} onRate={onRate} selectFirst={selectFirst} />;\n }\n const result = formatFieldValue(value, format);\n if (!result.ok || result.empty || !def?.rich) return <FormattedCell result={result} />;\n return rich(def.id, result.text, value, format) ?? <FormattedCell result={result} />;\n}\n\n/** What a link chip says: the site, and the page or file when there is one (\"unsplash.com · photo.jpg\"). */\nexport function linkChipText(raw: string): string {\n try {\n const url = new URL(raw.includes(\"://\") ? raw : `https://${raw}`);\n const host = url.hostname.replace(/^www\\./, \"\");\n const last = url.pathname.split(\"/\").filter(Boolean).pop();\n return last ? `${host} · ${decodeURIComponent(last)}` : host;\n } catch {\n return raw;\n }\n}\n","\"use client\";\n\n// src/typedDateHelper.tsx — @ai-matrx/records-ui\n//\n// THE SMALL CALENDAR AND CLOCK BESIDE A TYPED DATE — A HELPER THAT NEVER OWNS THE KEYS.\n//\n// 🚨 WHY (grids review 3, 2026-09-30, a BLOCKER). Double-click, Enter or F2 on a date & time cell\n// opened the BROWSER'S OWN picker (`<input type=\"datetime-local\">`): Space dropped its calendar,\n// typing `10/03/2026 1200PM` landed in its segments one at a time and the time was lost, and Enter\n// saved the moment it was pressed — Sep 30, 1:36 AM. A cell opened by typing already worked.\n//\n// THE RULE (Google Sheets and Airtable): every way into a date, a time or a date-and-time editor is\n// ONE plain text box, read ONCE on commit by the one reader (`@ai-matrx/records` `readTypedDate` /\n// `readTypedTime`). Beside it sits this: a calendar (and, for a moment, a list of times) for the\n// person who would rather point. It is a mouse helper only — it takes no focus, it is not in the Tab\n// order, a press in it never blurs the box (so it never commits the cell), and a pick writes WORDS\n// into the box, the same words a person could have typed; the reader still decides.\n\nimport { useState } from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, cn } from \"@ai-matrx/design-system\";\nimport { readTypedDate, readTypedTime, typedDateText, typedTimeText } from \"@ai-matrx/records\";\nimport { personWallNow, usePersonTimeZone } from \"./personTime\";\n\n/** What the helper offers: a calendar, a list of times, or both. */\nexport type DateHelperKind = \"date\" | \"datetime\" | \"time\";\n\nconst WEEK = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\n\nfunction pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** The day and the time the box's words read as right now, when they read at all. */\nfunction readBox(text: string, kind: DateHelperKind): { day: string | null; time: { h: number; m: number } | null } {\n if (kind === \"time\") {\n const t = readTypedTime(text);\n if (!t.ok) return { day: null, time: null };\n const [h, m] = t.value.split(\":\").map(Number);\n return { day: null, time: { h: h!, m: m! } };\n }\n const read = readTypedDate(text, { withTime: kind === \"datetime\" });\n if (!read.ok) return { day: null, time: null };\n if (kind === \"datetime\" && read.instant) {\n const at = new Date(read.instant);\n return { day: read.day, time: { h: at.getHours(), m: at.getMinutes() } };\n }\n return { day: read.day, time: null };\n}\n\n/** The words the box takes for a day and a time, in the reader's own order. */\nfunction wordsFor(kind: DateHelperKind, day: string | null, time: { h: number; m: number } | null): string {\n if (kind === \"time\") return time ? typedTimeText(time.h, time.m) : \"\";\n if (!day) return \"\";\n const dayText = typedDateText(day);\n return kind === \"datetime\" && time ? `${dayText} ${typedTimeText(time.h, time.m)}` : dayText;\n}\n\n/** Keeps the pointer from ever taking focus off the text box — the helper never owns the keys. */\nconst keepFocus = { onMouseDown: (e: { preventDefault: () => void }) => e.preventDefault(), tabIndex: -1 } as const;\n\nfunction CalendarGlyph() {\n return (\n <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" />\n <path d=\"M16 2v4M8 2v4M3 10h18\" />\n </svg>\n );\n}\nfunction ClockGlyph() {\n return (\n <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 6v6l4 2\" />\n </svg>\n );\n}\n\n/**\n * `onPicked`: a pick that completes the value (a day for a date, a time for a time or a moment) is\n * a finished edit, as in Notion — the host saves and closes. Typing in the box is untouched.\n */\nexport function TypedDateHelper({\n kind,\n text,\n onText,\n label,\n onPicked,\n startOpen = false,\n}: {\n kind: DateHelperKind;\n text: string;\n onText: (text: string) => void;\n label: string;\n onPicked?: (() => void) | undefined;\n /**\n * OPEN FROM THE FIRST FRAME (Arman 2026-10-08: a date took three clicks to reach its calendar).\n * A cell opened by a click, Enter or F2 shows its calendar at once beside the box (Notion,\n * Airtable); the box still holds the keyboard, so typing a date needs no further click. A cell\n * opened by typing keeps it closed — that person is already typing.\n */\n startOpen?: boolean | undefined;\n}) {\n const [open, setOpen] = useState(startOpen);\n const held = readBox(text, kind);\n usePersonTimeZone();\n const today = personWallNow();\n const start = held.day ? new Date(Number(held.day.slice(0, 4)), Number(held.day.slice(5, 7)) - 1, 1) : new Date(today.getFullYear(), today.getMonth(), 1);\n const [month, setMonth] = useState<{ y: number; m: number } | null>(null);\n const shown = month ?? { y: start.getFullYear(), m: start.getMonth() };\n const first = new Date(shown.y, shown.m, 1).getDay();\n const days = new Date(shown.y, shown.m + 1, 0).getDate();\n const cells: Array<number | null> = [...Array.from({ length: first }, () => null), ...Array.from({ length: days }, (_, i) => i + 1)];\n const todayKey = `${today.getFullYear()}-${pad(today.getMonth() + 1)}-${pad(today.getDate())}`;\n const times = Array.from({ length: 48 }, (_, i) => ({ h: Math.floor(i / 2), m: (i % 2) * 30 }));\n const pickDay = (d: number) => {\n const day = `${shown.y}-${pad(shown.m + 1)}-${pad(d)}`;\n onText(wordsFor(kind, day, held.time));\n if (kind === \"date\") {\n setOpen(false);\n onPicked?.();\n }\n };\n const pickTime = (t: { h: number; m: number }) => {\n const day = kind === \"datetime\" ? (held.day ?? todayKey) : null;\n onText(wordsFor(kind, day, t));\n setOpen(false);\n onPicked?.();\n };\n const turn = (by: number) => {\n const at = new Date(shown.y, shown.m + by, 1);\n setMonth({ y: at.getFullYear(), m: at.getMonth() });\n };\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n {...keepFocus}\n data-records-date-helper=\"\"\n aria-label={kind === \"time\" ? `Pick a time for ${label}` : `Pick a date for ${label}`}\n title={kind === \"time\" ? \"Pick a time\" : \"Pick a date\"}\n className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {kind === \"time\" ? <ClockGlyph /> : <CalendarGlyph />}\n </button>\n </PopoverTrigger>\n <PopoverContent\n sizing=\"content\"\n align=\"start\"\n className=\"p-2\"\n data-matrx-cell-editor=\"\"\n data-records-date-helper-panel=\"\"\n // THE BOX KEEPS THE KEYBOARD: the helper opens without taking focus and never hands it back\n // somewhere else when it closes.\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex gap-2\">\n {kind === \"time\" ? null : (\n <div className=\"flex flex-col gap-1\" role=\"grid\" aria-label={`${MONTHS[shown.m]} ${shown.y}`}>\n <div className=\"flex items-center justify-between text-xs font-medium\">\n <button type=\"button\" {...keepFocus} aria-label=\"Previous month\" className=\"rounded px-1.5 hover:bg-muted\" onClick={() => turn(-1)}>\n ‹\n </button>\n <span>\n {MONTHS[shown.m]} {shown.y}\n </span>\n <button type=\"button\" {...keepFocus} aria-label=\"Next month\" className=\"rounded px-1.5 hover:bg-muted\" onClick={() => turn(1)}>\n ›\n </button>\n </div>\n <div className=\"grid grid-cols-7 gap-0.5 text-center text-[11px]\">\n {WEEK.map((w) => (\n <span key={w} className=\"text-muted-foreground\">\n {w}\n </span>\n ))}\n {cells.map((d, i) => {\n if (d === null) return <span key={`blank-${i}`} />;\n const key = `${shown.y}-${pad(shown.m + 1)}-${pad(d)}`;\n return (\n <button\n key={key}\n type=\"button\"\n {...keepFocus}\n data-records-date-helper-day={key}\n className={cn(\n \"h-6 w-6 rounded tabular-nums hover:bg-muted\",\n key === held.day ? \"bg-primary text-primary-foreground hover:bg-primary\" : \"\",\n key === todayKey && key !== held.day ? \"ring-1 ring-ring\" : \"\",\n )}\n onClick={() => pickDay(d)}\n >\n {d}\n </button>\n );\n })}\n </div>\n </div>\n )}\n {kind === \"date\" ? null : (\n <div className=\"flex max-h-48 flex-col overflow-y-auto pr-1 text-[11px]\" aria-label=\"Times\">\n {times.map((t) => (\n <button\n key={`${t.h}:${t.m}`}\n type=\"button\"\n {...keepFocus}\n data-records-date-helper-time={`${pad(t.h)}:${pad(t.m)}`}\n className={cn(\n \"whitespace-nowrap rounded px-2 py-0.5 text-left tabular-nums hover:bg-muted\",\n held.time && held.time.h === t.h && held.time.m === t.m ? \"bg-primary text-primary-foreground\" : \"\",\n )}\n onClick={() => pickTime(t)}\n >\n {typedTimeText(t.h, t.m)}\n </button>\n ))}\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","// The person's time zone, as the app saved it (userPreferences.display.timeZone).\n//\n// The host app tells this package once (`setPersonTimeZone(\"America/Los_Angeles\")`); every \"today\" and\n// \"now\" a screen draws (the calendar's today marker and now-line, a timeline's today, a date picker's\n// today) is read in that zone instead of the device's. With nothing set the device zone applies, as before.\n// Nothing here stores a zone: the host's saved preference is the one place, this is its mirror.\n\nimport { useSyncExternalStore } from \"react\";\n\nlet zone: string | null = null;\nconst listeners = new Set<() => void>();\n\nfunction valid(z: unknown): z is string {\n if (typeof z !== \"string\" || !z.trim()) return false;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: z });\n return true;\n } catch {\n return false;\n }\n}\n\n/** The host app's saved zone (IANA). `null` / junk clears it: the device zone applies. */\nexport function setPersonTimeZone(next: string | null | undefined): void {\n const clean = valid(next) ? next : null;\n if (clean === zone) return;\n zone = clean;\n listeners.forEach((l) => l());\n}\n\nexport function getPersonTimeZone(): string | null {\n return zone;\n}\n\n/** Re-renders the caller when the zone changes; returns it. */\nexport function usePersonTimeZone(): string | null {\n return useSyncExternalStore(\n (cb) => {\n listeners.add(cb);\n return () => listeners.delete(cb);\n },\n () => zone,\n () => null,\n );\n}\n\n/**\n * `at` as a Date whose LOCAL fields (getFullYear, getHours, ...) read the wall clock in the person's zone.\n * For day / hour math only: never compare it with a stored instant.\n */\nexport function personWallNow(at: Date = new Date()): Date {\n if (!zone) return at;\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: zone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hourCycle: \"h23\",\n }).formatToParts(at);\n const n = (t: string) => Number(parts.find((p) => p.type === t)?.value ?? 0);\n return new Date(n(\"year\"), n(\"month\") - 1, n(\"day\"), n(\"hour\"), n(\"minute\"), n(\"second\"));\n}\n","// src/choiceNudge.ts — @ai-matrx/records-ui\n//\n// THE CHOICE NUDGE, READ ONCE PER CLIENT (lane CHOICE-COLUMN-EDIT, 2026-09-27).\n//\n// What a choice cell does with typed words that are not a choice is the Feature Knob\n// `custom/choice_nudge` (`client.choiceNudge()`): ask (the default), always add, or never add.\n// It is the same answer for every cell a client draws, so it is asked ONCE per client — one\n// client is one organization — and every cell after the first reads the cached answer. A door\n// that refuses or is absent answers the knob's own default, `ask`, which is the safe one: the\n// person is asked rather than something being added or refused on their behalf.\n\nimport { useEffect, useState } from \"react\";\nimport type { ChoiceNudge } from \"@ai-matrx/records\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\n\nconst asked = new WeakMap<object, Promise<ChoiceNudge>>();\n\n/** The knob for this client, asked once and cached for the life of the client. */\nexport function choiceNudgeOf(client: RecordsClient): Promise<ChoiceNudge> {\n let answer = asked.get(client);\n if (!answer) {\n answer = Promise.resolve()\n .then(() => client.choiceNudge())\n .then(\n (result) => (result.ok ? result.data : \"ask\"),\n () => \"ask\" as const,\n );\n asked.set(client, answer);\n }\n return answer;\n}\n\n/**\n * The knob, for a control that needs it. `null` while it is asked (a control waits rather than\n * deciding on a guess); `ask` when there is no client at all (a public page), since no door can\n * add a choice there anyway.\n */\nexport function useChoiceNudge(enabled = true): ChoiceNudge | null {\n const client = useOptionalRecordsClient();\n const [nudge, setNudge] = useState<ChoiceNudge | null>(null);\n useEffect(() => {\n if (!enabled || !client) return;\n let live = true;\n void choiceNudgeOf(client).then((answer) => {\n if (live) setNudge(answer);\n });\n return () => {\n live = false;\n };\n }, [client, enabled]);\n if (!client) return \"ask\";\n return nudge;\n}\n","\"use client\";\n\n// src/RecordsMount.tsx — @ai-matrx/records-ui\n//\n// THE ONE LINE A HOST ROUTE WRITES. `<RecordsProvider>` from @ai-matrx/records\n// and `<RecordsUiProvider>` from this package are two providers that must be\n// nested in one order, every time — so a route that got the order wrong would\n// fail with \"useRecordsClient was called outside <RecordsProvider>\" at the\n// bottom of a screen nobody was looking at. This mounts both, in the one order\n// that is correct, so a route file stays a mount and nothing more.\n//\n// THE RIGHTS QUESTION — AND THE ANSWER THAT USED TO BE HERE.\n//\n// `storeDecidesRights` returned `{admin: true, comment: true, write: true}` for\n// every non-kernel table, for everybody, on the reasoning that the doors are\n// the authority and a refusal would be shown verbatim when it came. The\n// sixth-pass verdict measured the cost of that reasoning: a colleague at viewer\n// double-clicked a cell, got a live editor, typed a value, pressed Enter, and\n// was told only then that she may not write. \"The permission is right; the\n// screen told her she could.\"\n//\n// It is not a guess any more. The read door has always answered the reader's\n// level on the table and the client now carries it (`Table.your_level`), so\n// this function ASKS instead of assuming, `letTheStoreDecideRights` still means\n// what it says, and a host that binds nothing gets the same honest answer\n// rather than every control absent. Kernel Tables (REC-27) keep their own\n// exclusion: the nine Tables the platform ships are not administered from a\n// person's screen at any level.\n\nimport { useRef, type ReactNode } from \"react\";\nimport type { RecordsActor, RecordsConfig, RecordsDataSource, Table, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider } from \"@ai-matrx/records/react\";\nimport { RecordLabelProvider } from \"./labels\";\n\nimport { NO_RIGHTS, RecordsUiProvider, type RecordsUiHost, type TableRights } from \"./host\";\n\nexport const STORE_DECIDES_REASON =\n \"This host offers exactly what the record store says this person may do: the level comes back with \" +\n \"the table on the read door, so a control they cannot use is never drawn in the first place.\";\n\nexport { KERNEL_REASON } from \"./rights\";\n\n/**\n * DEPRECATED, and kept only so a host that imported it still compiles.\n *\n * It used to answer yes to everything for every non-kernel table. It cannot\n * answer honestly at all, because the honest answer needs a door call and this\n * signature is synchronous — which is exactly why the guess was here. Binding\n * it now would be binding a port that OVERRIDES the store's real answer, so it\n * returns the not-yet-answered set and every caller should simply stop passing\n * a `rights` port: unbound is the honest path (`useTableRights`).\n */\nexport function storeDecidesRights(_table: Table): TableRights {\n return NO_RIGHTS;\n}\n\nexport interface RecordsMountProps {\n /** The store config: the host's session-carrying client, the actor, the organization. */\n config: RecordsConfig;\n /** What this host binds on top — links, toasts, uploads, rights. */\n host?: RecordsUiHost | undefined;\n /**\n * Use `storeDecidesRights` when the host binds no `rights` of its own. Left\n * off, an unbound host gets `NO_RIGHTS` and every administering control is\n * absent with its reason.\n */\n letTheStoreDecideRights?: boolean | undefined;\n children: ReactNode;\n}\n\nexport function RecordsMount({\n config,\n host,\n letTheStoreDecideRights,\n children,\n}: RecordsMountProps) {\n // `letTheStoreDecideRights` means what it says and now needs no port at all:\n // with nothing bound, `useTableRights` asks `custom.my_levels` and draws what\n // the answer allows. A port bound here would OVERRIDE that answer.\n const bound = useShallowStableHost(host);\n void letTheStoreDecideRights;\n return (\n <RecordsProvider config={config}>\n <RecordsUiProvider value={bound}>\n {/* WHAT AN ID IS CALLED. A choice and a relation are stored as the id of\n another record, so every read-only surface needs the same answer to\n \"what is that record called\" — resolved once here rather than once\n per cell, and never drawn as the id itself. */}\n <RecordLabelProvider>{children}</RecordLabelProvider>\n </RecordsUiProvider>\n </RecordsProvider>\n );\n}\n\n/**\n * The actor a signed-in person is. `user` is the store's own word (the closed\n * ACTOR_VOCABULARY is `user` · `agent` · `system`), and AGT-N-4 means an agent\n * acting for this person carries exactly this authority and no other.\n */\n/**\n * THE HOST, AS ONE IDENTITY FOR AS LONG AS ITS PARTS ARE THE SAME (lane RENDER-AUDIT, 2026-09-26).\n *\n * This used to be `{ ...(host ?? {}) }` — a NEW object on every render of the mount — and it is the\n * value of the host context every screen of this package reads (`useRecordsUi`: the table page,\n * the grid, the view bar, every rail). So any render of whatever sits above the mount (a search\n * parameter moving, the organization list arriving, a toast) re-rendered the whole table page and\n * every cell in it, with nothing on the table having changed. Measured on /data with the React\n * profiler hook: 11 host-context renders of `TablePage` during one page load.\n *\n * The host a caller builds is a bag of ports and values; it is the SAME host when every part is the\n * same part. So the previous object is kept until a part changes identity, and a host that builds\n * the bag inline on every render (the common case) costs nothing.\n */\nfunction useShallowStableHost(host: RecordsUiHost | undefined): RecordsUiHost {\n const held = useRef<RecordsUiHost | null>(null);\n const next = host ?? {};\n const previous = held.current;\n if (previous !== null && sameParts(previous, next)) return previous;\n const bound: RecordsUiHost = { ...next };\n held.current = bound;\n return bound;\n}\n\nfunction sameParts(a: RecordsUiHost, b: RecordsUiHost): boolean {\n const aKeys = Object.keys(a) as (keyof RecordsUiHost)[];\n const bKeys = Object.keys(b) as (keyof RecordsUiHost)[];\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) if (a[key] !== b[key]) return false;\n return true;\n}\n\nexport function personActor(userId: Uuid | null | undefined): RecordsActor {\n return userId ? { actor: \"user\", user_id: userId } : { actor: \"user\" };\n}\n\n/**\n * A supabase-js client AS this package's data seam.\n *\n * `RecordsDataSource` is deliberately a small structural subset of\n * `SupabaseClient` — the package holds no key and opens no connection, the host\n * hands it a client that already carries the person's session.\n *\n * IT IS NOT AN IDENTITY CAST, and it cost a live screen to learn why\n * (2026-09-19, /data's first load): the port's `rpc(fn, args, { schema })`\n * says the schema OUT LOUD, because every door of this store is `custom.<name>`\n * and every door of the trust layer is `iam.<name>`. supabase-js's own\n * `rpc(fn, args, options)` has no `schema` option at all — its third argument is\n * `{ head, get, count }` — so a client passed straight through silently asked\n * its default PostgREST profile and the store answered, correctly and uselessly,\n * \"Could not find the function public.table_kernel_id ... PGRST202\". The schema\n * is chosen the one way supabase-js offers: `client.schema(name).rpc(...)`.\n *\n * `schema(name).from(table)` already agrees structurally and is passed through.\n *\n * `fallbackSchema` is the profile a call that says NOTHING is sent to. No caller\n * in `@ai-matrx/records` omits the option — `callDoor` always says `custom` and\n * `trustDoor` always says `iam` — so it never fires today; it exists so that a\n * call which one day forgets lands on the store rather than silently on\n * `public`. It is a FALLBACK and not the answer: a version of this adapter that\n * sent EVERY door to one fixed schema would route the `iam` trust doors (the\n * external principal, the publish binding) into `custom` and get a PGRST202\n * naming the wrong schema.\n *\n * The cast itself stays HERE, once, where it is explained: a generated\n * `Database` type makes `schema().from().select()` enormous, and a host app that\n * passes its client straight into `config` gets `TS2589: Type instantiation is\n * excessively deep and possibly infinite` in its own build (matrx-frontend,\n * 2026-09-18, on all three campaign routes at once).\n */\n/*\n * ONE DATA SOURCE PER SUPABASE CLIENT (owner, 2026-10-02). The record store's data layer keys its\n * cache by the data source object, so a host that builds this adapter again on every mount (a\n * board tile woken or brought back by Undo) must get the SAME object back for the same client —\n * otherwise every remount is a stranger to the answers the last mount read.\n */\nconst dataSources = new WeakMap<object, Map<string, RecordsDataSource>>();\n\nexport function recordsDataSource(client: object, fallbackSchema = \"custom\"): RecordsDataSource {\n let bySchema = dataSources.get(client);\n if (!bySchema) {\n bySchema = new Map();\n dataSources.set(client, bySchema);\n }\n const held = bySchema.get(fallbackSchema);\n if (held) return held;\n const made = makeRecordsDataSource(client, fallbackSchema);\n bySchema.set(fallbackSchema, made);\n return made;\n}\n\nfunction makeRecordsDataSource(client: object, fallbackSchema: string): RecordsDataSource {\n const supabase = client as unknown as {\n rpc: (fn: string, args: Record<string, unknown>) => PromiseLike<unknown>;\n schema: (name: string) => {\n rpc: (fn: string, args: Record<string, unknown>) => PromiseLike<unknown>;\n from: (table: string) => unknown;\n };\n auth?: { getSession?: () => Promise<{ data?: { session?: unknown } | null }> };\n };\n return {\n // PAGE-BUNDLE: the real adapter opens a table page with one `custom.table_page_bundle` call.\n opensInOneCall: true,\n async rpc(fn, args, options) {\n const schema = options?.schema ?? fallbackSchema;\n // 🚨 NO STORE DOOR LEAVES WITHOUT A PERSON (lane MONITOR-TRIAGE, 2026-10-01). `anon` holds\n // no USAGE on schema `custom`, so a door called with no session can only come back\n // \"42501 permission denied for schema custom\" (HTTP 401) — seven of them per signed-out\n // /data load (inbox, counts, home, portals…), every one a red row in ops.system_error.\n // A `custom` door with no session is answered HERE, with the store's own signed-out\n // sentence and no network call. Other schemas (`iam`, `platform`) serve guests by design\n // and are never short-circuited. A client without `auth` (a server or test seam) is\n // passed straight through.\n if (schema === \"custom\" && supabase.auth?.getSession && !(await hasSession(supabase.auth.getSession))) {\n return { data: null, error: SIGNED_OUT } as Awaited<ReturnType<RecordsDataSource[\"rpc\"]>>;\n }\n const on = supabase.schema(schema);\n return (await on.rpc(fn, args)) as Awaited<ReturnType<RecordsDataSource[\"rpc\"]>>;\n },\n schema(name) {\n return supabase.schema(name) as ReturnType<RecordsDataSource[\"schema\"]>;\n },\n };\n}\n\n/** The read door's own sentence for a call with nobody signed in (`custom.read_records_page`, DOOR-1). */\nconst SIGNED_OUT = {\n code: \"42501\",\n message: \"Nobody is signed in, so there is nothing to read.\",\n hint: \"Sign in, then try again.\",\n details: null,\n} as const;\n\nasync function hasSession(getSession: () => Promise<{ data?: { session?: unknown } | null }>): Promise<boolean> {\n try {\n const answer = await getSession();\n return Boolean(answer?.data?.session);\n } catch {\n // Auth could not say: let the request go and the database's answer stand.\n return true;\n }\n}\n","\"use client\";\n\n// src/tablePicking.tsx — @ai-matrx/records-ui · lane 10 VIEWS-AND-FIELDS W1-A\n//\n// WHICH TABLES A \"CHOOSE A TABLE\" CONTROL OFFERS — ONE RULE FOR EVERY PICKER.\n//\n// Every choice column makes a backing List (`kept_for = 'choices'`, named \"<column> choices\").\n// The link-target picker listed all of them beside the organization's tables: 64 entries on a\n// clinic's account, \"Status choices\" five times, no way to tell them apart. Four other pickers had\n// each grown their own inline filter for the same question (`!kept_by_the_app` here, a lane check\n// there, `work_kind` somewhere else), and the one that had none flooded.\n//\n// THE RULE:\n// · by default a picker offers TABLES — never a value set or anything else the app keeps for\n// itself (the choice lists, checklist steps, booking slots, the app's own bookkeeping);\n// · \"Show lists\" adds the value sets, each named by its column and its owning table\n// (\"Status — Patient Visits\"), so no two visible entries share a name;\n// · the table already chosen is always offered, whatever it is, so a saved choice never vanishes.\n//\n// Which table is a value set, and which table owns it, are the store's facts\n// (`custom.table_facts`: `kept_for`, `used_in_table_id`; `custom.data_home_tables`: `kind`).\n// Nothing here guesses from a name except trimming the store's own \" choices\" suffix for the label.\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { withTablePlacement, type Table, type TablePlacementFact } from \"@ai-matrx/records\";\nimport { useRecordsClient, useTables } from \"@ai-matrx/records/react\";\nimport { Checkbox, cn } from \"@ai-matrx/design-system\";\n\n/** The facts a picker needs about one table, whichever list it came from. */\nexport interface PickerTable {\n id: string;\n name: string;\n kept_by_the_app?: boolean | null | undefined;\n /** `custom.table_facts`: which feature keeps it (`choices` for a value set). */\n kept_for?: string | null | undefined;\n /** `custom.data_home_tables`: the store's one word for what it is (`list` for a value set). */\n kind?: string | null | undefined;\n /** The table a value set belongs to (`custom.table_facts.used_in_table_id`). */\n used_in_table_id?: string | null | undefined;\n /** A checklist's steps, a booking page's slots, a workflow's states. */\n work_kind?: unknown;\n slug?: string | null | undefined;\n /** When the table was made — what tells two lists apart once their column is gone. */\n created_at?: string | null | undefined;\n}\n\n/** The slug prefix of the tables this package keeps for its own bookkeeping (saved views, forms …). */\nconst PLATFORM_TABLE_PREFIX = \"records_ui_\";\n\n/** A value set: the List a choice column keeps its choices in. */\nexport function isValueSet(table: PickerTable): boolean {\n if (table.kept_for === \"choices\") return true;\n return table.kept_for == null && table.kind === \"list\" && table.kept_by_the_app === true;\n}\n\n/** Anything the app keeps for itself rather than a table a person keeps. */\nexport function isKeptTable(table: PickerTable): boolean {\n return (\n table.kept_by_the_app === true ||\n isValueSet(table) ||\n Boolean(table.work_kind) ||\n (table.slug ?? \"\").startsWith(PLATFORM_TABLE_PREFIX)\n );\n}\n\nexport interface TablePickerEntry<T extends PickerTable> {\n table: T;\n id: string;\n /** Unique among the entries returned. */\n label: string;\n /** A value set (shown only with \"Show lists\", or because it is the chosen one). */\n isList: boolean;\n}\n\nexport interface TablePickerEntries<T extends PickerTable> {\n entries: TablePickerEntry<T>[];\n /** How many value sets \"Show lists\" would add — 0 means the control is not worth drawing. */\n listCount: number;\n}\n\nconst CHOICES_SUFFIX = / choices$/i;\n\n/**\n * THE ONE RULE. Tables first (by name), then — with `showLists` — the value sets, each named\n * \"<column> — <owning table>\". Any names still equal get \" (2)\", \" (3)\" so no two entries match.\n */\nexport function tablePickerEntries<T extends PickerTable>(\n tables: readonly T[],\n options: { showLists?: boolean; keep?: string | null | undefined } = {},\n): TablePickerEntries<T> {\n const byId = new Map(tables.map((t) => [t.id, t]));\n const lists = tables.filter(isValueSet);\n const listLabel = (t: T): string => {\n const column = t.name.replace(CHOICES_SUFFIX, \"\");\n // A LIST WHOSE COLUMN IS GONE: `custom.table_facts` names the list itself (or nothing) as where\n // it is used. Said so, and told apart by the day it was made — never by a counter.\n if (!t.used_in_table_id || t.used_in_table_id === t.id) {\n const made = madeOn(t.created_at);\n return made ? `${column} — no column · ${made}` : `${column} — no column`;\n }\n const owner = byId.get(t.used_in_table_id);\n // Owned by a table this person cannot see: its own name, as the store gave it.\n if (!owner) return t.name;\n return `${column} — ${owner.name}`;\n };\n const plain = tables\n .filter((t) => !isKeptTable(t) || (t.id === options.keep && !isValueSet(t)))\n .map((t) => ({ table: t, id: t.id, label: t.name, isList: false }))\n .sort((a, b) => a.label.localeCompare(b.label));\n const shownLists = lists\n .filter((t) => options.showLists || t.id === options.keep)\n .map((t) => ({ table: t, id: t.id, label: listLabel(t), isList: true }))\n .sort((a, b) => a.label.localeCompare(b.label));\n const entries = [...plain, ...shownLists];\n const seen = new Map<string, number>();\n for (const entry of entries) {\n const key = entry.label.toLowerCase();\n const n = (seen.get(key) ?? 0) + 1;\n seen.set(key, n);\n if (n > 1) entry.label = `${entry.label} (${n})`;\n }\n return { entries, listCount: lists.length };\n}\n\n/** \"Sep 3, 2026\" in the reader's own locale, or null when the store gave no date. */\nfunction madeOn(stamp: string | null | undefined): string | null {\n if (!stamp) return null;\n const at = new Date(stamp);\n if (Number.isNaN(at.getTime())) return null;\n return new Intl.DateTimeFormat(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" }).format(at);\n}\n\n/**\n * The organization's tables with the store's placement facts folded on (`kept_for`,\n * `used_in_table_id`), for a picker that reads `tableList()`. A store with no facts door, or one\n * that did not answer, leaves each table as `tableList()` gave it — its own `kept_by_the_app`.\n */\nexport function usePickerTables(): { loading: boolean; data: Array<Table & PickerTable>; reload: () => void } {\n const client = useRecordsClient();\n const tables = useTables();\n const [facts, setFacts] = useState<TablePlacementFact[] | null | \"reading\">(\"reading\");\n // A table made FROM a picker (\"New table…\" in the link-target picker) is read again, list and\n // facts both, so the picker offers what it just made.\n const [nonce, setNonce] = useState(0);\n const reloadTables = tables.reload;\n const reload = useCallback(() => {\n reloadTables();\n setNonce((n) => n + 1);\n }, [reloadTables]);\n useEffect(() => {\n let alive = true;\n void client.tableFacts().then((answered) => {\n if (alive) setFacts(answered.ok ? ((answered.data as unknown as TablePlacementFact[] | null) ?? null) : null);\n });\n return () => {\n alive = false;\n };\n }, [client, nonce]);\n const data = useMemo(\n () => withTablePlacement(tables.data ?? [], facts === \"reading\" ? null : facts) as Array<Table & PickerTable>,\n [tables.data, facts],\n );\n return { loading: tables.loading || facts === \"reading\", data, reload };\n}\n\n/** The \"Show lists\" control beside a table picker. Drawn only when there are lists to show. */\nexport function ShowListsToggle({\n count,\n on,\n onChange,\n className,\n}: {\n count: number;\n on: boolean;\n onChange: (on: boolean) => void;\n className?: string | undefined;\n}) {\n if (count === 0) return null;\n return (\n <label className={cn(\"flex items-center gap-1.5 text-[11px] text-muted-foreground\", className)}>\n <Checkbox checked={on} onCheckedChange={(next) => onChange(next === true)} aria-label=\"Show lists\" />\n Show lists ({count})\n </label>\n );\n}\n","\"use client\";\n\n// src/DataBindingPicker.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// \"FROM MY DATA\" — ONE PICKER FOR EVERY BINDING. A value that is filled from a person's own table\n// when something runs: an agent variable (matrx-frontend's CustomDataBindingPicker, the first\n// author of this shape and these words) and a workflow input (the studio's Collect Inputs field)\n// bind through the SAME declaration, resolved server-side by the SAME merge-field resolver\n// (aidream `conversation_context.merge_field_bindings`). This file is that picker's portable\n// half: table (every Table the person can open, in every organization), shape (whole table /\n// one record / one field of a record), the record, the field, the row template with clickable\n// placeholders, the row limit and what happens when nothing is found — all by NAME.\n//\n// THE SHAPE IS THE MERGE-FIELD DECLARATION, verbatim (`DataBinding` mirrors @ai-matrx/chat's\n// `CustomDataBinding`): `{kind: \"merge_field\", source: \"record\", semantic_type, table_id,\n// record_id?, field_key?, limit?, transform?: {name: \"list\", template, join?, max?}, missing,\n// override_policy: \"shown_locked\"}`.\n\nimport { useEffect, useMemo } from \"react\";\nimport type { Field, RecordsDataSource, Table, Uuid } from \"@ai-matrx/records\";\nimport { isEntityReferenceConfig } from \"@ai-matrx/records\";\nimport { useFields, useTable } from \"@ai-matrx/records/react\";\nimport { BasicInput, Button, CreatablePicker, cn, type CreatableOption } from \"@ai-matrx/design-system\";\nimport { fieldName } from \"./names\";\nimport { RecordPicker, TablePicker, TableScope, useTablesAnywhere } from \"./TablePickers\";\n\nexport interface DataBinding {\n kind: \"merge_field\";\n source: \"record\";\n semantic_type: \"collection\" | \"reference\" | \"value\";\n table_id: string;\n record_id?: string;\n field_key?: string;\n match?: Record<string, string | number | boolean | null>;\n limit?: number;\n transform?: { name: \"list\"; template: string; join?: string; max?: number };\n missing: \"absent\" | \"block\";\n override_policy: \"shown_locked\";\n}\n\nexport type DataBindingShape = DataBinding[\"semantic_type\"];\n\nexport const DATA_BINDING_SHAPES: { value: DataBindingShape; label: string }[] = [\n { value: \"collection\", label: \"The whole table\" },\n { value: \"reference\", label: \"One record\" },\n { value: \"value\", label: \"One field of a record\" },\n];\n\nexport const DATA_BINDING_MISSING: { value: DataBinding[\"missing\"]; label: string }[] = [\n { value: \"absent\", label: \"Say it's missing\" },\n { value: \"block\", label: \"Stop the run\" },\n];\n\n/** A fresh, empty whole-table binding. */\nexport function emptyDataBinding(): DataBinding {\n return {\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: \"collection\",\n table_id: \"\",\n missing: \"absent\",\n override_policy: \"shown_locked\",\n };\n}\n\n/** True when a value is a merge-field binding (the one shape this picker reads and writes). */\nexport function isDataBinding(value: unknown): value is DataBinding {\n return Boolean(value) && typeof value === \"object\" && (value as { kind?: unknown }).kind === \"merge_field\";\n}\n\n/** Ready to run only when the shape has everything it needs. */\nexport function isCompleteDataBinding(binding: DataBinding): boolean {\n if (!binding.table_id) return false;\n if (binding.semantic_type === \"collection\") return true;\n if (!binding.record_id) return false;\n return binding.semantic_type === \"value\" ? Boolean(binding.field_key) : true;\n}\n\n/** The placeholders one column offers; an entity reference offers its words and its id apart. */\nexport function bindingPlaceholdersFor(field: Field): { token: string; label: string }[] {\n const label = fieldName(field);\n if (isEntityReferenceConfig(field.config)) {\n return [\n { token: `{${field.key}.name}`, label: `${label} · name` },\n { token: `{${field.key}.id}`, label: `${label} · id` },\n ];\n }\n return [{ token: `{${field.key}}`, label }];\n}\n\nconst NAME_LIKE = /(^|_)(name|title|label)$/;\nconst DESCRIPTIVE = /(desc|description|summary|notes?|details?|about|why|purpose|role|category|type|group|status)/;\n\n/** The starting row template: the table's name column, then one or two describing columns. */\nexport function defaultBindingTemplate(table: Pick<Table, \"title_field\"> | null, fields: readonly Field[]): string {\n const first = fields[0];\n if (!first) return \"- {name}\";\n const declared = table?.title_field;\n const title =\n (declared ? fields.find((f) => f.key === declared || f.id === declared) : undefined) ??\n fields.find((f) => NAME_LIKE.test(f.key)) ??\n first;\n const token = (f: Field) => bindingPlaceholdersFor(f)[0]?.token ?? `{${f.key}}`;\n const rest = fields.filter((f) => f.id !== title.id);\n const [a, b] = [...rest.filter((f) => DESCRIPTIVE.test(f.key)), ...rest.filter((f) => !DESCRIPTIVE.test(f.key))];\n if (!a) return `- ${token(title)}`;\n return b ? `- ${token(title)}: ${token(a)} (${token(b)})` : `- ${token(title)}: ${token(a)}`;\n}\n\nexport interface DataBindingPickerProps {\n dataSource: RecordsDataSource;\n /** The signed-in person — every read runs as them. */\n userId: Uuid | null;\n binding: DataBinding;\n onChange: (binding: DataBinding) => void;\n disabled?: boolean;\n /** The host's starting row cap for a whole-table read (a knob the host reads), if any. */\n defaultRowLimit?: number | null;\n}\n\n/** \"From my data\": table → shape → record / field → template → when it's missing. */\nexport function DataBindingPicker({ dataSource, userId, binding, onChange, disabled, defaultRowLimit = null }: DataBindingPickerProps) {\n const tables = useTablesAnywhere(dataSource);\n const tableId = binding.table_id || null;\n const selectTable = (id: string) => {\n if (id === binding.table_id) return;\n onChange({\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: binding.semantic_type,\n table_id: id,\n missing: binding.missing,\n override_policy: \"shown_locked\",\n ...(binding.semantic_type === \"collection\" && defaultRowLimit ? { limit: defaultRowLimit } : {}),\n });\n };\n return (\n <div className=\"flex flex-col gap-2\">\n <TablePicker dataSource={dataSource} value={tableId} onChange={selectTable} disabled={Boolean(disabled)} tables={tables} />\n <TableScope dataSource={dataSource} userId={userId} tableId={tableId} tables={tables}>\n {tableId && (\n <BindingDetails\n tableId={tableId}\n binding={binding}\n onChange={onChange}\n disabled={disabled}\n defaultRowLimit={defaultRowLimit}\n />\n )}\n </TableScope>\n </div>\n );\n}\n\nfunction BindingDetails({\n tableId,\n binding,\n onChange,\n disabled,\n defaultRowLimit,\n}: {\n tableId: string;\n binding: DataBinding;\n onChange: (binding: DataBinding) => void;\n disabled?: boolean | undefined;\n defaultRowLimit: number | null;\n}) {\n const table = useTable(tableId);\n const fields = useFields(tableId);\n const fieldList = useMemo(() => fields.data ?? [], [fields.data]);\n const shape = binding.semantic_type;\n\n // PREFILL: a table or record read starts from the table's own name column + its next ones.\n useEffect(() => {\n if (disabled || shape === \"value\" || binding.transform || fields.loading || fieldList.length === 0) return;\n onChange({\n ...binding,\n transform: {\n name: \"list\",\n template: defaultBindingTemplate(table.data ?? null, fieldList),\n join: \"\\n\",\n ...(shape === \"collection\" && binding.limit !== undefined ? { max: binding.limit } : {}),\n },\n });\n }, [disabled, shape, binding, fields.loading, fieldList, table.data, onChange]);\n\n const selectShape = (next: DataBindingShape) => {\n if (next === shape) return;\n const base: DataBinding = {\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: next,\n table_id: binding.table_id,\n missing: binding.missing,\n override_policy: \"shown_locked\",\n };\n if (next !== \"collection\" && binding.record_id) base.record_id = binding.record_id;\n if (next === \"value\" && binding.field_key) base.field_key = binding.field_key;\n if (next === \"collection\") {\n const limit = binding.limit ?? defaultRowLimit;\n if (limit) base.limit = limit;\n }\n if (next !== \"value\" && binding.transform) {\n base.transform = {\n name: \"list\",\n template: binding.transform.template,\n ...(binding.transform.join !== undefined ? { join: binding.transform.join } : {}),\n ...(next === \"collection\" && base.limit !== undefined ? { max: base.limit } : {}),\n };\n }\n onChange(base);\n };\n\n const fieldOptions: CreatableOption[] = fieldList.map((f) => ({ value: f.key, label: fieldName(f) }));\n const template = binding.transform?.template ?? \"\";\n const setTemplate = (next: string) =>\n onChange({ ...binding, transform: { join: \"\\n\", ...binding.transform, name: \"list\", template: next } });\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap gap-1\" role=\"radiogroup\" aria-label=\"What to read\">\n {DATA_BINDING_SHAPES.map((s) => (\n <Button\n key={s.value}\n type=\"button\"\n size=\"sm\"\n variant={s.value === shape ? \"default\" : \"outline\"}\n role=\"radio\"\n aria-checked={s.value === shape}\n disabled={disabled}\n onClick={() => selectShape(s.value)}\n >\n {s.label}\n </Button>\n ))}\n </div>\n {shape !== \"collection\" && (\n <RecordPicker\n tableId={tableId}\n value={binding.record_id ?? null}\n onChange={(id) => onChange({ ...binding, record_id: id })}\n disabled={Boolean(disabled)}\n />\n )}\n {shape === \"value\" && (\n <CreatablePicker\n value={binding.field_key ?? null}\n options={fieldOptions}\n onSelect={(key) => onChange({ ...binding, field_key: key })}\n placeholder=\"Choose a column\"\n searchPlaceholder=\"Search columns\"\n noun=\"column\"\n loading={fields.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Column\"\n />\n )}\n {shape !== \"value\" && (\n <div className=\"flex flex-col gap-1\">\n <textarea\n className={cn(\n \"min-h-[3.5rem] w-full rounded-md border border-border bg-background px-2 py-1.5 font-mono text-xs\",\n )}\n aria-label=\"Each row reads as\"\n value={template}\n disabled={disabled}\n onChange={(e) => setTemplate(e.target.value)}\n />\n {!disabled && (\n <div className=\"flex flex-wrap gap-1\">\n {fieldList.flatMap(bindingPlaceholdersFor).map((p) => (\n <Button\n key={p.token}\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1.5 text-[11px]\"\n onClick={() => setTemplate(template + p.token)}\n >\n {p.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n )}\n {shape === \"collection\" && (\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n Up to\n <BasicInput\n type=\"number\"\n min={1}\n className=\"h-7 w-20 text-xs\"\n value={binding.limit ?? \"\"}\n disabled={disabled}\n onChange={(e) => {\n const n = Number.parseInt(e.target.value, 10);\n if (!Number.isFinite(n) || n < 1) return;\n onChange({ ...binding, limit: n, ...(binding.transform ? { transform: { ...binding.transform, max: n } } : {}) });\n }}\n />\n rows\n </label>\n )}\n <div className=\"flex flex-wrap items-center gap-1\" role=\"radiogroup\" aria-label=\"If nothing is found\">\n <span className=\"text-xs text-muted-foreground\">If nothing is found</span>\n {DATA_BINDING_MISSING.map((m) => (\n <Button\n key={m.value}\n type=\"button\"\n size=\"sm\"\n variant={m.value === binding.missing ? \"default\" : \"outline\"}\n role=\"radio\"\n aria-checked={m.value === binding.missing}\n disabled={disabled}\n onClick={() => onChange({ ...binding, missing: m.value })}\n >\n {m.label}\n </Button>\n ))}\n </div>\n </div>\n );\n}\n","\"use client\";\n\n// src/PickedSummaries.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// WHAT A PICKER CHOSE, READ BACK IN WORDS. A host that stores a table id, a record id or\n// `{column key: value}` (the workflow studio's step cards first) shows it as the table's name and\n// \"Stock status is Backordered\" — never the id, the key or the JSON. Each one reads through the\n// same doors the pickers use (`TablePickers.tsx`), and a value reads through the store's own\n// `renderValue`, so a choice shows its words, a relation its record's name.\n\nimport type { ReactNode } from \"react\";\nimport type { RecordsDataSource, Uuid } from \"@ai-matrx/records\";\nimport { useFields, useRecord, useTable } from \"@ai-matrx/records/react\";\nimport { RecordLabelProvider, useRecordLabels } from \"./labels\";\nimport { fieldName, recordName } from \"./names\";\nimport { TableScope, useTablesAnywhere } from \"./TablePickers\";\nimport { renderValue } from \"./values\";\n\n/** The chosen table's name, or `—` when it is not one this person can open. */\nexport function TableNameText({ dataSource, tableId }: { dataSource: RecordsDataSource; tableId: string | null }) {\n const tables = useTablesAnywhere(dataSource);\n if (!tableId) return <>—</>;\n if (tables.loading) return <>…</>;\n // A failed read says it failed — never \"—\", which reads as \"no table\".\n if (tables.error) return <>Couldn't load the table's name</>;\n return <>{tables.rows.find((t) => t.table_id === tableId)?.table_name ?? \"—\"}</>;\n}\n\n/** `{column key: value}` as \"Column is value, Other is value\" for one table. */\nexport function ColumnValuesText({\n dataSource,\n userId,\n tableId,\n value,\n}: {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n tableId: string | null;\n value: Record<string, unknown>;\n}) {\n if (!tableId) return <>—</>;\n return (\n <TableScope\n dataSource={dataSource}\n userId={userId}\n tableId={tableId}\n fallback={<>…</>}\n unavailable={<>Couldn't load this table's columns</>}\n >\n <RecordLabelProvider>\n <ColumnValuesWords tableId={tableId} value={value} />\n </RecordLabelProvider>\n </TableScope>\n );\n}\n\nfunction ColumnValuesWords({ tableId, value }: { tableId: string; value: Record<string, unknown> }) {\n const fields = useFields(tableId);\n // A choice is stored by its key; the label resolver reads it back as its words.\n const labels = useRecordLabels(fields.data ?? undefined);\n if (fields.loading) return <>…</>;\n // A failed read says it failed — never \"A removed column is —\", which lies about the table.\n if (fields.error) return <>Couldn't load this table's columns</>;\n const parts: ReactNode[] = [];\n for (const [key, stored] of Object.entries(value)) {\n // The store's own envelope keys (`_source`, `_values`, `_choices`…) ride on a record's\n // document; they are bookkeeping, never a column a person named.\n if (key.startsWith(\"_\")) continue;\n const field = (fields.data ?? []).find((f) => f.key === key);\n if (parts.length) parts.push(<span key={`${key}-sep`}>, </span>);\n parts.push(\n <span key={key}>\n {field ? fieldName(field) : \"A removed column\"} is {field ? renderValue(field, stored, undefined, labels) : \"—\"}\n </span>,\n );\n }\n return parts.length ? <>{parts}</> : <>—</>;\n}\n\n/** One record of a table, read back as its name. */\nexport function RecordNameText({\n dataSource,\n userId,\n tableId,\n recordId,\n}: {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n tableId: string | null;\n recordId: string | null;\n}) {\n if (!tableId || !recordId) return <>—</>;\n return (\n <TableScope\n dataSource={dataSource}\n userId={userId}\n tableId={tableId}\n fallback={<>…</>}\n unavailable={<>Couldn't load this record</>}\n >\n <RecordNameWords tableId={tableId} recordId={recordId} />\n </TableScope>\n );\n}\n\nfunction RecordNameWords({ tableId, recordId }: { tableId: string; recordId: string }) {\n const table = useTable(tableId);\n const record = useRecord(recordId);\n if (record.loading || table.loading) return <>…</>;\n if (record.error) return <>Couldn't load this record</>;\n if (!record.data) return <>A record you cannot open</>;\n return <>{recordName(record.data.document, table.data?.title_field ?? null)}</>;\n}\n","\"use client\";\n\n// src/values.tsx — @ai-matrx/records-ui\n//\n// HOW A VALUE IS SHOWN, one function, used by the grid cell, the peek, the\n// custom-fields section and the form's read state alike. Per SCR it is never\n// per-feature: every surface that shows a Value in this platform shows it the\n// same way, because the way is a property of the Field, not of the screen.\n//\n// VAL-2: a blank is never unexplained. When the record's envelope says why a\n// value is missing, the reason is what is shown — \"never asked\" and \"refused\"\n// are different facts and a person acts on them differently.\n\nimport { PersonChip } from \"./personChip\";\nimport { SWATCH_CLASS, formatColumnValue } from \"@ai-matrx/design-system/data-table\";\nimport { formatFieldValue, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { Field, HiddenFieldNotice, RecordDocument, ValueEnvelope } from \"@ai-matrx/records\";\nimport { WITHHELD_WORD, WithheldValue, withheldNoticeOf, withheldSentence } from \"./withheld\";\nimport { rowName } from \"./names\";\nimport { Badge, cn } from \"@ai-matrx/design-system\";\nimport { editorKindFor } from \"./parity\";\nimport { dateFormatFor, dateText, isDateField, systemStampOf } from \"./dates\";\nimport { useEmbeddedLook, type EmbeddedLook } from \"./embeddedLook\";\nimport { isId, useLabelWait, useRecordLabels, type LabelLookup } from \"./labels\";\nimport { ABSENCE_WORD_LABEL } from \"./enumLabels\";\nimport { entityReferenceText } from \"./EntityReferenceControl\";\nimport { wholeValueOf } from \"@ai-matrx/records/core\";\nimport { WholeValueCell } from \"./WholeValue\";\nimport { choiceChipLookOf } from \"./choiceLooks\";\nimport { formatPhone } from \"@ai-matrx/design-system/field-formats\";\nimport { FormattedValue, linkChipText } from \"./formattedValue\";\nimport { formatForField, shownAsOf } from \"./presentation\";\nimport { useRecordsUi } from \"./host\";\nimport { AttachmentChips } from \"./gridAttachments\";\nimport { KindValueCell, ReferenceChip, ReferenceChips, referencesOf } from \"./ReferenceChips\";\nimport { ClampedChips } from \"./ClampedChips\";\nimport { kindValueOf, kindValueWords } from \"./kindValues\";\nimport { formulaHasNothingToWorkOn, formulaSourceArchived } from \"./formulaNames\";\nimport { SignatureValue, isSignatureField, signatureWords } from \"./signature\";\nimport { newerKindWords, sourceArchivedOf, type SourceArchived } from \"@ai-matrx/records\";\nimport { newerKindValue, statusMarkOf } from \"./newerKindValues\";\nimport { KeptAsideValue, WorkedOutError, keptAsideFor, workedOutErrorFor } from \"./cellMarks\";\n\n/** A status choice's group mark (lane 10 P4), before its words on the chip. */\nfunction statusMark(field: Field, item: unknown, document?: RecordDocument) {\n const mark = statusMarkOf(field, item, document as Record<string, unknown> | undefined);\n return mark ? (\n <span aria-label={mark.words} title={mark.words} className=\"mr-1\" data-records-status-group={mark.group}>\n {mark.mark}\n </span>\n ) : null;\n}\n\n/** The envelope for one key, when the document carries one. */\nexport function envelopeFor(document: RecordDocument | undefined, key: string): ValueEnvelope | undefined {\n const block = document?._values as Record<string, ValueEnvelope> | undefined;\n return block?.[key];\n}\n/** The identifier a relation cell held before it moved, when its target no longer existed. */\nexport function unresolvedFor(document: RecordDocument | undefined, key: string): string | undefined {\n const sources = document?._sources as Record<string, { unresolved?: Record<string, unknown> }> | undefined;\n if (!sources || typeof sources !== \"object\") return undefined;\n for (const source of Object.values(sources)) {\n const held = source?.unresolved?.[key];\n if (typeof held === \"string\" && held) return held;\n if (Array.isArray(held) && held.length) return held.map(String).join(\", \");\n }\n return undefined;\n}\n\n/** A worked-out column that actually carries something to work out. */\nfunction hasFormula(field: Field): boolean {\n const config = (field.config ?? {}) as Record<string, unknown>;\n return Boolean(config.expr) || Boolean(String(config.formula_text ?? \"\").trim());\n}\n\n/**\n * WHY A WORKED-OUT COLUMN IS EMPTY, by its own kind and THIS record (lane VIEWS-AND-FIELDS W1-B\n * item 6) — the census of every column the store works out:\n * · a lookup reads from the record its link holds: no link → \"Pick a linked record\"; a link\n * whose value is empty → \"Empty on the linked record\";\n * · a rollup or a count works over the records its link holds: none → \"No linked records yet\";\n * some, with nothing worked out → a count reads its own 0, a total \"—\" (\"Nothing to add up\");\n * · a formula with no formula yet says so in words; with one, and the store's stamps, plain \"—\".\n * With no record to look at, a lookup or rollup is a plain \"—\" (never a guessed reason).\n * `words` replaces the dash; `sentence` is drawn in its place in italics; `why` is the tooltip.\n * `null`: not a worked-out column.\n */\nexport function computedEmptyOf(\n field: Field,\n document?: Record<string, unknown> | null,\n): { kind: \"lookup\" | \"rollup\" | \"count\" | \"formula\" | \"stamp\"; why?: string; sentence?: string; words?: string } | null {\n const kind = editorKindFor(field);\n const config = (field.config ?? {}) as Record<string, unknown>;\n if (kind === \"lookup\" || kind === \"rollup\") {\n const via = typeof config[\"via\"] === \"string\" ? config[\"via\"] : null;\n const held = document && via ? document[via] : undefined;\n const known = Boolean(document && via);\n const linked = !(held === null || held === undefined || held === \"\" || (Array.isArray(held) && held.length === 0));\n const count = kind === \"rollup\" && config[\"agg\"] === \"count\";\n const which = kind === \"lookup\" ? \"lookup\" : count ? \"count\" : \"rollup\";\n if (!known) return { kind: which };\n if (kind === \"lookup\") return { kind: which, why: linked ? \"Empty on the linked record\" : \"Pick a linked record\" };\n if (!linked) return { kind: which, why: \"No linked records yet\" };\n return count ? { kind: which, words: \"0\" } : { kind: which, why: \"Nothing to add up\" };\n }\n if (kind !== \"formula\" && field.type !== \"formula\") return null;\n if (typeof config[\"system\"] === \"string\") return { kind: \"stamp\" };\n if (!hasFormula(field)) return { kind: \"formula\", sentence: \"Worked out once its formula is in place\" };\n return { kind: \"formula\" };\n}\n\n/** The cell words for a lookup or roll-up whose source is archived (CHAIR-ROLLUP-HONEST). */\nexport const SOURCE_ARCHIVED_WORDS = \"Source archived\";\n\n/** What it is that was archived, for a tooltip: \"Patient on Appointments is archived\". */\nexport function sourceArchivedSentence(state: SourceArchived): string {\n if (!state.label) return \"A column it reads is archived\";\n return state.table ? `${state.label} on ${state.table} is archived` : `${state.label} is archived`;\n}\n\n/**\n * A LOOKUP OR ROLL-UP WHOSE SOURCE IS ARCHIVED (CHAIR-ROLLUP-HONEST, Law 4): the store answers a\n * typed state in the value's place (`sourceArchivedOf`), never a 0. The cell says so in two words\n * and names the archived column on hover; Column settings carries \"Bring back\".\n */\nexport function SourceArchivedValue({ state }: { state: SourceArchived }) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={sourceArchivedSentence(state)} data-records-source-archived={state.field_id ?? \"\"}>\n {SOURCE_ARCHIVED_WORDS}\n </span>\n );\n}\n\n// THE one map — see `enumLabels.ts`.\nexport const ABSENCE_WORDS: Record<string, string> = ABSENCE_WORD_LABEL;\n\nexport function renderValue(field: Field, value: unknown, document?: RecordDocument, labels?: LabelLookup, stillWaitingFor?: string | null, look?: EmbeddedLook | null) {\n const archivedSource = sourceArchivedOf(value);\n if (archivedSource) return <SourceArchivedValue state={archivedSource} />;\n const envelope = envelopeFor(document, field.key);\n if (envelope?.absent) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={`VAL-2: ${envelope.absent}`}>\n {ABSENCE_WORDS[String(envelope.absent)] ?? String(envelope.absent)}\n </span>\n );\n }\n if (value === null || value === undefined || value === \"\") {\n // VAL-2 AGAIN, FOR TWO BLANKS A DASH WOULD LIE ABOUT (VERIFIER-16, 2026-09-23).\n // A relation cell that pointed at a record which no longer exists moved EMPTY — the store\n // refuses a relation to nothing — and the id it held is kept on the record's own\n // provenance entry (`_sources.<ptr>.unresolved.<key>`). A dash there says \"nobody filled\n // this in\", which is false: somebody did, and what they chose is gone.\n const gone = unresolvedFor(document, field.key);\n if (gone) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={`It pointed at ${gone}`}>\n The record this pointed at no longer exists\n </span>\n );\n }\n // A FORMULA OVER A COLUMN WHOSE SOURCE IS ARCHIVED says so, never a blank (v7 item 7).\n const archivedInput = formulaSourceArchived(field, document as Record<string, unknown> | undefined);\n if (archivedInput) return <SourceArchivedValue state={archivedInput} />;\n // A WORKED-OUT COLUMN'S EMPTY STATE IS ITS OWN KIND'S (`computedEmptyOf`): a lookup is empty\n // because no linked record is picked, never because \"its formula\" is missing.\n const computed = computedEmptyOf(field, document as Record<string, unknown> | undefined);\n if (computed?.sentence) return <span className=\"text-xs italic text-muted-foreground\">{computed.sentence}</span>;\n if (computed?.words) return <span data-records-empty-why={computed.kind}>{computed.words}</span>;\n if (computed?.why) {\n return (\n <span className=\"text-muted-foreground\" title={computed.why} data-records-empty-why={computed.kind}>\n —\n </span>\n );\n }\n // EMBEDDED (`embeddedLook.ts`): a plain empty cell is blank, as Notion's is.\n if (look?.blankEmpty) return null;\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n // A SIGNATURE IS SEEN AS ITS DRAWING (or the signer's name a sealed document wrote), never as\n // the image's data text (`signature.tsx`).\n if (isSignatureField(field)) return <SignatureValue value={value} fieldKey={field.key} document={document} />;\n\n // THE NEWER KINDS (lane 10 P4) draw in their own shape (`newerKindValues.tsx`).\n const newer = newerKindValue(field, value);\n if (newer !== undefined) return newer;\n\n // A VALUE TOO BIG FOR ONE CELL: the words it keeps, and the way to the whole text (`WholeValue.tsx`).\n const whole = typeof value === \"string\" ? wholeValueOf(document, field.key) : null;\n if (whole) return <WholeValueCell words={value as string} pointer={whole} />;\n\n const kind = editorKindFor(field);\n // A REFERENCE IS A CHIP THAT OPENS WHAT IT NAMES (lane REFERENCE-CARRY): a relation's records and\n // an entity reference's platform things alike (`ReferenceChips.tsx`).\n if (kind === \"relation\" || kind === \"entity_reference\") {\n return <ReferenceChips refs={referencesOf(field, value, kind, labels)} waiting={stillWaitingFor} />;\n }\n // A VALUE THAT NAMES ITS OWN SHAPE — `__kind` JSON, or a Matrx directive stored before the Kind\n // Directives merge (```matrx {\"matrx_version\":1,…}```) — is drawn by the kind system, never as\n // the raw fence (Arman, Department table, 2026-09-28).\n // A PERSON IS A PERSON CHIP, never the link chip (`personChip.tsx`, night walk 2026-10-06).\n if (kind === \"member\") {\n const ids = (Array.isArray(value) ? value : [value]).filter((v) => v !== null && v !== undefined && v !== \"\");\n return (\n <span className=\"flex min-w-0 flex-wrap gap-1\" data-records-person-chips=\"\">\n {ids.map((id, i) => (\n <PersonChip key={`${String(id)}-${i}`} name={scalarText(field, id, labels, stillWaitingFor)} />\n ))}\n </span>\n );\n }\n const kv = kind === \"attachment\" ? null : kindValueOf(value);\n if (kv) return <KindValueCell kv={kv} where=\"cell\" title={field.label} />;\n // A CHOICE WEARS THE COLOUR ITS COLUMN KEEPS FOR IT (`choiceLooks.ts`) — never a colour hashed\n // from its word — as a chip whose words can be read in both themes (`CHOICE_CHIP_CLASS`, lane C,\n // review 2026-09-26: white words on pale fills measured ~1.1:1). A choice the column keeps no\n // colour for is a NEUTRAL chip, never bare text.\n const chosen = kind === \"select\" || kind === \"multi_select\";\n const chipOf = (item: unknown): { className: string; tinted: boolean; dot: string } => {\n const chipLook = choiceChipLookOf(field, item, scalarText(field, item, labels));\n return { className: chipLook.className, tinted: chipLook.color !== null, dot: SWATCH_CLASS[chipLook.color ?? \"gray\"] };\n };\n if (chosen) {\n const items = Array.isArray(value) ? value : [value];\n return (\n <span className=\"flex flex-wrap gap-1\" data-records-choice-chips=\"\">\n {items.map((item, i) => {\n const chip = chipOf(item);\n return (\n <Badge\n key={`${String(item)}-${i}`}\n variant=\"outline\"\n className={cn(\"text-[11px]\", chip.className)}\n data-records-choice-chip=\"\"\n {...(chip.tinted ? { \"data-records-choice-tint\": \"\" } : {})}\n >\n {look?.choiceDot ? <span aria-hidden=\"true\" data-matrx-pill-ink=\"\" data-records-choice-dot=\"\" className={cn(\"mr-1.5 inline-block size-1.5 shrink-0 rounded-full\", chip.dot)} /> : null}\n {statusMark(field, item, Array.isArray(value) ? undefined : document)}\n {scalarText(field, item, labels, Array.isArray(value) ? undefined : stillWaitingFor)}\n </Badge>\n );\n })}\n </span>\n );\n }\n // A FILE READS AS ITS NAME AND OPENS WHERE THE HOST KEEPS IT (`gridAttachments.tsx`).\n if (kind === \"attachment\") return <AttachmentChips value={value} />;\n if (Array.isArray(value)) {\n return (\n <span className=\"flex flex-wrap gap-1\">\n {value.map((item, i) => (\n <Badge key={`${String(item)}-${i}`} variant=\"secondary\" className=\"text-[11px]\">\n {scalarText(field, item, labels)}\n </Badge>\n ))}\n </span>\n );\n }\n if (kind === \"url\" && typeof value === \"string\") {\n // A LINK IS A CHIP NAMING WHERE IT GOES (lane C, review 2026-09-26 F1–F7: \"A URL column shows\n // raw image URLs\"): the site and the file, the whole address on hover. Airtable's link chip.\n const href = value.includes(\"://\") ? value : `https://${value}`;\n return (\n <a\n className=\"inline-flex min-w-0 max-w-full items-center gap-1 rounded-md border border-border bg-muted/60 px-1.5 py-0.5 text-[11px] text-foreground hover:bg-accent\"\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n title={value}\n data-records-link-chip=\"\"\n onClick={(event) => event.stopPropagation()}\n >\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">↗</span>\n <span className=\"truncate\">{linkChipText(value)}</span>\n </a>\n );\n }\n if (kind === \"phone\" && typeof value === \"string\" && value.trim() !== \"\") {\n return (\n <a\n className=\"truncate tabular-nums text-primary underline-offset-2 hover:underline\"\n href={`tel:${value.replace(/[^\\d+]/g, \"\")}`}\n title={value}\n data-records-phone=\"\"\n onClick={(event) => event.stopPropagation()}\n >\n {formatPhone(value)}\n </a>\n );\n }\n if (kind === \"email\" && typeof value === \"string\") {\n return (\n <a className=\"truncate text-primary underline-offset-2 hover:underline\" href={`mailto:${value}`}>\n {value}\n </a>\n );\n }\n if (typeof value === \"boolean\") {\n // LIMITS-FIX 2026-09-21: a tick box reads as a tick wherever it is only READ — a peek,\n // a portal, a form's answered state. The grid draws the real control instead, because\n // there a person expects to change it. (An UNANSWERED tick box never reaches here: it\n // has no value and left through the blank branch above, which is the third state.)\n return (\n <span className={kind === \"checkbox\" ? \"text-sm\" : \"\"} title={value ? \"Yes\" : \"No\"}>\n {value ? \"✓\" : \"—\"}\n </span>\n );\n }\n return <span className={cn(\"truncate\", kind === \"number\" || kind === \"currency\" || kind === \"percent\" ? \"tabular-nums\" : \"\")}>{scalarText(field, value, labels, stillWaitingFor)}</span>;\n}\n\n/**\n * The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1\n * says both change the MEANING — and with an id resolved to the NAME of the\n * record it points at.\n *\n * `labels` is the resolver from `RecordLabelProvider`. Without it, an id is\n * drawn as \"Loading…\" and never as itself: a 36-character identifier in a cell\n * reads like a value, and the 19 September verdict found it in choice cells,\n * relation cells and as every Kanban column heading.\n */\nexport function scalarText(\n field: Field,\n value: unknown,\n labels?: LabelLookup,\n /**\n * WHAT THIS COLUMN IS WAITING FOR, once it has been looking long enough to owe\n * a sentence (`useLabelWait`). \"Loading…\" is honest for a moment and a lie with\n * a spinner on it after that: VERIFIER-8 MEDIUM-1 watched a whole relation\n * column say it for 10-13 seconds while the rest of the grid sat readable\n * behind it, and nothing on screen said what it was waiting for.\n */\n stillWaitingFor?: string | null,\n): string {\n if (value === null || value === undefined) return \"—\";\n if (sourceArchivedOf(value)) return SOURCE_ARCHIVED_WORDS;\n // A drawn signature reads as \"Signed\" wherever only words fit (a card title, a sentence).\n if (isSignatureField(field)) return signatureWords(value) ?? \"—\";\n // The newer kinds' own words (lane 10 P4): an address on one line, h:mm, who by name, 3 / 5.\n const newerWords = newerKindWords(field, value);\n if (newerWords !== null) return newerWords;\n const kind = editorKindFor(field);\n // SC-R: a reference to a platform thing reads as the thing's own words (withheld ones said so).\n if (kind === \"entity_reference\") return entityReferenceText(value);\n // A many-relation reads as its records' names, never \"2 of them\" (lane REFERENCE-CARRY) — and a\n // SEVERAL-CHOICE value reads as its choices' words the same way (BREAKER-2 B2-19: a board grouped\n // by Body Areas titled one column \"1 of them\").\n if ((kind === \"relation\" || field.type === \"list\") && Array.isArray(value)) {\n return value.map((item) => scalarText(field, item, labels, stillWaitingFor)).join(\", \");\n }\n // A kind value in words: its items' own names, else what it is (`kindValues.ts`).\n const kv = kindValueOf(value);\n if (kv) return kindValueWords(kv);\n if (isId(value) && (field.type === \"list\" || field.type === \"relation\")) {\n return labels?.(field, String(value)) ?? stillWaitingFor ?? \"Loading…\";\n }\n // A CHOICE HELD BY ITS KEY reads as its option's words (DATA-V2-BASICS-2): the key never\n // reaches a person. Until the options are read the column's own \"Shows as\" answers below.\n if (field.type === \"list\" && typeof value === \"string\" && labels) {\n const words = labels(field, value);\n if (words) return words;\n }\n // A column's own \"Shows as\" (tranche 6e) words a card and a sentence the way the grid shows it.\n const shownAs = shownAsOf(field);\n if (shownAs) {\n const said = formatFieldValue(value, shownAs);\n if (said.ok && !said.empty) return said.text;\n }\n if (typeof value === \"number\") {\n if (kind === \"percent\") return `${value}%`;\n // The symbol goes in FRONT of an amount of money and a unit goes AFTER a\n // quantity: `$3` and `3 units`. Before this, `editorKindFor` called any\n // range field with a unit longer than one character a currency, so three\n // things measured in units rendered as \"units3\".\n if (kind === \"currency\") return field.unit ? `${field.unit}${value.toLocaleString()}` : value.toLocaleString();\n return field.unit ? `${value.toLocaleString()} ${field.unit}` : value.toLocaleString();\n }\n // A DATE IS READ BY THE ONE HELPER (`dates.ts`), the same registry the grid prints with:\n // a bare `2026-04-01` is April 1st in every zone, never UTC midnight moved to March 31st.\n // The store's own Created / Last changed stamps come through here too.\n if (kind === \"datetime\" || systemStampOf(field) === \"created_time\" || systemStampOf(field) === \"modified_time\") {\n const said = dateText(field, value);\n if (said !== null) return said;\n }\n // NEVER A JSON DUMP IN A CELL. A value with a shape a column cannot draw is\n // described; the raw document is available on the record panel, which is\n // where a person goes to look at it.\n if (Array.isArray(value)) return value.length === 0 ? \"\" : `${value.length} of them`;\n if (typeof value === \"object\") return \"…\";\n return String(value);\n}\n\n/** The provenance badge a value carries when the store interned a source for it (SCR-27). */\nexport function ProvenanceBadge({ document, fieldKey }: { document: RecordDocument | undefined; fieldKey: string }) {\n const envelope = envelopeFor(document, fieldKey);\n if (!envelope?.src) return null;\n // A value kept as a file: the cell already says so and opens it (WholeValue.tsx); its pointer's\n // raw fields are not a provenance a person reads.\n if (wholeValueOf(document, fieldKey)) return null;\n const sources = document?._sources as Record<string, Record<string, unknown>> | undefined;\n const source = sources?.[envelope.src];\n const label = source ? Object.values(source).map(String).join(\" · \") : envelope.src;\n return (\n <Badge variant=\"outline\" className=\"text-[10px] font-normal\" title={`Written by ${envelope.actor ?? \"?\"}${envelope.at ? ` at ${envelope.at}` : \"\"}`}>\n {label}\n </Badge>\n );\n}\n\n/**\n * THE VALUE, AS A COMPONENT, so a cell can resolve the ids it holds.\n *\n * `renderValue` is a plain function called from inside a column's `cell`\n * callback and from a dozen other places; a function cannot ask the resolver\n * for a name, because asking is a hook. Every read-only surface therefore draws\n * through this instead, and the one that needs the raw function (a plain-text\n * export, a chat line) keeps calling `renderValue` with no resolver and says\n * \"Loading…\" rather than printing an id.\n */\nexport function RecordValue({\n field,\n value,\n document,\n format,\n withheld,\n inCell,\n recordId,\n}: {\n field: Field;\n value: unknown;\n document?: RecordDocument | undefined;\n /**\n * WHOSE VALUE THIS IS. A drawn signature a form sent is kept as a File the value's source names,\n * and the read doors give the value without its source — so the signature reader asks for it by\n * the record (`signature.tsx`). Every other kind ignores it.\n */\n recordId?: string | null | undefined;\n /**\n * The column's DECLARED format (`presentation.ts`), when it has one.\n *\n * A cell renderer beats `MatrxColumnDef.format` — the table hands the cell to\n * the consumer and steps back — so a store column that declared `currency`\n * and then drew itself here would have shown a raw `1250.5` while its own\n * header was right-aligned for money. The primitive's formatter is asked for\n * the text instead of a second one being written beside it, so the read view\n * and the table can never disagree about what a number means. THE FALLBACK\n * LAW rides along: a value that does not fit is amber with the reason, never\n * blank.\n */\n format?: FieldFormatConfig | undefined;\n /**\n * THE STORE'S REASON, when it withheld this value from the reader (`ReadRow.hidden[key]`).\n * A withheld value reads \"Withheld\" with the store's sentence on hover — never \"—\", which\n * means the cell is empty (`withheld.tsx`).\n */\n withheld?: HiddenFieldNotice | null | undefined;\n /**\n * Drawn in a GRID CELL. In the merged grid a long-text cell reads through the host's text\n * renderer (`RecordsUiHost.renderText`, slot `cell` — markdown, formatted), clipped to the row;\n * unbound, the words as written.\n */\n inCell?: boolean | undefined;\n}) {\n const ui = useRecordsUi();\n const labels = useRecordLabels(ONE_FIELD_ARRAY_CACHE(field));\n // A CELL THAT IS STILL RESOLVING SAYS WHAT IT IS WAITING FOR — after one\n // second, not immediately: the word \"Loading…\" is honest for the moment it\n // takes, and a lie with a spinner on it after that.\n const stillWaitingFor = useLabelWait(field);\n const embeddedLook = useEmbeddedLook();\n if (withheld && (value === null || value === undefined)) return <WithheldValue field={field} notice={withheld} />;\n // A WORKED-OUT COLUMN THE STORE COULD NOT WORK OUT says so, with the store's sentence (`cellMarks.tsx`).\n if (value === null || value === undefined) {\n const failed = workedOutErrorFor(document, field.key);\n if (failed) return <WorkedOutError field={field} sentence={failed} floated={Boolean(inCell)} />;\n }\n // A VALUE KEPT ASIDE when its column changed stays where it was in a grid cell, amber, saying why.\n if (inCell) {\n const kept = keptAsideFor(document, field.key);\n if (kept) return <KeptAsideValue field={field} entry={kept} shown={scalarText(field, kept.value)} />;\n }\n const archivedSource = sourceArchivedOf(value);\n if (archivedSource) return <SourceArchivedValue state={archivedSource} />;\n // A WORKED-OUT COLUMN WITH NOTHING TO WORK ON IS EMPTY (review 2, A12): a new row's\n // `{Quote} * 1.08` is blank, never \"$0.00\" (`formulaNames.ts`).\n if (formulaHasNothingToWorkOn(field, document as Record<string, unknown> | undefined)) return embeddedLook?.blankEmpty ? null : <span className=\"text-muted-foreground\">—</span>;\n // THE NEWER KINDS (lane 10 P4) draw in their own shape in every layout (`newerKindValues.tsx`).\n if (value !== null && value !== undefined && value !== \"\" && !envelopeFor(document, field.key)?.absent) {\n const newer = newerKindValue(field, value, { inCell });\n if (newer !== undefined) return <>{newer}</>;\n }\n if (\n inCell &&\n ui.grid === \"merged\" &&\n ui.renderText &&\n typeof value === \"string\" &&\n value.trim() !== \"\" &&\n editorKindFor(field) === \"long_text\" &&\n !shownAsOf(field) &&\n !wholeValueOf(document, field.key) &&\n !envelopeFor(document, field.key)?.absent &&\n // A long-text cell holding a kind is drawn by the kind system below, not as markdown.\n !kindValueOf(value)\n ) {\n // ONE LINE, AT A FIXED HEIGHT (live walk 2026-10-07, \"Note from the client\": a saved three-line\n // note grew its row 35 → 67px, and the markdown placeholder → rendered swap moved it again,\n // 43 → 47). The row is 35px whatever the note holds; the whole text is the peek and the editor.\n return (\n <span className=\"block h-[1.5em] min-w-0 overflow-hidden whitespace-normal\" data-records-cell-text=\"\">\n {ui.renderText(value, \"cell\")}\n </span>\n );\n }\n // A DATE COLUMN PRINTS EACH VALUE IN ITS OWN SHAPE (`dates.ts`): a bare date is a date,\n // a moment is a date and time, whatever the column's kind says — so the grid, the form, the\n // panel and the calendar read one date the same way.\n // THE COLUMN'S OWN \"SHOWS AS\" WHEN THE CALLER NAMED NONE (merge tranche 6e): the record panel,\n // a card and a public page read the Field's format the way the grid does, so a percent kept as\n // 0.45 is 45% everywhere and a rating is stars everywhere.\n // A signature in a grid cell is drawn at the row's height.\n if (isSignatureField(field) && value !== null && value !== undefined && value !== \"\") {\n return <SignatureValue value={value} inCell={inCell} recordId={recordId} fieldKey={field.key} document={document} />;\n }\n // A LINK CELL IS ONE LINE: as many chips as fit, then \"+N\" that opens the whole list.\n if (inCell) {\n const linkKind = editorKindFor(field);\n if (linkKind === \"relation\" || linkKind === \"entity_reference\") {\n const refs = referencesOf(field, value, linkKind, labels);\n if (refs.length > 1) {\n return (\n <ClampedChips\n dataAttr={field.key}\n items={refs.map((r) => ({ key: `${r.token}:${r.id}`, node: <ReferenceChip reference={r} waiting={stillWaitingFor} /> }))}\n />\n );\n }\n }\n }\n const shown = format ?? formatForField(field);\n // THE VALUE'S OWN SHAPE (date or date-and-time) CHOSEN BY `dateFormatFor`, THE COLUMN'S OPTIONS KEPT\n // (`dateStyle: \"long\"` — \"January 1, 2026\"). Taking the shape alone dropped the options, so a long\n // date read medium in every layout.\n const shape = shown && (shown.id === \"date\" || shown.id === \"datetime\") && isDateField(field)\n ? dateFormatFor(field, value)\n : undefined;\n const dated: FieldFormatConfig | undefined = shape\n ? { ...shape, ...(shown?.options ? { options: shown.options } : {}) }\n : undefined;\n const formatted = shown ? formatColumnValue({ format: dated ?? shown }, value) : null;\n // EMBEDDED (`embeddedLook.tsx`): an empty value with a display format is as blank as an unformatted\n // one — it falls through to `renderValue`, which keeps every reason an empty cell may owe.\n if (formatted && !(embeddedLook?.blankEmpty && formatted.empty)) return <FormattedValue value={value} format={dated ?? shown!} />;\n return <>{renderValue(field, value, document, labels, stillWaitingFor, embeddedLook)}</>;\n}\n\n/**\n * `useRecordLabels` takes an array and declares what it is about to draw. A new\n * array literal per cell would re-declare on every render, so each Field gets\n * exactly one array for the life of the process.\n */\nconst ONE_FIELD_ARRAYS = new WeakMap<Field, Field[]>();\nfunction ONE_FIELD_ARRAY_CACHE(field: Field): Field[] {\n const held = ONE_FIELD_ARRAYS.get(field);\n if (held) return held;\n const made = [field];\n ONE_FIELD_ARRAYS.set(field, made);\n return made;\n}\n\n/**\n * WHAT ONE CARD SAYS — the kanban's, the calendar's, the gallery's and the pipeline's alike, so\n * no card can read a record differently from another. `field` is the card's title column\n * (`cardTitleField`); a value the store withheld reads \"Withheld\" and carries the store's reason\n * for the card's hover (`withheld.tsx`), never a bare \"—\".\n */\nexport function cardWords(\n record: { document?: RecordDocument | null; hidden?: Record<string, HiddenFieldNotice> | null } & Parameters<typeof rowName>[0],\n field: Field | undefined,\n labels?: LabelLookup,\n): { text: string; withheld: string | null } {\n if (!field) return { text: rowName(record, null, \"Untitled\"), withheld: null };\n const value = (record.document ?? {})[field.key];\n const notice = withheldNoticeOf(record.hidden, field.key);\n if (notice && (value === null || value === undefined)) {\n return { text: WITHHELD_WORD, withheld: withheldSentence(field, notice) };\n }\n return { text: scalarText(field, value, labels), withheld: null };\n}\n","\"use client\";\n\n// src/embeddedLook.tsx — @ai-matrx/records-ui · CHAIR-EMBEDDED-FIDELITY\n//\n// THE EMBEDDED TABLE'S LOOK, AS NAMED OPTIONS (never free-form styling). `TablePage\n// presentation=\"embedded\"` is the grid a page holds inline, measured against Notion's inline\n// database. Every difference from the full page is ONE option here, switched on by `Grid`\n// when `embedded` and read by the pieces that draw a value:\n//\n// · `blankEmpty` an empty cell is blank, not \"—\" (\"Withheld\" and a worked-out column's reason\n// words stay: they say something a dash would not).\n// · `choiceDot` a choice chip carries a small leading dot in its option's colour.\n// · `plainRelation` a relation cell reads like Notion's: the record's icon (else a page glyph)\n// then its title — no fill, no badge, no coloured underline; hover underlines.\n//\n// Row height and column dividers are classes on the table (`EMBEDDED_TABLE_CLASS`), drawn from\n// the design system's own tokens (`border-border`).\n\nimport { createContext, useContext } from \"react\";\n\nexport interface EmbeddedLook {\n blankEmpty: boolean;\n choiceDot: boolean;\n plainRelation: boolean;\n}\n\nexport const EMBEDDED_LOOK: EmbeddedLook = { blankEmpty: true, choiceDot: true, plainRelation: true };\n\nconst EmbeddedLookContext = createContext<EmbeddedLook | null>(null);\nexport const EmbeddedLookProvider = EmbeddedLookContext.Provider;\n/** The embedded look in force here, or `null` on a full page. */\nexport function useEmbeddedLook(): EmbeddedLook | null {\n return useContext(EmbeddedLookContext);\n}\n\n/**\n * Embedded rows are 40px tall with the value centred in them (as every grid cell is), and thin\n * vertical dividers sit between columns in the existing border token.\n */\nexport const EMBEDDED_TABLE_CLASS = [\n \"[&_tbody_td]:h-10\",\n \"[&_tbody_td]:align-middle!\",\n \"[&_tbody_td]:border-r\",\n \"[&_tbody_td]:border-border\",\n \"[&_tbody_td:last-child]:border-r-0\",\n \"[&_thead_th]:border-r\",\n \"[&_thead_th]:border-border\",\n \"[&_thead_th:last-child]:border-r-0\",\n].join(\" \");\n\n/** With no calculation chosen, the footer holds only the new-row line: no grey band, no rule above it. */\nexport const EMBEDDED_PLAIN_FOOTER_CLASS = \"[&_tfoot]:bg-transparent [&_tfoot]:border-t-0\";\n\n/**\n * HOW MANY ROWS AN EMBEDDED TABLE READS AT A TIME (CHAIR-EMBEDDED-FIDELITY 16): its first page, and\n * each \"Show more\" press brings about this many more — never the whole table. Declared beside the\n * server's first-page builder (`firstPage.ts`), which asks the same first page (lane SSR-ROWS).\n */\nexport { EMBEDDED_PAGE_SIZE } from \"./firstPage\";\n","// src/enumLabels.ts — @ai-matrx/records-ui\n//\n// ONE LABEL MAP PER ENUM. NOTHING ELSE IN THIS PACKAGE OWNS A COPY.\n//\n// Lane FRONT-DOOR's finding (2026-09-21): about twenty sites in this package\n// turned an enum VALUE the store already canonicalizes into a person-facing\n// word, each one on its own — worst example, `ChecklistRunner.tsx` called the\n// work-due state \"finished\" **\"Done\"** while `ActionInbox.tsx`, reading the\n// SAME `WorkDueState` off the SAME `custom.work_inbox`/`checklist_run` doors,\n// called it **\"Finished\"**. A person moving between a table's checklist tab\n// and her inbox saw two different words for one fact about her own work.\n//\n// So every enum this package draws a label for is named ONCE, here, keyed by\n// its canonical values — imported from `@ai-matrx/records` wherever the store\n// exports a named type/const for it, and named locally (with the reason) where\n// it does not. A panel imports the map; it never writes its own.\n//\n// THE GUARD: `enumLabels.test.tsx` renders every converted panel's label\n// function over the FULL canonical value list of its enum (pulled from\n// `@ai-matrx/records`, not retyped) and fails the moment a value has no entry\n// or a caller falls through to the raw token. See that file for RED/GREEN.\n\nimport type {\n ChecklistRequirementKind,\n ContextPolicy,\n FieldSensitivity,\n StageRuleOnFail,\n SubscriptionCadence,\n WorkDueState,\n WorkInboxKind,\n WorkApprovalState,\n} from \"@ai-matrx/records\";\n\n/**\n * An array literal checked, AT COMPILE TIME, to name every member of `T` and no\n * extra one. `WorkDueState`, `WorkInboxKind`, `ChecklistRequirementKind` and\n * `SubscriptionCadence` are typed unions in `@ai-matrx/records` with no\n * runtime array exported alongside them — so this is how the four `*_VALUES`\n * lists below stay tied to the PACKAGE'S OWN TYPE instead of drifting from it\n * by hand: add a sixth `WorkDueState` in `@ai-matrx/records` and `tsc` refuses\n * this file until the array is updated to name it too. The census test below\n * imports these arrays rather than the store's raw union so it is exercising\n * the same list this file's label maps are keyed against.\n */\nfunction exhaustiveValuesOf<T extends string>() {\n return function <const U extends readonly T[]>(values: [T] extends [U[number]] ? U : never): U {\n return values as U;\n };\n}\n\n// ── work due state — WorkDueState (packages/records/src/work.ts) ───────────\n//\n// Shared by a checklist step (`checklist_run().due_state`) and a work-inbox\n// row (`work_inbox().due_state`, `work_list().due_state`) — ONE enum, drawn in\n// both a checklist runner and an approvals inbox. This is the pair the finding\n// named: \"finished\" read \"Done\" in one and \"Finished\" in the other. **\"Done\"\n// wins** — it is the word a non-technical business owner actually says out\n// loud about a piece of work (\"is that job done yet?\"), it is one syllable\n// shorter than the other four words in this set are used to being read\n// alongside (\"Overdue\", \"Today\", \"Scheduled\", \"No date\"), and \"Finished\" reads\n// more like a formal status report than a plain answer to \"is it done\".\nexport const WORK_DUE_STATES = exhaustiveValuesOf<WorkDueState>()([\n \"overdue\",\n \"due_today\",\n \"scheduled\",\n \"undated\",\n \"finished\",\n]);\nexport const DUE_STATE_LABEL: Record<WorkDueState, string> = {\n overdue: \"Overdue\",\n due_today: \"Today\",\n scheduled: \"Scheduled\",\n undated: \"No date\",\n finished: \"Done\",\n};\n\n// ── work inbox kind — WorkInboxKind (packages/records/src/work.ts) ─────────\nexport const WORK_INBOX_KINDS = exhaustiveValuesOf<WorkInboxKind>()([\"assignment\", \"approval\", \"proposal\"]);\n// UI-FIX-19 (VERIFIER-19 #6): a kind is a NOUN. \"Approve\" in the row's bordered kind badge read as\n// a live Approve control on every withdrawn and decided item; only a control may be a verb.\nexport const WORK_INBOX_KIND_LABEL: Record<WorkInboxKind, string> = {\n assignment: \"Assigned\",\n approval: \"Approval\",\n proposal: \"Agent proposal\",\n};\n/** The heading an inbox grouped by kind reads (lane S5-PRIME) — plural, the way Linear groups. */\nexport const WORK_INBOX_KIND_GROUP_LABEL: Record<WorkInboxKind, string> = {\n approval: \"Approvals\",\n proposal: \"Agent proposals\",\n assignment: \"Assigned to you\",\n};\n\n// ── approval state — WorkApprovalState (packages/records/src/work.ts) ──────\n// Lane S5-PRIME: a closed item says what happened to it. `withdrawn` is the store's own close —\n// the thing it would change was archived — never a person's decision.\nexport const WORK_APPROVAL_STATES = exhaustiveValuesOf<WorkApprovalState>()([\"pending\", \"approved\", \"declined\", \"withdrawn\"]);\nexport const WORK_APPROVAL_STATE_LABEL: Record<WorkApprovalState, string> = {\n pending: \"Waiting\",\n approved: \"Approved\",\n declined: \"Declined\",\n withdrawn: \"Withdrawn\",\n};\n\n// ── checklist requirement kind — ChecklistRequirementKind (checklist.ts) ───\nexport const CHECKLIST_REQUIREMENT_KINDS = exhaustiveValuesOf<ChecklistRequirementKind>()([\n \"none\",\n \"note\",\n \"answer\",\n \"record_field\",\n \"form\",\n \"document\",\n]);\nexport const CHECKLIST_REQUIREMENT_LABEL: Record<ChecklistRequirementKind, string> = {\n none: \"\",\n note: \"Say what you did\",\n answer: \"Fill this in\",\n record_field: \"This has to be filled in on the record\",\n form: \"This step is a form\",\n document: \"This step is a document\",\n};\n\n// ── field sensitivity — FieldSensitivity (vocabulary.ts, FLD-12/AGT-7) ─────\nexport const FIELD_SENSITIVITY_LABEL: Record<FieldSensitivity, string> = {\n public: \"Anyone who can open the record\",\n internal: \"People in this organization\",\n confidential: \"People who have been given the record\",\n restricted: \"Owners and administrators only\",\n};\n\n// ── context policy — ContextPolicy (vocabulary.ts, FLD-12) ─────────────────\n// Whether an agent may see a Field's values at all — not `Delivery` (how much\n// of a merge field's value reaches a turn), a different vocabulary entirely.\nexport const CONTEXT_POLICY_LABEL: Record<ContextPolicy, string> = {\n include: \"Yes, an assistant can read it\",\n summarize: \"Only a summary of it\",\n on_request: \"Only when somebody asks for it\",\n exclude: \"No, keep it away from assistants\",\n};\n\n// ── stage-rule on_fail — StageRuleOnFail (pipeline.ts) ──────────────────────\nexport const STAGE_RULE_ON_FAIL_LABEL: Record<StageRuleOnFail, string> = {\n refuse: \"Turn it away\",\n require_approval: \"Ask for approval\",\n};\n\n// ── subscription cadence — SubscriptionCadence (subscription.ts) ───────────\n//\n// `DigestScheduler.tsx` carries its own copy of this enum's words as a\n// grammatical FRAGMENT dropped into a sentence (\"arrives the moment something\n// arrives\") rather than a standalone label (\"hourly summary\") — a different\n// job for the same four values. That file is owned by another lane right now\n// (lane preamble's do-not-touch list) so it is left exactly as it is; this map\n// is the standalone-label form used by every OTHER site that names a cadence.\nexport const SUBSCRIPTION_CADENCES = exhaustiveValuesOf<SubscriptionCadence>()([\"instant\", \"hourly\", \"daily\", \"weekly\"]);\nexport const SUBSCRIPTION_CADENCE_LABEL: Record<SubscriptionCadence, string> = {\n instant: \"as it happens\",\n hourly: \"hourly summary\",\n daily: \"daily summary\",\n weekly: \"weekly summary\",\n};\n\n// ── subscription channel — no named export in @ai-matrx/records ───────────\n//\n// `Subscription.channel` is typed inline as `\"in_app\" | \"email\" | \"sms\"`\n// (subscription.ts) with no exported const array, so the value list below IS\n// the canonical list — the same three literals the store's type carries.\nexport const SUBSCRIPTION_CHANNEL_VALUES = [\"in_app\", \"email\", \"sms\"] as const;\nexport type SubscriptionChannel = (typeof SUBSCRIPTION_CHANNEL_VALUES)[number];\n// `NotifyRuleEditor.tsx` used to say plain \"by email\" / \"by text\" with no\n// caveat; `SubscriptionsPanel.tsx` (and the untouched `DigestScheduler.tsx`)\n// say \"only if an address/number is on the account\". **The caveat wins** — a\n// person choosing email delivery needs to know up front that it silently does\n// nothing without an address on file, the way Linear and Notion surface a\n// precondition next to the control rather than failing quietly later.\nexport const SUBSCRIPTION_CHANNEL_LABEL: Record<SubscriptionChannel, string> = {\n in_app: \"in the app\",\n email: \"by email — only if an address is on the account\",\n sms: \"by text — only if a number is on the account\",\n};\n\n// ── rollup aggregate operation — NewFieldDeclaration[\"agg\"] (field.ts) ─────\n//\n// `field.ts` types this inline (`agg?: \"sum\" | \"count\" | \"min\" | \"max\" |\n// \"avg\"`) with no exported const array, so — same as the channel above — the\n// list below IS the canonical list.\nexport const ROLLUP_AGG_VALUES = [\"count\", \"sum\", \"avg\", \"min\", \"max\"] as const;\nexport type RollupAgg = (typeof ROLLUP_AGG_VALUES)[number];\nexport const ROLLUP_AGG_LABEL: Record<RollupAgg, string> = {\n count: \"How many there are\",\n sum: \"The total of\",\n avg: \"The average of\",\n min: \"The smallest\",\n max: \"The largest\",\n};\n\n// ── formula operation — the FormulaOperations menu (FieldEditor.tsx) ───────\n//\n// No `@ai-matrx/records` type names this set at all; it is this package's own\n// menu of what a two-column formula field can do, so this file is its one\n// canonical home.\nexport const FORMULA_OP_VALUES = [\"concat\", \"add\", \"sub\", \"mul\", \"div\"] as const;\nexport type FormulaOp = (typeof FORMULA_OP_VALUES)[number];\nexport const FORMULA_OP_LABEL: Record<FormulaOp, string> = {\n concat: \"Join them together\",\n add: \"Add them up\",\n sub: \"Take the second from the first\",\n mul: \"Multiply them\",\n div: \"Divide the first by the second\",\n};\n/** Whether this operation reads naturally as \"X and Y and Z…\" over more than two columns. */\nexport const FORMULA_OP_JOINS: Record<FormulaOp, boolean> = {\n concat: true,\n add: true,\n sub: false,\n mul: true,\n div: false,\n};\n\n// ── field validation-rule kind — FieldRule[\"kind\"] (field.ts) ──────────────\n//\n// `field.ts` types this inline with no exported const array; canonical here.\nexport const FIELD_RULE_KIND_VALUES = [\"min\", \"max\", \"length\", \"pattern\", \"equals_field\", \"differs_from_field\"] as const;\nexport type FieldRuleKindValue = (typeof FIELD_RULE_KIND_VALUES)[number];\nexport const FIELD_RULE_KIND_LABEL: Record<FieldRuleKindValue, string> = {\n min: \"At least\",\n max: \"At most\",\n length: \"Number of characters\",\n pattern: \"Looks like\",\n equals_field: \"Same as the column\",\n differs_from_field: \"Different from the column\",\n};\n\n// ── proposed-change act — `ProposedChange[\"act\"]` (ProposalRow.tsx, package-local) ──\n//\n// This type is not in `@ai-matrx/records` (`ProposalRow.tsx` declares it\n// itself, for an agent's field/table proposal), so it is canonical here.\nexport const PROPOSED_CHANGE_ACT_VALUES = [\"add\", \"update\", \"remove\"] as const;\nexport type ProposedChangeAct = (typeof PROPOSED_CHANGE_ACT_VALUES)[number];\nexport const PROPOSED_CHANGE_ACT_LABEL: Record<ProposedChangeAct, string> = {\n add: \"Add\",\n update: \"Update\",\n remove: \"Remove\",\n};\n\n// ── booking-page state — `FormSummary[\"state\"]` / `BookingSummary` (rule.ts) ──\n//\n// `rule.ts` types this inline (`\"draft\" | \"open\" | \"closed\" | \"full\"`) with no\n// exported const array; canonical here.\nexport const BOOKING_PAGE_STATE_VALUES = [\"draft\", \"open\", \"closed\", \"full\"] as const;\nexport type BookingPageState = (typeof BOOKING_PAGE_STATE_VALUES)[number];\nexport const BOOKING_PAGE_STATE_LABEL: Record<BookingPageState, string> = {\n draft: \"Not open yet — nobody can book until you open it.\",\n open: \"Open. Anyone with the link can book a time.\",\n closed: \"Closed. The link still works and says you are not taking bookings.\",\n full: \"Every time you offered is taken.\",\n};\n\n// ── value-envelope absence word — `ValueEnvelope.absent` (record.ts) ───────\n//\n// Kept for completeness of the census: `values.tsx` mapped each absence word\n// to itself (`\"none\" → \"none\"`), which is a passthrough with a safe fallback\n// rather than a wording decision, so there is no conflict to resolve — this is\n// still its one home so a future word change happens in one place.\nexport const ABSENCE_WORD_VALUES = [\"never asked\", \"none\", \"refused\", \"conflicting\"] as const;\nexport type AbsenceWord = (typeof ABSENCE_WORD_VALUES)[number];\nexport const ABSENCE_WORD_LABEL: Record<AbsenceWord, string> = {\n \"never asked\": \"never asked\",\n none: \"none\",\n refused: \"refused\",\n conflicting: \"conflicting\",\n};\n","\"use client\";\n\n// src/WholeValue.tsx — @ai-matrx/records-ui\n//\n// A VALUE TOO BIG FOR ONE CELL, SHOWN HONESTLY. The store keeps the whole text as a file and the\n// cell holds its first words (`@ai-matrx/records/core` `wholeValueOf`). A cell that drew only the\n// words would pass the start of a 700 KB research text off as the whole value; so it draws the\n// words, then says how big the whole text is and opens it — through the host's page for files\n// (`hrefForFile`). Unbound, it says the whole text is kept as a file this screen cannot open:\n// absent or honest, never a dead link.\n\nimport { useEffect, useState } from \"react\";\nimport type { Field, Uuid } from \"@ai-matrx/records\";\nimport { wholeValueSize, type WholeValuePointer } from \"@ai-matrx/records/core\";\nimport { BasicTextarea } from \"@ai-matrx/design-system\";\nimport { useRecordsUi } from \"./host\";\nimport { fieldName } from \"./names\";\n\nexport const WHOLE_VALUE_UNBOUND =\n \"The whole text is kept as a file, and this screen has no way to open files yet.\";\n\nexport function wholeValueLine(pointer: WholeValuePointer): string {\n return `Open the whole text (${wholeValueSize(pointer)})`;\n}\n\nexport function WholeValueCell({ words, pointer }: { words: string; pointer: WholeValuePointer }) {\n const host = useRecordsUi();\n const href = host.hrefForFile?.({ fileId: pointer.file_id as Uuid });\n const line = wholeValueLine(pointer);\n return (\n <span className=\"flex min-w-0 items-baseline gap-2\" data-whole-value-file={pointer.file_id}>\n <span className=\"truncate\" title={`The first ${pointer.shown_chars} of ${pointer.chars} characters`}>\n {words}…\n </span>\n {href ? (\n host.Link ? (\n host.Link({ href, children: line, className: \"shrink-0 text-xs text-primary underline-offset-2 hover:underline\" })\n ) : (\n <a className=\"shrink-0 text-xs text-primary underline-offset-2 hover:underline\" href={href} target=\"_blank\" rel=\"noreferrer\">\n {line}\n </a>\n )\n ) : (\n <span className=\"shrink-0 text-xs italic text-muted-foreground\" title={WHOLE_VALUE_UNBOUND}>\n {`${wholeValueSize(pointer)} in a file`}\n </span>\n )}\n </span>\n );\n}\n\n// ── EDITING A TEXT KEPT AS A FILE (lane BIG-VALUES-WRITE, 2026-09-25) ─────────────────────────\n//\n// A text of any size simply saves: the store keeps the first 1000 characters in the cell and the\n// whole text as a file, behind the scenes. So an editor must never start from those 1000\n// characters — saving them would replace the whole text with its start. It opens the WHOLE text\n// (the host's `readFileText`), and a save writes the whole edited text; the store files it again as\n// the next version. A host that cannot read files gets the words and the link, never an editor\n// that would cut the value.\n\nexport const WHOLE_VALUE_NOT_EDITABLE_HERE =\n \"The whole text is kept as a file. Open it to read it; this screen cannot load it to edit.\";\n\n/** The sentence a person reads while the whole text is being opened. */\nexport function wholeValueOpening(pointer: WholeValuePointer): string {\n return `Opening the whole text (${wholeValueSize(pointer)})…`;\n}\n\nexport type WholeText =\n | { state: \"loading\" }\n | { state: \"ready\"; text: string }\n | { state: \"failed\"; why: string }\n | { state: \"unbound\" };\n\n/** The whole text behind a pointer, read once through the host. */\nexport function useWholeText(pointer: WholeValuePointer | null): WholeText {\n const host = useRecordsUi();\n const read = host.readFileText;\n const fileId = pointer?.file_id ?? null;\n const [answer, setAnswer] = useState<WholeText>({ state: \"loading\" });\n useEffect(() => {\n if (!fileId) return;\n if (!read) {\n setAnswer({ state: \"unbound\" });\n return;\n }\n let live = true;\n setAnswer({ state: \"loading\" });\n read({ fileId: fileId as Uuid }).then(\n (text) => live && setAnswer({ state: \"ready\", text }),\n (thrown: unknown) =>\n live && setAnswer({ state: \"failed\", why: thrown instanceof Error ? thrown.message : String(thrown) }),\n );\n return () => {\n live = false;\n };\n }, [fileId, read]);\n return answer;\n}\n\n/**\n * THE RECORD FORM'S EDITOR FOR A TEXT KEPT AS A FILE. `value` is what the form holds: the stored\n * words until the person types, then what they typed. Until they type, the box shows the whole text\n * read from the file — so nothing is marked changed by opening it.\n */\nexport function WholeValueEditor({\n field,\n pointer,\n words,\n value,\n onChange,\n id,\n disabled,\n}: {\n field: Field;\n pointer: WholeValuePointer;\n words: string;\n value: unknown;\n onChange: (value: unknown) => void;\n id: string;\n disabled?: boolean;\n}) {\n const whole = useWholeText(pointer);\n const touched = typeof value === \"string\" ? value !== words : value !== null && value !== undefined;\n if (touched) {\n return (\n <BasicTextarea\n id={id}\n rows={12}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n data-whole-value-editor={pointer.file_id}\n />\n );\n }\n if (whole.state === \"ready\") {\n return (\n <BasicTextarea\n id={id}\n rows={12}\n value={whole.text}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n data-whole-value-editor={pointer.file_id}\n aria-label={fieldName(field)}\n />\n );\n }\n return (\n <div id={id} className=\"flex flex-col gap-1 rounded border px-2 py-1.5 text-sm\">\n <WholeValueCell words={words} pointer={pointer} />\n <span className=\"text-xs text-muted-foreground\">\n {whole.state === \"loading\"\n ? wholeValueOpening(pointer)\n : whole.state === \"failed\"\n ? `The whole text could not be opened to edit (${whole.why}). Open it to read it.`\n : WHOLE_VALUE_NOT_EDITABLE_HERE}\n </span>\n </div>\n );\n}\n","\"use client\";\n\n// src/ReferenceChips.tsx — @ai-matrx/records-ui · lane REFERENCE-CARRY\n//\n// A REFERENCE IS A CHIP THAT OPENS WHAT IT NAMES — wherever a value is read (grid cell, peek, record\n// panel, card). Two store declarations carry a reference (PROGRESS-REFERENCE-CARRY §D.1): a\n// `relation` Field holds record ids of one Table, an entity reference holds `{token, id}` of any\n// platform thing. A person sees ONE thing — a chip with the thing's own words — and the host's\n// `renderReference` port makes it a door (route, new tab, peek). Before this a relation cell drew\n// grey text badges that opened nothing, and a many-relation read \"2 of them\".\n//\n// Also here: `KindValueCell`, a cell whose value names its own shape (`kindValues.ts`), drawn by the\n// host's kind system (`renderKind`) — never the raw ```matrx fence.\n\nimport type { ReactNode } from \"react\";\nimport { entityRefsOf, type Field } from \"@ai-matrx/records\";\nimport { Badge, Skeleton, cn } from \"@ai-matrx/design-system\";\nimport { useRecordsUi, type ReferenceChipRef } from \"./host\";\nimport { isId, type LabelLookup } from \"./labels\";\nimport { WITHHELD_ENTITY_LABEL } from \"./EntityReferenceControl\";\nimport { useEmbeddedLook } from \"./embeddedLook\";\nimport { kindItemWords, kindLabel, kindValueWords, type KindValue } from \"./kindValues\";\n\n/**\n * NOTION'S ORDER: the related record's own icon, else its table's, else (the chip's) page glyph. Only\n * a drawable GLYPH counts — an emoji or short symbol; a table's icon kept as an icon NAME\n * (\"graduation-cap\") is not a glyph and falls through to the next.\n */\nexport function glyphOf(icon: string | null | undefined): string | null {\n const text = (icon ?? \"\").trim();\n return text !== \"\" && text.length <= 8 && /[^\\u0000-\\u007f]/.test(text) ? text : null;\n}\n/** The icon an icon-NAME is kept as (\"Briefcase\"): a word a host's `renderIcon` may draw. */\nfunction nameOf(icon: string | null | undefined): string | null {\n const text = (icon ?? \"\").trim();\n return /^[A-Za-z][A-Za-z0-9_-]{1,40}$/.test(text) ? text : null;\n}\nfunction iconOf(pair: { icon: string | null; tableIcon: string | null } | undefined): { icon?: string } {\n // The record's own icon first, whichever way it is kept; then its table's.\n const own = glyphOf(pair?.icon) ?? nameOf(pair?.icon);\n const table = glyphOf(pair?.tableIcon) ?? nameOf(pair?.tableIcon);\n const chosen = own ?? table;\n return chosen ? { icon: chosen } : {};\n}\n\n/** The references a relation or entity-reference value names, in the order it holds them. */\nexport function referencesOf(field: Field, value: unknown, kind: string, labels?: LabelLookup): ReferenceChipRef[] {\n if (kind === \"entity_reference\") {\n return entityRefsOf(value).map((r) => ({ token: r.token, id: r.id, label: r.label }));\n }\n const ids = (Array.isArray(value) ? value : [value]).filter(isId).map(String);\n const tableId = typeof field.relation_target === \"string\" ? field.relation_target : undefined;\n return ids.map((id) => ({\n token: \"record\",\n id,\n label: labels?.(field, id) ?? null,\n tableId,\n ...iconOf(labels?.icons?.(field, id)),\n ...(labels?.archived?.(field, id) ? { archived: true } : {}),\n }));\n}\n\n/** The word an archived reference wears, and its one-sentence tooltip. */\nexport const ARCHIVED_REFERENCE_WORD = \"Archived\";\nexport const ARCHIVED_REFERENCE_TIP = \"In the Archived view; restore it to use it again\";\n\n/** A plain page glyph (Lucide file-text geometry), for a related record that has no icon. */\nfunction PageGlyph() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width={14} height={14} fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" data-records-page-glyph=\"\">\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n <path d=\"M10 13H8\" /><path d=\"M16 17H8\" />\n </svg>\n );\n}\n\n/** One chip. The host's door when it has one; otherwise the words, and nothing that looks openable. */\nexport function ReferenceChip({ reference, waiting }: { reference: ReferenceChipRef; waiting?: string | null | undefined }) {\n const host = useRecordsUi();\n const look = useEmbeddedLook();\n // A NAME ON ITS WAY IS A PULSE INSIDE THE CHIP, never the word \"Loading…\" in a capsule\n // (STABLE-TABLES, night walk 2026-10-06): the chip and its door are there; the name lands in the\n // box the placeholder held.\n const pending = reference.label == null && reference.token === \"record\" && !waiting && !host.renderReference;\n const pendingMark = <Skeleton aria-label=\"Loading\" data-records-reference-pending=\"\" className=\"inline-block h-3 w-16 shrink-0 rounded-sm align-middle\" />;\n const words = reference.label ?? (reference.token === \"record\" ? (waiting ?? \"Loading…\") : WITHHELD_ENTITY_LABEL);\n const drawn: ReactNode = host.renderReference ? host.renderReference({ ...reference, label: reference.label ?? words }) : null;\n // EMBEDDED (`embeddedLook.tsx` `plainRelation`): Notion's relation — icon, then title, nothing else.\n if (look?.plainRelation) {\n return (\n <span\n className={cn(\n \"inline-flex max-w-full min-w-0 items-center gap-1.5 text-sm text-foreground hover:underline [&_a]:text-inherit [&_a]:no-underline [&_a:hover]:underline\",\n reference.archived && \"opacity-70\",\n )}\n data-records-reference-chip={reference.token}\n data-records-reference-plain=\"\"\n data-records-reference-archived={reference.archived ? \"\" : undefined}\n title={reference.archived ? ARCHIVED_REFERENCE_TIP : words}\n >\n <span aria-hidden=\"true\" data-records-reference-icon=\"\" className=\"inline-flex size-4 shrink-0 items-center justify-center text-muted-foreground\">\n {glyphOf(reference.icon) ? <span className=\"text-sm leading-none\">{reference.icon}</span> : (reference.icon && host.renderIcon?.(reference.icon)) || <PageGlyph />}\n </span>\n {drawn ?? (pending ? pendingMark : <span className=\"truncate\">{words}</span>)}\n {reference.archived ? <span className=\"shrink-0 text-muted-foreground\">{ARCHIVED_REFERENCE_WORD}</span> : null}\n </span>\n );\n }\n // AN ARCHIVED RECORD IS STILL NAMED (chair ruling B3-21): the chip keeps its words and door, is\n // drawn muted, and says \"Archived\" — state, not prose. Restoring it brings the plain chip back.\n return (\n <Badge\n variant=\"secondary\"\n className={cn(\n \"max-w-full min-w-0 gap-1 px-1.5 py-0 text-[11px] font-normal\",\n reference.archived && \"opacity-70\",\n )}\n data-records-reference-chip={reference.token}\n data-records-reference-archived={reference.archived ? \"\" : undefined}\n title={reference.archived ? ARCHIVED_REFERENCE_TIP : words}\n >\n {drawn ?? (pending ? pendingMark : <span className=\"truncate\">{words}</span>)}\n {reference.archived ? <span className=\"shrink-0 text-muted-foreground\">{ARCHIVED_REFERENCE_WORD}</span> : null}\n </Badge>\n );\n}\n\n/** Every reference a value holds, as chips (a dash when it holds none). */\nexport function ReferenceChips({ refs, waiting }: { refs: ReferenceChipRef[]; waiting?: string | null | undefined }) {\n if (refs.length === 0) return <span className=\"text-muted-foreground\">—</span>;\n return (\n <span className=\"flex min-w-0 flex-wrap gap-1\" data-records-reference-chips=\"\">\n {refs.map((r) => (\n <ReferenceChip key={`${r.token}:${r.id}`} reference={r} waiting={waiting} />\n ))}\n </span>\n );\n}\n\n/**\n * A CELL HOLDING A KIND. The host's kind system draws it (`renderKind`): a reference directive as\n * chips, any other kind as a compact button that opens the real view. Unbound, a neutral chip names\n * what it is and the raw text is one hover away.\n */\nexport function KindValueCell({\n kv,\n where,\n title,\n}: {\n kv: KindValue;\n where: \"cell\" | \"panel\";\n title: string;\n}) {\n const host = useRecordsUi();\n if (host.renderKind) {\n return <span className=\"flex min-w-0 max-w-full items-center\" data-records-kind-value={kv.kind}>{host.renderKind({ value: kv.value, kind: kv.kind, where, title })}</span>;\n }\n const named = kv.items.map(kindItemWords).filter((w): w is string => w !== null);\n return (\n <span className={cn(\"flex min-w-0 flex-wrap gap-1\")} data-records-kind-value={kv.kind} title={JSON.stringify(kv.value)}>\n {named.length > 0 ? (\n named.map((w, i) => (\n <Badge key={`${w}-${i}`} variant=\"secondary\" className=\"px-1.5 py-0 text-[11px] font-normal\">\n {w}\n </Badge>\n ))\n ) : (\n <Badge variant=\"outline\" className=\"px-1.5 py-0 text-[11px] font-normal\">\n {kindLabel(kv.kind)}\n </Badge>\n )}\n </span>\n );\n}\n\nexport { kindValueWords };\n","// src/kindValues.ts — @ai-matrx/records-ui · lane REFERENCE-CARRY\n//\n// A CELL THAT HOLDS A KIND. A value is a kind value when it names its own shape — `__kind` — or\n// when it is a stored Matrx directive written before the Kind Directives merge (the retired 4-key\n// shell `{\"matrx_version\": 1, \"kind\": \"reference\", \"type\": \"scope\", \"items\": [...]}`, usually inside\n// a ```matrx fence). Before this, a text cell holding either printed the raw fence: Arman's\n// Department table, 2026-09-28 — Team Leader read ```matrx {\"matrx_version\":1,…}```.\n//\n// THE SHELL IS UNDERSTOOD IN ONE PLACE. Whether an object is a directive — the current shell, or\n// the retired one stored before the merge — is `@ai-matrx/content-ir/directives`' `tryDecodeDirective`\n// alone (its containment guard keeps the retired shell there). This module only takes the object out\n// of its fence and hands it, untouched, to the host's `renderKind` port, which draws it through the\n// kind system. New values are stored as `__kind` JSON, never as a fence.\n\nimport { tryDecodeDirective } from \"@ai-matrx/content-ir/directives\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\n\n/** What a cell holds when it holds a kind. */\nexport interface KindValue {\n /** The parsed object, exactly as stored (`__kind` kept — it is part of the data). */\n value: Record<string, unknown>;\n /**\n * The kind's own name: `__kind`, or for a directive the slug the one decoder reads\n * (`directive_v1_reference_scope`, the retired shell included).\n */\n kind: string;\n /** True when the one decoder read this as a Matrx directive. */\n directive: boolean;\n /** The items a directive carries (a reference's chips), when it carries any. */\n items: Record<string, unknown>[];\n}\n\nconst KIND_KEY = \"__kind\";\n/** One fenced block and nothing else: ```matrx {…}``` or ```json {…}```. */\nconst WHOLE_FENCE = /^\\s*```(?:matrx|json)?[ \\t]*\\r?\\n?([\\s\\S]*?)\\r?\\n?[ \\t]*```\\s*$/;\n\nfunction asObject(value: unknown): Record<string, unknown> | null {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n}\n\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") || !trimmed.endsWith(\"}\")) return null;\n try {\n return asObject(JSON.parse(trimmed));\n } catch {\n return null;\n }\n}\n\nfunction fromObject(obj: Record<string, unknown>): KindValue | null {\n // THE ONE DECODER decides what a directive is — the current two-key shell and, for stored\n // content only, the retired 4-key one. A directive it cannot honour is not drawn as one.\n const directive = tryDecodeDirective(obj);\n if (directive) return { value: obj, kind: directive.slug, directive: true, items: [...directive.items] };\n const named = obj[KIND_KEY];\n if (typeof named === \"string\" && named.trim() !== \"\") {\n const items = Array.isArray(obj.items) ? obj.items.filter((i): i is Record<string, unknown> => asObject(i) !== null) : [];\n return { value: obj, kind: named.trim(), directive: false, items };\n }\n return null;\n}\n/**\n * The kind value a cell holds, or null. An object with `__kind`, a string that is such an object's\n * JSON, or a string that is ONE fenced block of it (```matrx / ```json), the retired directive shell\n * included. Text that merely mentions a fence among other words is text, and stays text.\n */\nexport function kindValueOf(value: unknown): KindValue | null {\n const obj = asObject(value);\n if (obj) return fromObject(obj);\n if (typeof value !== \"string\" || value.length > 200_000) return null;\n const fenced = WHOLE_FENCE.exec(value);\n const parsed = parseJsonObject(fenced ? fenced[1]! : value);\n return parsed ? fromObject(parsed) : null;\n}\n\n/** The words an item names itself by (a reference's label, a title, a name). */\nexport function kindItemWords(item: Record<string, unknown>): string | null {\n for (const key of [\"label\", \"title\", \"name\", \"display_name\"]) {\n const v = item[key];\n if (typeof v === \"string\" && v.trim() !== \"\") return v.trim();\n }\n return null;\n}\n\n/**\n * A kind value in words, for a sentence, a card, a copy or an export: the items' own names when it\n * carries named items (\"Arman Sadeghi, Tahir Mahfooz\"), else what kind of thing it is.\n */\nexport function kindValueWords(kv: KindValue): string {\n const named = kv.items.map(kindItemWords).filter((w): w is string => w !== null);\n if (named.length > 0) return named.join(\", \");\n return kindLabel(kv.kind);\n}\n\n/** A kind's name the way a person reads it: `directive_v1_reference_scope` → \"Reference Scope\". */\nexport function kindLabel(kind: string): string {\n return humanizeIdentifier(kind.replace(/^directive_v\\d+_/, \"\").replace(/_v\\d+$/, \"\")) || \"Structured value\";\n}\n","// src/formulaNames.ts — @ai-matrx/records-ui\n//\n// A FORMULA READS WITH TODAY'S COLUMN NAMES (merged-grid review 2, 2026-09-27, C3).\n//\n// A formula written as `{Quote} * 1.08` kept reading `{Quote}` after the column was renamed\n// \"Quote amount\" — it still computed, because the store keeps the parsed expression by FIELD ID\n// (`config.expr`: `{\"field\": \"<id>\"}` nodes), but the words a person reads were the text as first\n// typed (`config.formula_text`). Airtable and Sheets both show a formula with the column's current\n// name. So the text is DRAWN from the ids: each `{name}` in the text is paired, in order, with the\n// expression's field references (the parser keeps left-to-right order), and a name that no longer\n// belongs to the id it points at is replaced by that id's current label.\n//\n// It changes only what is SHOWN. When the pairing cannot be trusted — the counts differ, or one\n// name would have to become two different columns — the text is shown exactly as it was.\n\nimport { sourceArchivedOf, type Field, type SourceArchived } from \"@ai-matrx/records\";\nimport { fieldName } from \"./names\";\n\n/** Every `{\"field\": id}` in an expression, depth-first, left to right. */\nexport function fieldRefsOf(expr: unknown): string[] {\n const out: string[] = [];\n const walk = (node: unknown) => {\n if (Array.isArray(node)) {\n for (const n of node) walk(n);\n return;\n }\n if (node === null || typeof node !== \"object\") return;\n const obj = node as Record<string, unknown>;\n if (typeof obj[\"field\"] === \"string\" && Object.keys(obj).length === 1) {\n out.push(obj[\"field\"]);\n return;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(expr);\n return out;\n}\n\nconst BRACE = /\\{([^{}]*)\\}/g;\n\n/** The formula's text with every column named as it is called NOW. */\nexport function formulaTextNow(text: string, expr: unknown, fields: readonly Field[] | null | undefined): string {\n if (!text || !fields || fields.length === 0) return text;\n const refs = fieldRefsOf(expr);\n const names = [...text.matchAll(BRACE)].map((m) => m[1] ?? \"\");\n if (refs.length === 0 || refs.length !== names.length) return text;\n const byId = new Map(fields.map((f) => [String(f.id), f]));\n // One stale name must become ONE column; otherwise the pairing is not trusted.\n const becomes = new Map<string, string>();\n const replacement: string[] = [];\n for (let i = 0; i < names.length; i += 1) {\n const name = names[i]!;\n const field = byId.get(refs[i]!);\n if (!field) return text;\n const now = fieldName(field);\n if (now.trim().toLowerCase() === name.trim().toLowerCase()) {\n replacement.push(name);\n continue;\n }\n const seen = becomes.get(name);\n if (seen !== undefined && seen !== now) return text;\n becomes.set(name, now);\n replacement.push(now);\n }\n let i = 0;\n return text.replace(BRACE, () => `{${replacement[i++]}}`);\n}\n\n/** The Field with its formula's text drawn in today's names (a copy; the Field is untouched). */\nexport function withFormulaNamesNow(field: Field, fields: readonly Field[] | null | undefined): Field {\n const config = (field.config ?? {}) as Record<string, unknown>;\n const text = typeof config[\"formula_text\"] === \"string\" ? (config[\"formula_text\"] as string) : \"\";\n if (text === \"\") return field;\n const now = formulaTextNow(text, config[\"expr\"] ?? (field as { expr?: unknown }).expr, fields);\n return now === text ? field : ({ ...field, config: { ...config, formula_text: now } } as Field);\n}\n\n/* ═══ HOW A WORKED-OUT COLUMN SHOWS BY DEFAULT (merged-grid review 2, 2026-09-27, A12) ══════════════\n *\n * A formula over money showed 2,639.875 until somebody set \"Shows as Currency\" by hand, and a row\n * with nothing typed yet showed \"$0.00\". Airtable: a formula's result format follows its inputs\n * (money in, money out) and a formula with nothing to work on is blank. So, when the column's own\n * settings chose no look:\n * · arithmetic over a money column shows as that money; arithmetic over plain numbers shows as a\n * number with the inputs' declared precision (2 when none says);\n * · a row where every column the formula reads is empty shows the cell empty.\n * A look the column's settings chose always wins; a formula that is not plain arithmetic (a\n * comparison, words, a date) keeps the value as the store answers it.\n */\n\n/** The store's arithmetic nodes: a result made only of these is a number. */\nconst ARITHMETIC = new Set([\"fx.add\", \"fx.sub\", \"fx.mul\", \"fx.div\", \"fx.sum\", \"fx.round\", \"fx.min\", \"fx.max\", \"fx.abs\", \"fx.avg\", \"fx.neg\", \"fx.ceil\", \"fx.floor\"]);\n\nfunction opsOf(expr: unknown, out: string[] = []): string[] {\n if (Array.isArray(expr)) for (const n of expr) opsOf(n, out);\n else if (expr && typeof expr === \"object\") {\n const obj = expr as Record<string, unknown>;\n if (typeof obj[\"op\"] === \"string\") out.push(obj[\"op\"]);\n for (const value of Object.values(obj)) if (value && typeof value === \"object\") opsOf(value, out);\n }\n return out;\n}\n\nfunction exprOf(field: Field): unknown {\n const config = (field.config ?? {}) as Record<string, unknown>;\n return config[\"expr\"] ?? (field as { expr?: unknown }).expr;\n}\n\n/** The columns a formula reads, as Fields (in order, once each); `null` when one cannot be found. */\nexport function formulaInputs(field: Field, fields: readonly Field[] | null | undefined): Field[] | null {\n const refs = fieldRefsOf(exprOf(field));\n if (refs.length === 0 || !fields) return null;\n const byId = new Map(fields.map((f) => [String(f.id), f]));\n const out: Field[] = [];\n for (const id of new Set(refs)) {\n const f = byId.get(id);\n if (!f) return null;\n out.push(f);\n }\n return out;\n}\n\nconst NUMERIC_KINDS = new Set([\"number\", \"currency\", \"percent\"]);\n\n/** The default look of a formula's result, from its inputs — or `undefined` to leave it as answered. */\nexport function formulaDefaultFormat(\n field: Field,\n fields: readonly Field[] | null | undefined,\n kindOf: (f: Field) => string,\n currencyCodeOf: (unit: string | null | undefined) => string,\n): { id: string; options?: Record<string, unknown> } | undefined {\n const inputs = formulaInputs(field, fields);\n if (!inputs || inputs.length === 0) return undefined;\n const ops = opsOf(exprOf(field));\n if (ops.length === 0 || !ops.every((op) => ARITHMETIC.has(op))) return undefined;\n if (!inputs.every((f) => NUMERIC_KINDS.has(kindOf(f)))) return undefined;\n const precisions = inputs\n .map((f) => ((f as unknown as { display_format?: { options?: { precision?: unknown } } }).display_format?.options?.precision))\n .filter((p): p is number => typeof p === \"number\");\n const precision = precisions.length > 0 ? Math.max(...precisions) : 2;\n // Money is a money column, or a number column whose settings show it as money.\n const lookOf = (f: Field) => (f as unknown as { display_format?: { id?: unknown; options?: { currency?: unknown } } }).display_format;\n const money = inputs.find((f) => kindOf(f) === \"currency\" || lookOf(f)?.id === \"currency\");\n if (money) {\n const code = lookOf(money)?.options?.currency;\n return { id: \"currency\", options: { currency: typeof code === \"string\" && code !== \"\" ? code : currencyCodeOf(money.unit) } };\n }\n return { id: \"decimal\", options: { precision } };\n}\n\n/** The keys a formula reads, stamped on the drawn copy so a cell can tell \"nothing to work on\". */\nexport const FORMULA_INPUT_KEYS = \"__formula_input_keys\";\n\n/** True when every column this formula reads is empty on this record: the cell is drawn empty. */\nexport function formulaHasNothingToWorkOn(field: Field, document: Record<string, unknown> | null | undefined): boolean {\n const keys = ((field.config ?? {}) as Record<string, unknown>)[FORMULA_INPUT_KEYS];\n if (!Array.isArray(keys) || keys.length === 0 || !document) return false;\n return keys.every((key) => {\n const v = document[String(key)];\n return v === null || v === undefined || v === \"\" || (Array.isArray(v) && v.length === 0);\n });\n}\n\n/**\n * A FORMULA THAT READS A COLUMN WHOSE SOURCE IS ARCHIVED (v7 TABLE-EXPERIENCE item 7, Law 4): the\n * first input holding the store's \"source archived\" answer, so an empty formula cell says why\n * instead of drawing a blank. Null when none does (or the inputs are not known on this copy).\n */\nexport function formulaSourceArchived(field: Field, document: Record<string, unknown> | null | undefined): SourceArchived | null {\n const keys = ((field.config ?? {}) as Record<string, unknown>)[FORMULA_INPUT_KEYS];\n if (!Array.isArray(keys) || !document) return null;\n for (const key of keys) {\n const state = sourceArchivedOf(document[String(key)]);\n if (state) return state;\n }\n return null;\n}\n\n/**\n * THE ONE DRAWN COPY OF A WORKED-OUT COLUMN: today's names in its text, its default look when its\n * settings chose none, and the keys it reads. Every other column comes back untouched.\n */\nexport function withFormulaDisplayNow(\n field: Field,\n fields: readonly Field[] | null | undefined,\n kindOf: (f: Field) => string,\n currencyCodeOf: (unit: string | null | undefined) => string,\n): Field {\n if (kindOf(field) !== \"formula\") return field;\n let next = withFormulaNamesNow(field, fields);\n const inputs = formulaInputs(field, fields);\n const config = (next.config ?? {}) as Record<string, unknown>;\n if (inputs && inputs.length > 0) next = { ...next, config: { ...config, [FORMULA_INPUT_KEYS]: inputs.map((f) => f.key) } } as Field;\n const chosen = (field as unknown as { display_format?: { id?: unknown } }).display_format;\n const hasLook = chosen && typeof chosen === \"object\" && typeof chosen.id === \"string\" && chosen.id !== \"formula\";\n if (!hasLook) {\n const look = formulaDefaultFormat(field, fields, kindOf, currencyCodeOf);\n if (look) next = { ...next, display_format: look } as unknown as Field;\n }\n return next;\n}\n","\"use client\";\n\n// src/HeldChangeDecision.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// APPROVE OR REFUSE A HELD CHANGE — for any host that is not the record pages. A workflow step\n// whose write the organization holds for a person PAUSES its run with the store's wait\n// (`matrx_records.held.held_interrupt_payload`: `held_write` + the `matrx_held_write` marker).\n// The server resumes such a run ONLY once the queue row is decided (`resolve_held_resume`\n// refuses a still-pending one with \"Approve or refuse it on the card first\"), so a host that\n// shows the pause as an ordinary question — a text box — leaves the person with no way through:\n// the W1.1 verifier typed \"Approve\", got a 409, and the run stayed stuck.\n//\n// This is the decision itself: `custom.work_approval_may_decide` decides whether the buttons are\n// drawn at all (a person who may not decide is told so, never shown a dead button), and\n// `custom.work_approval_decide` approves (APPLYING the change, as the person) or refuses. One\n// decision on the one queue row the chat, the table's page and the run page decide too.\n\nimport { useEffect, useState } from \"react\";\nimport type { RecordsDataSource, RecordsError, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider, useRecordsClient } from \"@ai-matrx/records/react\";\nimport { Button } from \"@ai-matrx/design-system\";\nimport { personActor } from \"./RecordsMount\";\nimport { RefusalLine } from \"./Refusal\";\n\nexport interface HeldChangeDecisionProps {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n /** The organization the held change lives in (the marker's `organization_id`). */\n organizationId: Uuid;\n approvalId: Uuid;\n /** Told once the store took the decision; `approved` says which way. */\n onDecided: (approved: boolean) => void;\n}\n\nexport function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }: HeldChangeDecisionProps) {\n return (\n <RecordsProvider config={{ dataSource, actor: personActor(userId), organizationId }}>\n <Decision approvalId={approvalId} onDecided={onDecided} />\n </RecordsProvider>\n );\n}\n\nfunction Decision({ approvalId, onDecided }: { approvalId: Uuid; onDecided: (approved: boolean) => void }) {\n const client = useRecordsClient();\n const [may, setMay] = useState<boolean | null>(null);\n const [busy, setBusy] = useState<\"approve\" | \"refuse\" | null>(null);\n const [error, setError] = useState<RecordsError | null>(null);\n\n useEffect(() => {\n let live = true;\n void client.workApprovalMayDecide({ approval_id: approvalId }).then((res) => {\n if (!live) return;\n if (res.ok) setMay(res.data);\n else {\n setMay(false);\n setError(res.error);\n }\n });\n return () => {\n live = false;\n };\n }, [client, approvalId]);\n\n const decide = async (approve: boolean) => {\n setBusy(approve ? \"approve\" : \"refuse\");\n setError(null);\n const res = await client.workApprovalDecide({ approval_id: approvalId, approve });\n setBusy(null);\n if (res.ok) onDecided(approve);\n else setError(res.error);\n };\n\n if (may === null) return <p className=\"text-xs text-muted-foreground\">Checking who can decide…</p>;\n return (\n <div className=\"flex flex-col gap-1.5\">\n {may ? (\n <div className=\"flex gap-2\">\n <Button type=\"button\" size=\"sm\" disabled={busy !== null} onClick={() => void decide(true)}>\n {busy === \"approve\" ? \"Approving…\" : \"Approve\"}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" disabled={busy !== null} onClick={() => void decide(false)}>\n {busy === \"refuse\" ? \"Refusing…\" : \"Refuse\"}\n </Button>\n </div>\n ) : (\n !error && <p className=\"text-xs text-muted-foreground\">An owner or admin of this organization decides this.</p>\n )}\n {error ? <RefusalLine error={error} /> : null}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_design_system","held","import_react","import_records","import_design_system","document","import_records","import_records","import_text_case","document","import_react","import_records","import_design_system","import_react","import_design_system","import_jsx_runtime","import_design_system","import_jsx_runtime","import_design_system","import_jsx_runtime","nameOf","import_jsx_runtime","refusal","target","id","import_react","import_design_system","import_react","import_records","import_jsx_runtime","import_react","import_records","import_uuid","import_react","import_design_system","import_jsx_runtime","document","asked","import_jsx_runtime","asked","import_react","import_design_system","import_jsx_runtime","import_jsx_runtime","import_react","import_records","import_design_system","import_react","import_design_system","import_jsx_runtime","shown","import_jsx_runtime","own","import_react","import_records","import_design_system","import_jsx_runtime","recordName","own","id","import_react","import_jsx_runtime","import_data_table","import_field_formats","import_records","import_react","import_design_system","import_field_formats","import_react","import_data_table","import_field_formats","import_design_system","import_jsx_runtime","own","shown","import_jsx_runtime","import_react","import_design_system","import_records","import_react","import_jsx_runtime","shown","import_react","asked","import_jsx_runtime","read","shown","own","refusal","add","import_react","import_jsx_runtime","import_react","import_records","import_design_system","import_jsx_runtime","import_jsx_runtime","own","shown","import_react","import_records","import_design_system","import_jsx_runtime","import_react","import_data_table","import_field_formats","import_design_system","import_react","import_core","import_react","import_core","import_design_system","import_jsx_runtime","import_field_formats","import_records","import_design_system","import_text_case","import_jsx_runtime","own","import_records","document","import_records","import_jsx_runtime","document","import_jsx_runtime","import_react","import_design_system","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/pickers.ts","../src/TablePickers.tsx","../src/askOnce.ts","../src/editors.tsx","../src/dates.ts","../src/newerKindValues.tsx","../src/choiceLooks.ts","../src/parity.ts","../src/docs.ts","../src/fieldTypes.ts","../src/names.ts","../src/RelationPicker.tsx","../src/PickOrAdd.tsx","../src/personChip.tsx","../src/Refusal.tsx","../src/plainWords.ts","../src/refusals.ts","../src/tellApart.ts","../src/buttonCell.tsx","../src/columnName.ts","../src/FieldEditor.tsx","../src/ReferenceBuilder.tsx","../src/createTable.ts","../src/tablePicking.tsx","../src/FormulaTextEditor.tsx","../src/host.tsx","../src/rights.ts","../src/EntityReferenceKindPicker.tsx","../src/SourceArchivedNotice.tsx","../src/values.tsx","../src/embeddedLook.tsx","../src/labels.tsx","../src/signature.tsx","../src/personTime.ts","../src/presentation.ts","../src/enumLabels.ts","../src/EntityReferenceControl.tsx","../src/PickOne.tsx","../src/WholeValue.tsx","../src/formattedValue.tsx","../src/gridAttachments.tsx","../src/FilePicker.tsx","../src/ReferenceChips.tsx","../src/kindValues.ts","../src/formulaNames.ts","../src/Condition.tsx","../src/FieldRetype.tsx","../src/FieldRulePreview.tsx","../src/ColumnLook.tsx","../src/ChoiceListEditor.tsx","../src/NewerKindQuestions.tsx","../src/FieldFormatPicker.tsx","../src/archiveWords.ts","../src/gridMenus.ts","../src/ButtonSettings.tsx","../src/AccentSwatches.tsx","../src/PersonPicker.tsx","../src/FloatingRefusal.tsx","../src/formatControls.tsx","../src/typedDateHelper.tsx","../src/choiceNudge.ts","../src/RecordsMount.tsx","../src/DataBindingPicker.tsx","../src/PickedSummaries.tsx","../src/HeldChangeDecision.tsx"],"sourcesContent":["// src/pickers.ts — @ai-matrx/records-ui/pickers (W1.1)\n//\n// The pick-by-name primitives alone: table / column-value / record pickers, the \"From my data\"\n// binding picker and their read-back words. A host that only needs these (the workflow studio)\n// imports this subpath so the rest of the package's screens never enter its module graph.\nexport { TablePicker, TableScope, ColumnValuesEditor, RecordPicker, useTablesAnywhere } from \"./TablePickers\";\nexport type {\n TableAnywhere,\n TablesAnywhere,\n TablePickerProps,\n TableScopeProps,\n ColumnValuesEditorProps,\n RecordPickerProps,\n} from \"./TablePickers\";\nexport {\n DataBindingPicker,\n emptyDataBinding,\n isDataBinding,\n isCompleteDataBinding,\n defaultBindingTemplate,\n bindingPlaceholdersFor,\n DATA_BINDING_SHAPES,\n DATA_BINDING_MISSING,\n} from \"./DataBindingPicker\";\nexport type { DataBinding, DataBindingShape, DataBindingPickerProps } from \"./DataBindingPicker\";\nexport { TableNameText, ColumnValuesText, RecordNameText } from \"./PickedSummaries\";\nexport { HeldChangeDecision } from \"./HeldChangeDecision\";\nexport type { HeldChangeDecisionProps } from \"./HeldChangeDecision\";\n","\"use client\";\n\n// src/TablePickers.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// PICK BY NAME, NEVER BY ID. The one table picker, column/value row editor and record picker for\n// any host screen that STORES a table id, a record id or `{column key: value}` but must SHOW names:\n// the workflow studio's data steps first (`data.table.*`, `records.*` declare `table_picker`,\n// `column_values`, `record_picker`), every other builder after. Before this a workflow step asked\n// a person to paste a table uuid and hand-write `{\"status\": \"low\"}` as JSON.\n//\n// THE LIST is `custom.data_home_tables()` with no organization — every Table the person can open in\n// every organization she can reach (law: common-docs/policies/access-ladder.md),\n// one flat list, each row naming its organization. The chosen Table's columns and records are read\n// in the organization the Table lives in (`TableScope`), never the active one.\n//\n// WHAT IS STORED is unchanged: the table id, the record id, and `{field.key: stored value}` — the\n// exact keys `custom` record documents carry, so a saved workflow from before this file reads back\n// and runs unchanged. A key that is no longer a column is shown as itself, marked, never dropped.\n\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport type { Field, RecordsDataSource, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider, useFields, useRecords, useTable } from \"@ai-matrx/records/react\";\nimport { Button, CreatablePicker, type CreatableOption } from \"@ai-matrx/design-system\";\nimport { FieldControl } from \"./editors\";\nimport { fieldName, rowNameIn } from \"./names\";\nimport { personActor } from \"./RecordsMount\";\nimport { tablePickerEntries } from \"./tablePicking\";\nimport { RefusalLine } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** One row of `custom.data_home_tables()`. */\nexport interface TableAnywhere {\n table_id: Uuid;\n table_name: string;\n organization_id: Uuid;\n organization_name: string;\n kind: string | null;\n platform_owned: boolean;\n /** When the table last changed (the door's own column) — what tells two same-named tables apart. */\n updated_at?: string | null;\n /** Who made it, when the door says. */\n created_by_name?: string | null;\n}\n\nexport interface TablesAnywhere {\n loading: boolean;\n /** The store's own sentence when the list was refused. */\n error: string | null;\n rows: TableAnywhere[];\n}\n\n// ONE READ PER DATA SOURCE (W1.1, 2026-10-02). Every TableScope / table name on a screen used to\n// read `data_home_tables` for itself — a Find Records result of 20 rows fired 20 identical reads,\n// and when they failed every row sat on \"…\". Reads in flight (and a just-read list, briefly) are\n// shared per data source; a failed read is never kept, so the next mount asks again.\nconst SHARED_FOR_MS = 5_000;\nconst sharedReads = new WeakMap<RecordsDataSource, { at: number; read: Promise<TablesAnywhere> }>();\n\nfunction readTablesAnywhere(dataSource: RecordsDataSource): Promise<TablesAnywhere> {\n const held = sharedReads.get(dataSource);\n if (held && Date.now() - held.at < SHARED_FOR_MS) return held.read;\n const read = Promise.resolve(dataSource.rpc(\"data_home_tables\", {}, { schema: \"custom\" })).then(\n ({ data, error }): TablesAnywhere => {\n if (error) {\n return {\n loading: false,\n error: refusalSentence({ message: String(error[\"message\"] ?? \"\") }) || \"Tables could not be read.\",\n rows: [],\n };\n }\n const rows = (Array.isArray(data) ? (data as TableAnywhere[]) : []).slice();\n rows.sort((a, b) => a.table_name.localeCompare(b.table_name));\n return { loading: false, error: null, rows };\n },\n (thrown: unknown): TablesAnywhere => ({\n loading: false,\n error: String((thrown as Error)?.message ?? thrown) || \"Tables could not be read.\",\n rows: [],\n }),\n );\n sharedReads.set(dataSource, { at: Date.now(), read });\n void read.then((result) => {\n if (result.error && sharedReads.get(dataSource)?.read === read) sharedReads.delete(dataSource);\n });\n return read;\n}\n\n/** Every Table the person can open, in every organization, sorted by name. */\nexport function useTablesAnywhere(dataSource: RecordsDataSource): TablesAnywhere {\n const [state, setState] = useState<TablesAnywhere>({ loading: true, error: null, rows: [] });\n useEffect(() => {\n let live = true;\n void readTablesAnywhere(dataSource).then((result) => {\n if (live) setState(result);\n });\n return () => {\n live = false;\n };\n }, [dataSource]);\n return state;\n}\n\nexport interface TablePickerProps {\n dataSource: RecordsDataSource;\n value: string | null;\n onChange: (tableId: string) => void;\n disabled?: boolean;\n /** Hand in an already-read list to skip a second read. */\n tables?: TablesAnywhere;\n}\n\n/** Pick a Table by its name; the id is what `onChange` hands back. */\nexport function TablePicker({ dataSource, value, onChange, disabled, tables }: TablePickerProps) {\n const own = useTablesAnywhere(dataSource);\n const list = tables ?? own;\n // Tables the app keeps for itself (choice lists, ledgers) stay out of the list unless chosen —\n // the one rule every table picker uses (`tablePicking.ts`).\n const options = tablePickerEntries(\n list.rows.map((t) => ({ ...t, id: t.table_id, name: t.table_name })),\n { keep: value },\n ).entries.map(({ table: t }) => t);\n // Two tables of one name in one organization are told apart by a second line: who made it and\n // when it last changed (the organization hint cannot tell them apart).\n const sameName = new Map<string, number>();\n for (const t of options) {\n const key = `${t.organization_id}|${t.table_name.trim().toLowerCase()}`;\n sameName.set(key, (sameName.get(key) ?? 0) + 1);\n }\n const pickerOptions: CreatableOption[] = options.map((t) => {\n const twin = (sameName.get(`${t.organization_id}|${t.table_name.trim().toLowerCase()}`) ?? 0) > 1;\n const row = t as typeof t & TableAnywhere;\n const second = [\n row.created_by_name ? `by ${row.created_by_name}` : null,\n row.updated_at ? `changed ${new Date(row.updated_at).toLocaleDateString()}` : null,\n ]\n .filter(Boolean)\n .join(\" · \");\n return {\n value: t.table_id,\n // The organization hint already tells two same-named tables apart across organizations.\n label: t.table_name,\n hint: t.organization_name,\n keywords: t.organization_name,\n ...(twin && second\n ? {\n render: (\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate\">{t.table_name}</span>\n <span className=\"truncate text-[11px] text-muted-foreground\">{second}</span>\n </span>\n ),\n }\n : {}),\n };\n });\n const missing = Boolean(value) && !list.loading && !list.error && !list.rows.some((t) => t.table_id === value);\n return (\n <div className=\"flex flex-col gap-1\">\n <CreatablePicker\n value={value || null}\n options={pickerOptions}\n onSelect={onChange}\n placeholder={missing ? \"Table not available\" : \"Choose a table\"}\n searchPlaceholder=\"Search tables\"\n noun=\"table\"\n loading={list.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Table\"\n />\n {list.error && <RefusalLine error={refusalOf(\"door\", list.error, \"Try again in a moment.\")} />}\n {missing && <p className=\"text-[11px] text-destructive\">This table is archived or not shared with you.</p>}\n </div>\n );\n}\n\nexport interface TableScopeProps {\n dataSource: RecordsDataSource;\n /** The signed-in person — the actor every read runs as. */\n userId: Uuid | null;\n tableId: string | null;\n children: ReactNode;\n /** Shown while the Table's organization is unknown, or when no Table is chosen. */\n fallback?: ReactNode;\n /** Shown when the list of Tables could not be read, or the Table is not one this person can\n * open — a scope that never resolves must say so, never wait forever. Defaults to `fallback`. */\n unavailable?: ReactNode;\n tables?: TablesAnywhere;\n}\n\n/** The record store, bound to the organization the chosen Table lives in. */\nexport function TableScope({ dataSource, userId, tableId, children, fallback = null, unavailable, tables }: TableScopeProps) {\n const own = useTablesAnywhere(dataSource);\n const list = tables ?? own;\n const organizationId = list.rows.find((t) => t.table_id === tableId)?.organization_id ?? null;\n if (tableId && !organizationId && !list.loading) return <>{unavailable ?? fallback}</>;\n if (!tableId || !organizationId) return <>{fallback}</>;\n return (\n <RecordsProvider config={{ dataSource, actor: personActor(userId), organizationId }}>\n {children}\n </RecordsProvider>\n );\n}\n\nexport interface ColumnValuesEditorProps {\n tableId: string;\n /** `{field key: stored value}` — what the step matches on or writes. */\n value: Record<string, unknown>;\n onChange: (next: Record<string, unknown>) => void;\n disabled?: boolean;\n /** The add button's label: \"Add a condition\" for a lookup, \"Add a value\" for a write. */\n addLabel: string;\n}\n\n/** Column / value rows for one Table. Must sit inside a `TableScope`. */\nexport function ColumnValuesEditor({ tableId, value, onChange, disabled, addLabel }: ColumnValuesEditorProps) {\n const fields = useFields(tableId);\n const all = useMemo(() => fields.data ?? [], [fields.data]);\n const byKey = useMemo(() => new Map(all.map((f) => [f.key, f])), [all]);\n const keys = Object.keys(value);\n // A row whose column is not chosen yet lives here until it is.\n const [adding, setAdding] = useState(false);\n\n const optionsFor = (current: string | null): CreatableOption[] =>\n all\n .filter((f) => f.key === current || !(f.key in value))\n .map((f) => ({ value: f.key, label: fieldName(f) }));\n\n const rename = (from: string, to: string) => {\n if (from === to) return;\n const next: Record<string, unknown> = {};\n for (const k of keys) next[k === from ? to : k] = k === from ? null : value[k];\n onChange(next);\n };\n const remove = (key: string) => {\n const { [key]: _gone, ...rest } = value;\n void _gone;\n onChange(rest);\n };\n\n return (\n <div className=\"flex flex-col gap-2\">\n {fields.error && <RefusalLine error={fields.error} />}\n {keys.map((key) => {\n const field = byKey.get(key);\n return (\n <ColumnValueRow\n key={key}\n columnKey={key}\n field={field}\n loading={fields.loading}\n options={optionsFor(key)}\n value={value[key]}\n disabled={disabled}\n onColumn={(to) => rename(key, to)}\n onValue={(v) => onChange({ ...value, [key]: v })}\n onRemove={() => remove(key)}\n />\n );\n })}\n {adding && (\n <ColumnValueRow\n columnKey={null}\n field={undefined}\n loading={fields.loading}\n options={optionsFor(null)}\n value={null}\n disabled={disabled}\n onColumn={(to) => {\n setAdding(false);\n onChange({ ...value, [to]: null });\n }}\n onValue={() => undefined}\n onRemove={() => setAdding(false)}\n />\n )}\n {!disabled && !adding && keys.length < all.length && (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"self-start\" onClick={() => setAdding(true)}>\n {addLabel}\n </Button>\n )}\n </div>\n );\n}\n\nfunction ColumnValueRow({\n columnKey,\n field,\n loading,\n options,\n value,\n disabled,\n onColumn,\n onValue,\n onRemove,\n}: {\n columnKey: string | null;\n field: Field | undefined;\n loading: boolean;\n options: CreatableOption[];\n value: unknown;\n disabled?: boolean | undefined;\n onColumn: (key: string) => void;\n onValue: (value: unknown) => void;\n onRemove: () => void;\n}) {\n // A saved key that is no longer a column keeps its own words and says so.\n const orphan = columnKey !== null && !loading && field === undefined;\n const shown = orphan ? [{ value: columnKey, label: columnKey, hint: \"Not a column\" }, ...options] : options;\n return (\n <div className=\"flex flex-col gap-1 rounded-md border border-border/60 p-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"min-w-0 flex-1\">\n <CreatablePicker\n value={columnKey}\n options={shown}\n onSelect={onColumn}\n placeholder=\"Choose a column\"\n searchPlaceholder=\"Search columns\"\n noun=\"column\"\n loading={loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Column\"\n />\n </div>\n {!disabled && (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" aria-label=\"Remove\" onClick={onRemove}>\n ✕\n </Button>\n )}\n </div>\n {field ? (\n <FieldControl field={field} value={value} onChange={onValue} disabled={disabled} />\n ) : orphan ? (\n <p className=\"text-[11px] text-muted-foreground\">{value === null || value === undefined ? \"—\" : String(value)}</p>\n ) : null}\n </div>\n );\n}\n\nexport interface RecordPickerProps {\n tableId: string;\n value: string | null;\n onChange: (recordId: string) => void;\n disabled?: boolean;\n}\n\n/** Pick one record of a Table by its name. Must sit inside a `TableScope`. */\nexport function RecordPicker({ tableId, value, onChange, disabled }: RecordPickerProps) {\n const table = useTable(tableId);\n const records = useRecords(tableId, { pageSize: 200 });\n const rows = records.data?.rows ?? [];\n const options: CreatableOption[] = rows.map((row) => ({\n value: row.id,\n label: rowNameIn(table.data ?? null, row),\n }));\n const missing = Boolean(value) && !records.loading && !records.error && !rows.some((r) => r.id === value);\n return (\n <div className=\"flex flex-col gap-1\">\n <CreatablePicker\n value={value || null}\n options={options}\n onSelect={onChange}\n placeholder={missing ? \"Record not in this table\" : \"Choose a record\"}\n searchPlaceholder=\"Search records\"\n noun=\"record\"\n loading={records.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Record\"\n />\n {records.error && <RefusalLine error={records.error} />}\n </div>\n );\n}\n","// src/askOnce.ts — @ai-matrx/records-ui\n//\n// ONE QUESTION IN FLIGHT, ONE ANSWER FOR EVERY ASKER (lane TABLE-ACTIONS T5.3, PROOF-BOOK 1.18).\n//\n// A table open asked `custom.field_options` 13 times for 2 choice columns (the colours, the label\n// lookup, the paste planner and each re-run of their effects each asked on their own) and the\n// header menus' value counts twice per column. Every asker of the same question, on the same\n// client, within `freshMs` of the last answer, gets that one answer. A refusal is never kept: the\n// next asker asks again. A write that changes the answer calls `forgetAsked` with its prefix.\n\nimport { onTableStructureChanged, type RecordsClient } from \"@ai-matrx/records/core\";\n\ntype Answer = { ok: boolean };\n\ntype Held = Map<string, { at: number; epoch: number; answer: Promise<unknown> }>;\n\n/**\n * A Table's shape moved (a column or its choices were written by anybody on this page): everything\n * kept before that moment is stale, whatever its age. This is what lets the freshness window cover a\n * whole page open (lane DEDUPE-READS) instead of two seconds.\n */\nlet structureEpoch = 0;\nonTableStructureChanged(() => {\n structureEpoch += 1;\n});\n\nconst asked = new WeakMap<object, Held>();\n/** Per data source (the host's one supabase client survives a records client's rebuild) and per person. */\nconst byPerson = new WeakMap<object, Map<string, Held>>();\n\n/**\n * WHO IS ASKING, NOT WHICH OBJECT (lane SEED-ENTITY). The records client is REBUILT when the active\n * organization resolves (~1.5 s into a page); its reads re-fire from effects keyed on the client. The\n * questions kept here are semantic (a table, a column, a set of ids — never the organization), and the\n * answer is the same person's, so a rebuilt client over the SAME data source for the SAME person\n * shares them. A client with no data source in its config (a test double) keeps its own.\n */\nfunction heldFor(client: object): Held {\n const config = (client as { config?: { dataSource?: unknown; actor?: { actor?: string; user_id?: string | null; on_behalf_of?: string | null } } }).config;\n const source = config?.dataSource;\n if (source && typeof source === \"object\" && config?.actor) {\n const who = [config.actor.actor ?? \"-\", config.actor.user_id ?? \"-\", config.actor.on_behalf_of ?? \"-\"].join(\"|\");\n let persons = byPerson.get(source);\n if (!persons) {\n persons = new Map();\n byPerson.set(source, persons);\n }\n let held = persons.get(who);\n if (!held) {\n held = new Map();\n persons.set(who, held);\n }\n return held;\n }\n let held = asked.get(client);\n if (!held) {\n held = new Map();\n asked.set(client, held);\n }\n return held;\n}\n\nexport function askOnce<T extends Answer>(client: object, key: string, ask: () => Promise<T>, freshMs: number): Promise<T> {\n const held = heldFor(client);\n const now = Date.now();\n const kept = held.get(key);\n if (kept && kept.epoch === structureEpoch && now - kept.at <= freshMs) return kept.answer as Promise<T>;\n const answer = ask().then(\n (result) => {\n if (!result.ok) held.delete(key);\n return result;\n },\n (thrown: unknown) => {\n held.delete(key);\n throw thrown;\n },\n );\n held.set(key, { at: now, epoch: structureEpoch, answer });\n return answer;\n}\n\n/** Tests only: forget everything kept for every client (tests that share one data source across cases). */\nexport function forgetAllAsked(client: object): void {\n heldFor(client).clear();\n}\n\n/** Forget every kept answer whose key starts with `prefix` (a write changed what it answers). */\nexport function forgetAsked(client: object, prefix: string): void {\n const held = heldFor(client);\n for (const key of [...held.keys()]) if (key.startsWith(prefix)) held.delete(key);\n}\n\n/**\n * How long a column's choices are shared between askers: one page open, including the records\n * client being rebuilt when the active organization resolves (~2 s in) and every effect that re-runs\n * after it. 2 s ended just before the second fire (lane DEDUPE-READS: Spaces measured one at hydration\n * and one ~2 s later). A write on this page ends it at once (`structureEpoch`); another person's edit\n * shows within this window at most.\n */\nexport const FIELD_OPTIONS_FRESH_MS = 10_000;\n\n/** A column's choices, asked once for every asker in the same moment (`custom.field_options`). */\nexport function fieldOptionsOnce(\n client: Pick<RecordsClient, \"fieldOptions\">,\n fieldId: string,\n): ReturnType<RecordsClient[\"fieldOptions\"]> {\n return askOnce(client, `field_options:${fieldId}`, () => client.fieldOptions({ field_id: fieldId }), FIELD_OPTIONS_FRESH_MS);\n}\n\n/** How long a page of badges is shared between askers: the one page open, ended by any explicit refresh. */\nexport const ENRICH_CELLS_FRESH_MS = 5_000;\n","\"use client\";\n\n// src/editors.tsx — @ai-matrx/records-ui\n//\n// ONE EDITOR PER PARITY TYPE, and every one of them is a design-system\n// primitive. There is no bespoke input in this package and no per-feature\n// editor anywhere in the platform: a Field decides which of these is drawn,\n// from what the STORE stores about it (behaviour + modifiers + format + unit +\n// relation target), never from the value it happens to hold.\n//\n// FLD-9: a Formula is worked out by the system. Its editor is not a disabled\n// text box — it is the value with the sentence the store itself would say if\n// you tried to type into it.\n\nimport { fieldOptionsOnce, forgetAsked } from \"./askOnce\";\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from \"react\";\nimport type { Field, RecordDocument, RecordsError, StoredRecord, Uuid } from \"@ai-matrx/records\";\nimport { isButtonField, allowsOtherValues, choiceValuesOf, coerceTypedAnswer, newerKindOf, decideTypedChoice, isTheChosen, optionKey, rankTypedMatches, readTypedTime, typedDateText, typedTimeText, type ChoiceNudge } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport {\n BasicInput,\n BasicTextarea,\n Badge,\n Button,\n Checkbox,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n} from \"@ai-matrx/design-system\";\nimport { carriesTimeOfDay } from \"./dates\";\nimport { newerKindControl } from \"./newerKindValues\";\nimport { editorKindFor } from \"./parity\";\nimport { fieldName, recordName } from \"./names\";\nimport { RelationPicker } from \"./RelationPicker\";\nimport { ButtonValue } from \"./buttonCell\";\nimport { AttachmentControl, hostTakesFiles } from \"./gridAttachments\";\nimport { useRecordsUi } from \"./host\";\nimport { EntityReferenceControl } from \"./EntityReferenceControl\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { PersonPicker } from \"./PersonPicker\";\nimport { RefusalLine, RefusalNotice } from \"./Refusal\";\nimport { FloatingRefusal } from \"./FloatingRefusal\";\nimport { refusalFromThrown } from \"./refusals\";\nimport { formatForField } from \"./presentation\";\nimport { formatControl, typedText } from \"./formatControls\";\nimport { TypedDateHelper, type DateHelperKind } from \"./typedDateHelper\";\nimport { FormattedValue } from \"./formattedValue\";\nimport { useChoiceNudge } from \"./choiceNudge\";\nimport { SignaturePad, isSignatureField } from \"./signature\";\nimport { choiceChipLookOf } from \"./choiceLooks\";\n\n/**\n * STORE-RULE-GAPS: the choice editor below takes words that are not a choice on a column that\n * takes other values (`config.allow_other`) — kept as typed, or added to the choices, as the\n * person (or the `custom/choice_nudge` knob) decides. The field editor offers that setting's\n * tick ONLY because this is true — the screen never offers a setting it cannot honour.\n */\nexport const CHOICE_EDITOR_ADDS_WHAT_IS_TYPED = true;\n\n/* ═══ WORDS THAT ARE NOT A CHOICE YET (lane CHOICE-COLUMN-EDIT, 2026-09-27) ═════════════════════\n *\n * A software team's \"Account Type\" column offers Cursor · Claude · Codex and somebody types\n * \"Gemini\". The cell asks: Add “Gemini” to the choices for Account Type? — Add / Keep as typed /\n * Cancel, with Keep as typed only on a column that takes other values. What it asks, or does\n * without asking, is `decideTypedChoice` (@ai-matrx/records) reading the `custom/choice_nudge`\n * knob; this file only draws the answer.\n *\n * 🚨 THE LIE THIS CLOSES. The allow-other picker offered Add “<typed>” and sent the word; the\n * store kept it as an OTHER value and never added it to the choices. Now Add really adds: in a\n * grid cell the value becomes a `ChoiceAddition`, which the grid saves through\n * `recordUpdateAddingChoices` (the new choice and the cell, one transaction); elsewhere the\n * choice is added through `fieldUpdate`'s `options_add` and the cell then takes it.\n */\n\n/** A cell value that also ADDS words to its column's choices. Only a host that declares\n * `addsChoices` (the grid) is ever handed one. */\nexport interface ChoiceAddition {\n readonly addingChoices: true;\n /** What the cell holds — the words (beside the keys of existing choices, for several). */\n readonly value: unknown;\n /** The words added to the column's choices. */\n readonly add: readonly string[];\n}\n\nexport function isChoiceAddition(value: unknown): value is ChoiceAddition {\n return typeof value === \"object\" && value !== null && (value as { addingChoices?: unknown }).addingChoices === true;\n}\n\nexport function choiceAddition(value: unknown, add: readonly string[]): ChoiceAddition {\n return { addingChoices: true, value, add: [...add] };\n}\n\n/** A value with any addition set aside. */\nexport function withoutAddition(value: unknown): { value: unknown; add: readonly string[] } {\n return isChoiceAddition(value) ? { value: value.value, add: value.add } : { value, add: [] };\n}\n\n/** The question a choice cell asks about words that are not one of its choices. */\nexport interface ChoiceAsk {\n /** The words that are not a choice. */\n readonly words: readonly string[];\n /** True only when the column takes other values. */\n readonly keepOffered: boolean;\n /** What the cell takes on Add. */\n readonly onAdd: ChoiceAddition;\n /** What the cell takes on Keep as typed. */\n readonly asTyped: unknown;\n}\n\n/** “Gemini” · “Gemini” and “Copilot” · “A”, “B” and “C”. */\nfunction quoted(words: readonly string[]): string {\n const q = words.map((w) => `“${w}”`);\n return q.length <= 1 ? (q[0] ?? \"\") : `${q.slice(0, -1).join(\", \")} and ${q[q.length - 1]}`;\n}\n\n/** Add “Gemini” to the choices for Account Type? */\nexport function choiceAskSentence(field: Field, words: readonly string[]): string {\n return `Add ${quoted(words)} to the choices for ${fieldName(field)}?`;\n}\n\n/** “Gemini” is not one of the choices for Account Type. */\nexport function notAChoiceSentence(field: Field, words: readonly string[]): string {\n return `${quoted(words)} ${words.length === 1 ? \"is\" : \"are\"} not one of the choices for ${fieldName(field)}.`;\n}\n\n/** The question's three doors, drawn once for the typed cell and the picker alike. */\nexport function ChoiceAskButtons({\n field,\n words,\n keepOffered,\n onAdd,\n onKeep,\n onCancel,\n busy,\n}: {\n field: Field;\n words: readonly string[];\n keepOffered: boolean;\n onAdd: () => void;\n onKeep: () => void;\n onCancel: () => void;\n busy?: boolean | undefined;\n}) {\n return (\n <span data-records-choice-ask=\"\" data-records-cell-note=\"\" role=\"group\" aria-label={choiceAskSentence(field, words)} className=\"flex flex-col gap-1\">\n <span className=\"text-[11px] leading-snug\">{choiceAskSentence(field, words)}</span>\n <span className=\"flex flex-wrap items-center gap-1\">\n <Button type=\"button\" size=\"sm\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onAdd}>\n Add\n </Button>\n {keepOffered ? (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onKeep}>\n Keep as typed\n </Button>\n ) : null}\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" disabled={busy ?? false} onClick={onCancel}>\n Cancel\n </Button>\n </span>\n </span>\n );\n}\n\n/** Kinds whose control is the record's own (a choice, a link, a person, a file, a worked-out value). */\nconst FORMAT_BLIND_KINDS = new Set([\"formula\", \"lookup\", \"rollup\", \"json\", \"checkbox\", \"select\", \"multi_select\", \"member\", \"entity_reference\", \"relation\", \"attachment\", \"datetime\"]);\n\nexport interface FieldEditorControlProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n /**\n * A GRID CELL'S PICKER OPENS AT ONCE (merged-grid review 2026-09-26, A2). One click on a selected\n * choice, multi-choice or person cell opens its list directly — no inline Save/Cancel form that\n * grows the row. Honoured by the choice and person pickers; every other control ignores it.\n */\n autoOpen?: boolean | undefined;\n /** The picker's list closed (a pick, Enter, Tab, a click away): the cell commits what is chosen. Escape is `onCancel`. */\n onClose?: (() => void) | undefined;\n /**\n * WHAT THE PERSON TYPED TO OPEN A GRID CELL'S PICKER (merged-grid review 2, A2 — Airtable): a\n * letter typed on a selected choice, multi-choice or person cell opens its list with that text\n * already in the search box. Honoured by the choice and person pickers.\n */\n initialSearch?: string | undefined;\n /** The control's own answer is final (a choice cell's Add / Keep as typed): commit it now. */\n onCommit?: (() => void) | undefined;\n /** The control's own Cancel: the cell goes back to what it held. */\n onCancel?: (() => void) | undefined;\n /**\n * The host saves a `ChoiceAddition` through `recordUpdateAddingChoices` (the grid). Without it\n * a choice control adds the words through `fieldUpdate`'s `options_add` and hands back words.\n */\n addsChoices?: boolean | undefined;\n /**\n * DRAWN AS A FORM QUESTION (lane VIEWS-AND-FIELDS W1-B item 3): a choice is answered from its\n * choices laid out — pills for a few, a searchable list for more (`ChoiceAnswer`) — never a\n * drop-down or a \"Choose\" button. Every other control ignores it.\n */\n asForm?: boolean | undefined;\n /** A FORM'S SINGLE CHOICE WAS PICKED (lane TYPEFORM-2): the runner may go on to the next question. */\n onChosen?: (() => void) | undefined;\n}\n\n/** The label row every editor shares: one line, the label, the unit, the required mark. */\nexport function FieldLabel({ field, htmlFor, children }: { field: Field; htmlFor: string; children?: ReactNode }) {\n return (\n <div className=\"flex items-baseline gap-1.5\">\n <Label htmlFor={htmlFor} className=\"text-xs font-medium\">\n {fieldName(field)}\n </Label>\n {field.required ? <span className=\"text-xs text-destructive\">required</span> : null}\n {/* A length of time reads as h:mm, so its stored unit (seconds) is not a word to show (P4). */}\n {field.unit && newerKindOf(field) !== \"duration\" ? <span className=\"text-xs text-muted-foreground\">{field.unit}</span> : null}\n {children}\n </div>\n );\n}\n\n\n/* ═══ A CELL OPENED BY TYPING (merged-grid cold review, 2026-09-26) ════════════════════════════════\n *\n * 🚨 THE DEFECT. A dispatcher selected a Visit date cell and typed `10/03/2026`; the store kept\n * **Jan 31, 0026**. The typed first character was DROPPED (a date was not a \"typed\" kind), the\n * editor opened on the stored value as the browser's segmented date control, and the rest of the\n * keystrokes landed in it one segment at a time — each half-typed segment a \"valid\" date. A\n * number cell had the same hazard: `-5` or `$50` dropped the first character and APPENDED the rest\n * to the value already in the box (100 → 10050). A choice cell handed the keystrokes to a closed\n * drop-down, whose type-ahead picked whatever option the SECOND letter matched.\n *\n * THE RULE (Google Sheets and Airtable): what a person types into a selected cell goes into a\n * plain TEXT box, whole; nothing is written until they commit; on commit the text is read by the\n * ONE typed-answer reader (`coerceTypedAnswer` — the same one a paste, a public form and an import\n * use), in the reader's locale; and anything it would have to guess is REFUSED with its sentence,\n * the box still holding what was typed. A kind whose value is not typed words (a linked record, a\n * person, a file, a document) and a tick box (one click or Space toggles it) are not opened by a\n * keystroke at all — Enter opens them.\n */\n\n/** A draft that is still the words a person typed, with the reader's verdict on them. */\nexport interface TypedDraft {\n readonly typedDraft: true;\n readonly text: string;\n /**\n * What the text reads as, why it is not a value, or — for a choice column — the question about\n * words that are not a choice yet. `null` while the column's choices (and the knob) load.\n */\n readonly judged: { value: unknown } | { refusal: string; why?: string; cancelOnly?: true } | { ask: ChoiceAsk } | null;\n /**\n * The words the cell OPENED with (Enter, a double-click, F2 — `draftForOpening`). Committing them\n * unchanged writes nothing: opening a cell and pressing Enter never rewrites what is stored.\n */\n readonly openedAs?: string | undefined;\n}\n\nexport function isTypedDraft(value: unknown): value is TypedDraft {\n return typeof value === \"object\" && value !== null && (value as { typedDraft?: unknown }).typedDraft === true;\n}\n\n/** Text kinds take the typed words as the value itself: a letter is a letter. */\nconst TYPED_AS_WORDS = new Set([\"text\", \"long_text\", \"phone\"]);\n/**\n * Kinds whose typed words are READ into a value on commit. A link and an email are read too\n * (review 2, A9): \"company.com\" is kept as https://company.com, and words that cannot be an email\n * say what one looks like — before anything reaches the store.\n */\nconst TYPED_AND_READ = new Set([\"number\", \"currency\", \"percent\", \"datetime\", \"select\", \"multi_select\", \"email\", \"url\"]);\n\n/**\n * What a keystroke on a selected cell does to THIS column: `\"words\"` — the text is the value;\n * `\"read\"` — the text is read on commit; `\"search\"` — the column's picker opens with the text as\n * its search (a choice, a multi-choice, a person: Airtable); `\"none\"` — typing does not open it.\n */\nexport function typingOpens(field: Field): \"words\" | \"read\" | \"search\" | \"none\" {\n if (isButtonField(field)) return \"none\";\n const kind = String(editorKindFor(field));\n if (kind === \"formula\" || kind === \"lookup\" || kind === \"rollup\") return \"none\";\n if (kind === \"select\" || kind === \"multi_select\" || kind === \"member\") return \"search\";\n const format = formatForField(field);\n if (format && format.id === \"time\") return \"read\";\n if (format && format.id === \"rating\") return \"read\";\n if (TYPED_AS_WORDS.has(kind)) return \"words\";\n if (TYPED_AND_READ.has(kind)) return \"read\";\n return \"none\";\n}\n\n/**\n * The reader's verdict on typed text for this column (choices: when they are known; `nudge`: the\n * `custom/choice_nudge` knob, `null` while it is asked, absent meaning its default `ask`).\n */\n/** The few words a cell says when what was typed cannot be an email, a link or a phone number. */\nexport const SHORT_REFUSAL = {\n email: \"Enter a valid email\",\n url: \"Enter a valid link\",\n phone: \"Enter a valid phone number\",\n time: \"Enter a time, like 2:30 PM\",\n date: \"Enter a date\",\n number: \"Enter a number\",\n value: \"Not a valid value\",\n} as const;\n\nexport function judgeTyped(field: Field, text: string, choices?: StoredRecord[] | null, nudge?: ChoiceNudge | null): TypedDraft[\"judged\"] {\n const trimmed = text.trim();\n const kind = String(editorKindFor(field));\n const format = formatForField(field);\n if (trimmed === \"\") return { value: null };\n if (format && format.id === \"time\") {\n // THE ONE TIME READER (`@ai-matrx/records` `readTypedTime`): `1200PM`, `12pm`, `9:30a`, `0930`\n // are all read; a bare `9` (morning or evening?) is refused with the way to write it.\n const read = readTypedTime(trimmed);\n return read.ok ? { value: read.value } : { refusal: SHORT_REFUSAL.time, why: `${fieldName(field)} holds a time of day, and ${read.why}` };\n }\n if (kind === \"select\" || kind === \"multi_select\") {\n if (!choices || nudge === null) return null;\n const several = field.multi || kind === \"multi_select\";\n const words = several ? trimmed.split(/\\s*[,;\\n]\\s*/).filter(Boolean) : [trimmed];\n const allowOther = allowsOtherValues(field);\n // ONE DECISION PER WORD, from the one helper every surface uses.\n const parts: string[] = [];\n const add: string[] = [];\n const ask: string[] = [];\n const notChoices: string[] = [];\n let keepOffered = allowOther;\n for (const word of words) {\n const decided = decideTypedChoice({ words: word, options: choices, allowOther, nudge });\n if (decided.decision === \"empty\") continue;\n if (decided.decision === \"chosen\") parts.push(decided.key);\n else {\n parts.push(decided.words);\n if (decided.decision === \"add\") add.push(decided.words);\n else if (decided.decision === \"ask\") {\n ask.push(decided.words);\n keepOffered = keepOffered && decided.keepOffered;\n } else if (decided.decision === \"not_a_choice\") notChoices.push(decided.words);\n }\n }\n const valueOf = (list: string[]) => (several ? list : (list[0] ?? null));\n if (notChoices.length > 0) return { refusal: notAChoiceSentence(field, notChoices), cancelOnly: true };\n if (ask.length > 0) {\n return {\n ask: { words: ask, keepOffered, onAdd: choiceAddition(valueOf(parts), [...add, ...ask]), asTyped: valueOf(parts) },\n };\n }\n if (add.length > 0) return { value: choiceAddition(valueOf(parts), add) };\n return { value: valueOf(parts) };\n }\n if (format && (format.id === \"rating\")) {\n const n = Number(trimmed);\n const max = format.options?.ratingMax ?? 5;\n return Number.isInteger(n) && n >= 0 && n <= max\n ? { value: n === 0 ? null : n }\n : { refusal: `Enter 1 to ${max}`, why: `${fieldName(field)} is a rating from 1 to ${max}.` };\n }\n // A PHONE NUMBER IS READ TOO (lane CELL-EDITORS, night walk 2026-10-06): any words used to be saved.\n // Digits with the usual marks (+, spaces, dashes, dots, brackets, an extension) and 7 to 15 digits.\n if (kind === \"phone\" || (format && format.id === \"phone\")) {\n const digits = trimmed.replace(/\\D/g, \"\");\n const usual = /^\\+?[\\d\\s().-]+(\\s*(x|ext\\.?)\\s*\\d+)?$/i.test(trimmed);\n return usual && digits.length >= 7 && digits.length <= 20 ? { value: trimmed } : { refusal: SHORT_REFUSAL.phone };\n }\n const showsAsPercent = Boolean(format && (format.id === \"percent\" || format.id === \"progress\"));\n const read = coerceTypedAnswer(field as never, text, { label: fieldName(field), showsAsPercent });\n // A CELL HAS NO ROOM FOR A PARAGRAPH (interface-text rules): an email or a link that cannot be one is\n // said in a few words, never echoing what was typed — the box beside it already shows that.\n // EVERY TYPED REFUSAL IS A SHORT LABEL (REVIEW-FIX 9, interface-text): \"Enter a date\", never the\n // reader's paragraph; the full reason rides the note's tooltip (`why`).\n if (\"refusal\" in read) {\n if (kind === \"email\" || kind === \"url\") return { refusal: SHORT_REFUSAL[kind] };\n const short =\n kind === \"datetime\" ? SHORT_REFUSAL.date : kind === \"number\" || kind === \"currency\" || kind === \"percent\" || showsAsPercent ? SHORT_REFUSAL.number : read.refusal.length <= 32 ? read.refusal : SHORT_REFUSAL.value;\n return short === read.refusal ? { refusal: short } : { refusal: short, why: read.refusal };\n }\n // A percent kept as a fraction is typed as the percent a person reads.\n if (typeof read.value === \"number\" && format && (format.id === \"percent\" || format.id === \"progress\") && format.options?.percentScale === \"fraction\") {\n return { value: Math.round((read.value / 100) * 1e9) / 1e9 };\n }\n return { value: read.value };\n}\n\n/**\n * WHICH HELPER SITS BESIDE A TYPED BOX: a calendar for a date, a calendar and a list of times for a\n * moment, a list of times for a time of day — or none. `value` is the stored value, when there is one.\n */\nexport function dateHelperKind(field: Field, value?: unknown): DateHelperKind | null {\n const format = formatForField(field);\n if (format && format.id === \"time\") return \"time\";\n if (String(editorKindFor(field)) !== \"datetime\") return null;\n return String(field.config?.[\"kind\"] ?? \"\") === \"datetime\" || carriesTimeOfDay(field, value) ? \"datetime\" : \"date\";\n}\n\n/** The words a stored value opens as in its column's typed box — the words the reader reads back to it. */\nexport function openingText(field: Field, value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"\";\n const helper = dateHelperKind(field, value);\n if (helper === \"time\") {\n const read = readTypedTime(String(value));\n if (!read.ok) return String(value);\n const [h, m] = read.value.split(\":\").map(Number);\n return typedTimeText(h!, m!);\n }\n if (helper) return typedDateText(value, { withTime: helper === \"datetime\" });\n const format = formatForField(field);\n return format ? typedText(format, value) : String(value);\n}\n\n/** Kinds whose Enter / double-click / F2 editor is the typed box too — never the browser's own control. */\nconst OPENS_AS_TYPED_TEXT = new Set([\"datetime\", \"number\", \"currency\", \"percent\"]);\n\n/**\n * 🚨 THE DRAFT A CELL OPENS WITH BY ENTER, A DOUBLE-CLICK OR F2 (grids review 3, 2026-09-30, a\n * BLOCKER). A date, a time or a date-and-time column opened the browser's own picker, which lost a\n * typed time and saved \"now\"; a money column's own box dropped a typed percent sign. Every way into\n * these columns is now the SAME typed box a keystroke opens, holding the stored value's words and\n * read once on commit. `undefined` for every other column (it keeps its own control).\n */\nexport function draftForOpening(field: Field, current: unknown): TypedDraft | undefined {\n const format = formatForField(field);\n if (format && format.id === \"rating\") return undefined;\n const opens = (format && format.id === \"time\") || OPENS_AS_TYPED_TEXT.has(String(editorKindFor(field)));\n if (!opens) return undefined;\n const text = openingText(field, current);\n return { typedDraft: true, text, judged: judgeTyped(field, text), openedAs: text };\n}\n\n/**\n * THE DRAFT A KEYSTROKE OPENS A CELL WITH — or `undefined` when typing does not open this column.\n * A text column takes the typed words as its value; every other typed column holds a TypedDraft.\n */\nexport function draftFromTyping(field: Field, seed: string): string | TypedDraft | undefined {\n const opens = typingOpens(field);\n if (opens === \"none\") return undefined;\n if (opens === \"words\") return seed;\n return { typedDraft: true, text: seed, judged: judgeTyped(field, seed) };\n}\n\n/**\n * \"Reads as …\" EARNS ITS PLACE (interface-text): it floats over the cell only when it tells the person\n * something the box does not. Typed \"9/5/2026\" it would repeat the box, so it is not drawn; typed\n * \"Sep 5 2026\" or \"12.5\" for a money column, what it reads as is news. `always`: an addition to a\n * list of choices is always said. Keyed by the typed words, so it is measured again as they change.\n */\nfunction ReadsAsNote({ typed, always, children }: { typed: string; always: boolean; children: ReactNode }) {\n const note = useRef<HTMLSpanElement | null>(null);\n const [repeats, setRepeats] = useState(false);\n useLayoutEffect(() => {\n if (always) return;\n const words = (t: string | null | undefined) => (t ?? \"\").replace(/^Reads as/, \"\").replace(/\\s+/g, \"\").toLowerCase();\n setRepeats(words(note.current?.textContent) === words(typed));\n }, [typed, always]);\n if (repeats) return null;\n return (\n <span ref={note} data-records-typed-reads-as=\"\" data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">\n {children}\n </span>\n );\n}\n\n/** The box a typed draft is edited in: the words, and what they read as — or why they are not a value. */\nfunction TypedTextControl({ field, value, onChange, disabled, id, onCommit, onCancel }: FieldEditorControlProps & { value: TypedDraft }) {\n const client = useOptionalRecordsClient();\n const kind = String(editorKindFor(field));\n const needsChoices = kind === \"select\" || kind === \"multi_select\";\n const nudge = useChoiceNudge(needsChoices);\n const [choices, setChoices] = useState<StoredRecord[] | null>(null);\n useEffect(() => {\n if (!needsChoices || !client) return;\n let cancelled = false;\n void fieldOptionsOnce(client, field.id).then((result) => {\n if (!cancelled) setChoices(result.ok ? inTheStoresOrder(result.data ?? []) : []);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, needsChoices]);\n // The verdict on what is ALREADY in the box once the choices (and the knob) arrive.\n useEffect(() => {\n if (choices && nudge && value.judged === null) onChange({ ...value, judged: judgeTyped(field, value.text, choices, nudge) });\n }, [choices, nudge, value, field, onChange]);\n const judged = value.judged;\n const format = formatForField(field);\n const helper = dateHelperKind(field);\n const retype = (text: string) =>\n onChange({\n typedDraft: true,\n text,\n judged: judgeTyped(field, text, needsChoices ? choices : undefined, needsChoices ? nudge : undefined),\n ...(value.openedAs !== undefined ? { openedAs: value.openedAs } : {}),\n });\n const box = (\n <BasicInput\n id={id}\n value={value.text}\n disabled={disabled}\n autoComplete=\"off\"\n aria-label={fieldName(field)}\n aria-invalid={judged !== null && \"refusal\" in judged ? true : undefined}\n onChange={(e) => retype(e.target.value)}\n />\n );\n return (\n <span className=\"flex flex-col gap-0.5\">\n {helper && !disabled ? (\n <span className=\"flex min-w-0 items-center gap-0.5\">\n {box}\n <TypedDateHelper kind={helper} text={value.text} onText={retype} label={fieldName(field)} onPicked={onCommit} startOpen={value.openedAs !== undefined} />\n </span>\n ) : (\n box\n )}\n {judged === null ? (\n <span data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">Reading {fieldName(field)}'s choices…</span>\n ) : \"ask\" in judged ? (\n <ChoiceAskButtons\n field={field}\n words={judged.ask.words}\n keepOffered={judged.ask.keepOffered}\n onAdd={() => {\n onChange({ ...value, judged: { value: judged.ask.onAdd } });\n onCommit?.();\n }}\n onKeep={() => {\n onChange({ ...value, judged: { value: judged.ask.asTyped } });\n onCommit?.();\n }}\n onCancel={() => onCancel?.()}\n />\n ) : \"refusal\" in judged ? (\n <>\n <FloatingRefusal text={judged.refusal} why={\"why\" in judged ? judged.why : undefined} />\n {judged.cancelOnly && onCancel ? (\n <span data-records-cell-note=\"\" data-records-choice-ask=\"\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" onClick={() => onCancel()}>\n Cancel\n </Button>\n </span>\n ) : null}\n </>\n ) : judged.value === null || judged.value === undefined ? null : (\n <ReadsAsNote key={value.text} typed={value.text} always={isChoiceAddition(judged.value)}>\n {isChoiceAddition(judged.value) ? `Adds ${quoted(judged.value.add)} to the choices for ${fieldName(field)}. ` : null}\n Reads as{\" \"}\n {needsChoices ? (\n String(\n (Array.isArray(withoutAddition(judged.value).value) ? (withoutAddition(judged.value).value as unknown[]) : [withoutAddition(judged.value).value])\n .map((k) => {\n const option = choices?.find((o) => optionKey(o) === k);\n return option ? recordName(option.data as RecordDocument | undefined, null, String(k)) : String(k);\n })\n .join(\", \"),\n )\n ) : (\n (() => {\n const shown = format ?? (kind === \"datetime\" ? { id: carriesTimeOfDay(field, judged.value) ? \"datetime\" : \"date\" } : undefined);\n return shown ? <FormattedValue value={judged.value} format={shown} /> : String(judged.value);\n })()\n )}\n </ReadsAsNote>\n )}\n </span>\n );\n}\n\n/** A column that holds the person's own name (\"Name\", \"Full name\", \"Your name\"). */\nfunction isPersonsName(field: Field): boolean {\n const words = `${field.key} ${field.label ?? \"\"}`.toLowerCase();\n return /(^|[\\s_])(full[\\s_]?)?name(\\s|$)/.test(words) && !/(therapist|doctor|physician|company|business|pet|room)/.test(words);\n}\n\nexport function FieldControl({ field, value, onChange, disabled, id, autoOpen, onClose, onCommit, onCancel, addsChoices, initialSearch, asForm, onChosen }: FieldEditorControlProps) {\n const host = useRecordsUi();\n const kind = editorKindFor(field);\n const inputId = id ?? `field-${field.key}`;\n // A STRANGER'S OWN PAGE FILLS HER OWN DETAILS (lane HANDOVER, 2026-09-28). A public form or\n // booking page has no records client (nobody is signed in), and there the browser may offer the\n // person's own name, email and phone. In a signed-in grid or record form it never does: the\n // cell holds somebody else's email, and the browser's suggestions would be her own.\n const ownDetails = useOptionalRecordsClient() === null;\n\n // A CELL OPENED BY TYPING edits the typed words, whatever the column's own control is.\n if (isTypedDraft(value)) return <TypedTextControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} onCommit={onCommit} onCancel={onCancel} />;\n\n // A SIGNATURE IS DRAWN, never typed (lane 10 W1-A): the one pad, in every form, record panel\n // and grid editor that asks for this column (`signature.tsx`).\n if (isSignatureField(field)) return <SignaturePad id={inputId} value={value} onChange={onChange} disabled={disabled} />;\n\n // THE NEWER KINDS (lane 10 P4): a length of time typed as 45 min, an address in its parts, a\n // barcode typed or photographed; who made it and a count are shown, never typed.\n // NOTION-PROPS-3: a button has no control — it holds no value (a form leaves it out; a record page presses it).\n if (isButtonField(field)) return <ButtonValue field={field} />;\n const newerControl = newerKindControl({ field, value, onChange, disabled, id: inputId });\n if (newerControl !== undefined) return newerControl;\n\n // THE COLUMN'S OWN FORMAT EDITS ITS VALUE (merge tranche 6e): stars for a rating, a percent\n // typed as a percent whatever scale it is kept in, money typed with its symbol and commas.\n // A format with no opinion about its input falls through to the kind's own control below.\n const format = formatForField(field);\n // A TIME OF DAY IS TYPED WORDS AND A HELPER, NEVER THE BROWSER'S TIME CONTROL (grids review 3).\n if (format && format.id === \"time\") return <TypedWordsControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n if (format && !FORMAT_BLIND_KINDS.has(String(kind))) {\n const own = formatControl({ format, value, onChange, disabled, id: inputId, label: fieldName(field), ownDetails });\n if (own) return own;\n }\n\n switch (kind) {\n case \"formula\":\n case \"lookup\":\n case \"rollup\":\n return (\n <div id={inputId} className=\"rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground\">\n {/* The store's own sentence for typing into a computed field. */}\n {value === null || value === undefined ? \"—\" : String(value)}\n <span className=\"ml-2 italic\">\n {fieldName(field)} is worked out by the system, so it cannot be typed in\n </span>\n </div>\n );\n case \"json\":\n return <JsonControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"long_text\":\n return (\n <BasicTextarea\n id={inputId}\n rows={3}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n case \"number\":\n case \"currency\":\n case \"percent\":\n return (\n <BasicInput\n id={inputId}\n type=\"number\"\n inputMode=\"decimal\"\n className=\"tabular-nums\"\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : Number(e.target.value))}\n />\n );\n case \"datetime\":\n // A TYPED BOX AND A HELPER, NEVER THE BROWSER'S PICKER (grids review 3): the record form,\n // a public form and a bulk change read what is typed through the one date reader.\n return <TypedWordsControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"email\":\n case \"phone\":\n case \"url\":\n return (\n <BasicInput\n id={inputId}\n type={kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\"}\n // THE RIGHT KEYBOARD (lane TYPEFORM-2): @ on the email keyboard, the dial pad for a phone, / and .com for a link.\n inputMode={kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\"}\n {...(ownDetails ? { autoComplete: kind === \"email\" ? \"email\" : kind === \"phone\" ? \"tel\" : \"url\" } : {})}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n case \"checkbox\":\n return <CheckboxControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"select\":\n case \"multi_select\":\n return <OptionControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} addsChoices={addsChoices} initialSearch={initialSearch} asForm={asForm} onChosen={onChosen} />;\n case \"member\":\n // A person field asks who is in the organization, never what is in a\n // Table — see PersonPicker's header for the screen that made this split.\n return <PersonPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} initialSearch={initialSearch} />;\n case \"entity_reference\":\n // SC-R: a note, a web site, an agent … — chips of what it names, never a text box.\n return <EntityReferenceControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"attachment\":\n // A FILE COMES FROM THE HOST'S FILE WINDOW OR AN UPLOAD (`gridAttachments.tsx`), never from a\n // list of the kernel File Table's rows. A host with neither port keeps the relation picker.\n if (hostTakesFiles(host)) {\n return <AttachmentControl field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} autoOpen={autoOpen} onClose={onClose} />;\n }\n return <RelationPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} />;\n case \"relation\":\n return <RelationPicker field={field} value={value} onChange={onChange} disabled={disabled} id={inputId} onPicked={onCommit} autoOpen={autoOpen} onClose={onClose} onCancel={onCancel} />;\n default:\n if (typeof value === \"boolean\" || field.config?.[\"kind\"] === \"boolean\") {\n return (\n <Checkbox\n id={inputId}\n checked={value === true}\n disabled={disabled}\n onCheckedChange={(next) => onChange(next === true)}\n />\n );\n }\n return (\n <BasicInput\n id={inputId}\n {...(ownDetails && isPersonsName(field) ? { autoComplete: \"name\" } : {})}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n );\n }\n}\n\n/**\n * A DATE, A TIME OR A MOMENT OUTSIDE A GRID CELL (the record form, a public form, a bulk change):\n * the same typed box and helper a cell opens, for a host that holds plain VALUES. The words are read\n * on every keystroke and the value is handed over the moment they read; words that do not read keep\n * their sentence under the box, the value stays what it was, and leaving the box puts the words back\n * to that value — so what the box shows is always what will be saved.\n */\nexport function TypedWordsControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const [text, setText] = useState(() => openingText(field, value));\n const [refusal, setRefusal] = useState<string | null>(null);\n const [why, setWhy] = useState<string | undefined>(undefined);\n const sent = useRef<unknown>(value);\n // A value that moves under the box (a reload, another control) is shown — unless it is what was just read.\n useEffect(() => {\n if (value === sent.current) return;\n sent.current = value;\n setText(openingText(field, value));\n setRefusal(null);\n }, [value, field]);\n const helper = dateHelperKind(field, value);\n const retype = (next: string) => {\n setText(next);\n const judged = judgeTyped(field, next);\n if (judged && \"value\" in judged) {\n setRefusal(null);\n sent.current = judged.value;\n onChange(judged.value);\n } else if (judged && \"refusal\" in judged) {\n setRefusal(judged.refusal);\n setWhy(\"why\" in judged ? judged.why : undefined);\n }\n };\n return (\n <span className=\"flex flex-col gap-0.5\">\n <span className=\"flex min-w-0 items-center gap-0.5\">\n <BasicInput\n id={id}\n value={text}\n disabled={disabled}\n autoComplete=\"off\"\n aria-invalid={refusal ? true : undefined}\n placeholder={helper ? typedDatePlaceholder(helper) : undefined}\n onChange={(e) => retype(e.target.value)}\n onBlur={() => {\n if (!refusal) return;\n setText(openingText(field, sent.current));\n setRefusal(null);\n }}\n />\n {helper && !disabled ? <TypedDateHelper kind={helper} text={text} onText={retype} label={fieldName(field)} /> : null}\n </span>\n {refusal ? <FloatingRefusal text={refusal} why={why} /> : null}\n </span>\n );\n}\n\n/**\n * WHAT AN EMPTY DATE BOX SHOWS: the SHAPE to type, never a date (WALK3-FIX, 2026-10-07). It showed\n * \"10/03/2026 2:30 PM\" — a real-looking day — and on 10/07 a person read it as a stale default\n * prefilled into Cleanings' Appointment Date. The pattern follows the locale's own order.\n */\nexport function typedDatePlaceholder(helper: \"date\" | \"datetime\" | \"time\" | string): string {\n const time = \"h:mm AM\";\n if (helper === \"time\") return time;\n const pattern = typedDateText(\"2026-11-22\").replace(\"2026\", \"YYYY\").replace(\"11\", \"MM\").replace(\"22\", \"DD\");\n return helper === \"datetime\" ? `${pattern} ${time}` : pattern;\n}\n\n/**\n * A TICK BOX, WITH ITS THIRD STATE SAID OUT LOUD.\n *\n * LIMITS-FIX 2026-09-21. `checkbox` is the store's fourteenth parity type and it holds a\n * REAL boolean — but a record nobody has answered holds NO VALUE AT ALL, and that is a\n * different fact from `false`. An unticked box cannot show the difference, so this control\n * draws the box AND, while the answer is missing, the word \"not answered yet\" beside it\n * with the way to keep it that way. Ticking writes `true`, unticking writes `false`, and\n * \"Clear\" puts the record back to never having said — which no plain checkbox can do.\n */\nfunction CheckboxControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const unanswered = value === null || value === undefined;\n return (\n <div className=\"flex items-center gap-2\">\n <Checkbox\n id={id}\n checked={value === true}\n disabled={disabled}\n aria-label={fieldName(field)}\n onCheckedChange={(next) => onChange(next === true)}\n />\n {unanswered ? (\n <span className=\"text-xs italic text-muted-foreground\">not answered yet</span>\n ) : (\n <>\n <span className=\"text-xs text-muted-foreground\">{value === true ? \"Yes\" : \"No\"}</span>\n {field.required ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-5 px-1 text-[10px]\"\n disabled={disabled}\n onClick={() => onChange(null)}\n >\n Clear\n </Button>\n )}\n </>\n )}\n </div>\n );\n}\n\n/**\n * A document-shaped value, edited as the text it is. It is parsed on every\n * keystroke and the PARSE FAILURE IS SHOWN — a box that silently handed the\n * store unparseable text and let it answer `22P02 invalid input syntax` is a\n * refusal the person could have been spared half a second earlier.\n */\nfunction JsonControl({ field, value, onChange, disabled, id }: FieldEditorControlProps) {\n const initial = value === null || value === undefined ? \"\" : typeof value === \"string\" ? value : JSON.stringify(value, null, 2);\n const [text, setText] = useState(initial);\n const [broken, setBroken] = useState<RecordsError | null>(null);\n return (\n <div className=\"flex flex-col gap-1\">\n <BasicTextarea\n id={id}\n rows={4}\n className=\"font-mono text-[11px]\"\n value={text}\n disabled={disabled}\n onChange={(e) => {\n const next = e.target.value;\n setText(next);\n if (next.trim() === \"\") {\n setBroken(null);\n onChange(null);\n return;\n }\n try {\n onChange(JSON.parse(next));\n setBroken(null);\n } catch (thrown) {\n // The parser's own words (\"Unexpected token } in JSON at position 14\")\n // are an engineer's: they go out of sight, the person reads a sentence.\n setBroken(\n refusalFromThrown(\n thrown,\n `${fieldName(field)} is not readable as structured data yet.`,\n \"Fix the text so it reads as structured data, or discard it to put back what was there.\",\n \"invalid_argument\",\n ),\n );\n }\n }}\n />\n {broken ? (\n // The typed text is still in the box: the notice owns the two doors out. In a grid cell it\n // floats over the table (`data-records-cell-note`), so the row never grows.\n <span data-records-cell-note=\"\" className=\"block\">\n <RefusalNotice\n error={broken}\n onKeepEditing={() => (id ? document.getElementById(id)?.focus() : undefined)}\n onDiscard={() => {\n setText(initial);\n setBroken(null);\n }}\n />\n </span>\n ) : null}\n </div>\n );\n}\n\n/**\n * THE ORDER THE STORE KEEPS (STORE-RULE-GAPS). Every option carries the position it was\n * declared at in `metadata.option_position` — the list as a person wrote it, and a choice\n * added by typing goes LAST, where the store put it. `custom.field_options` answers in no\n * particular order, so this control orders by that position (a row with none after those\n * that have one, then by when it was made) instead of drawing whatever order came back.\n */\nexport function inTheStoresOrder(options: StoredRecord[]): StoredRecord[] {\n const position = (o: StoredRecord): number => {\n const raw = (o as { metadata?: Record<string, unknown> | null }).metadata?.[\"option_position\"];\n const n = typeof raw === \"number\" ? raw : typeof raw === \"string\" ? Number(raw) : Number.NaN;\n return Number.isFinite(n) ? n : Number.POSITIVE_INFINITY;\n };\n const made = (o: StoredRecord): string => String((o as { created_at?: unknown }).created_at ?? \"\");\n return [...options].sort((a, b) => position(a) - position(b) || made(a).localeCompare(made(b)));\n}\n\n/**\n * FLD-5 / FLD-6. A pick-list IS a Table and an option is a Record of it — that part is\n * unchanged. What a CELL holds is the option's own stable WORD (its key), not the\n * option record's uuid, so renaming a choice rewrites no row; the read doors hand\n * back the LABEL and name the key beside it in `_choices`. This control therefore\n * recognises all three ways of naming the same choice — `isTheChosen` — and WRITES\n * the key, which is the contract. The options are read through the store's own\n * `custom.field_options` door, which resolves the options Table from the Field's\n * config — this component never has to know which Table that is.\n */\nfunction OptionControl({ field, value, onChange, disabled, id, autoOpen, onClose, onCancel, addsChoices, initialSearch, asForm, onChosen }: FieldEditorControlProps) {\n // NOT `useRecordsClient`. A drop-down is the commonest question on a public\n // form, and this control asked the hook that THROWS for a client the public\n // arm of `FormRunner` deliberately never mounts — so a stranger opening a\n // form with one choice question got HTTP 500 (VERIFIER-10, F1).\n const client = useOptionalRecordsClient();\n const [options, setOptions] = useState<StoredRecord[] | null>(null);\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n /** Bumped when this control added a choice, so the list is read again. */\n const [reread, setReread] = useState(0);\n\n useEffect(() => {\n if (!client) return;\n let cancelled = false;\n void fieldOptionsOnce(client, field.id).then((result) => {\n if (cancelled) return;\n if (result.ok) setOptions(inTheStoresOrder(result.data ?? []));\n else setRefusal(result.error);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, reread]);\n\n // EVERY STATE CARRIES THE CELL'S OWN ID. A cell that identified itself only\n // when it happened to be a text box is a cell nobody can tell apart from the\n // developer window that used to open instead of it.\n // A PUBLIC PAGE CARRIES THE CHOICES IT ASKS (lane HANDOVER, 2026-09-28): the form and booking\n // doors hand each choice question its live choices' labels as `public_choices`, so a stranger\n // picks \"Follow-up\" instead of typing a word the owner then has to match up.\n const handed = publicChoicesOf(field);\n if (!client && handed.length > 0) {\n // A public page IS a form: its choices are laid out in their own colours (`ChoiceAnswer`).\n return <ChoiceAnswer field={field} choices={handed} value={value} onChange={onChange} disabled={disabled} id={id} onChosen={onChosen} />;\n }\n if (!client) {\n // ABSENT AND HONEST. The choices of a field live in the owner's own data,\n // and a page answered without an account may not read it — so the question\n // says what it is and takes the answer as text rather than drawing an empty\n // drop-down or taking the page down.\n return (\n <div className=\"flex flex-col gap-1\">\n <BasicInput\n id={id}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n {/* The Field's own name is printed above by `FieldLabel`; saying it\n again here is how the screen read \"Service typeService type is…\". */}\n <p className=\"text-xs text-muted-foreground\">\n This is normally picked from a list. A page answered without an account cannot read that\n list, so type your answer and whoever receives it will match it up.\n </p>\n </div>\n );\n }\n if (refusal)\n return (\n <div id={id}>\n <RefusalLine error={refusal} />\n </div>\n );\n if (!options) return <p id={id} className=\"text-xs text-muted-foreground\">Reading this field's choices…</p>;\n if (asForm && options.length > 0) {\n const titled = (option: StoredRecord) => recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n return (\n <ChoiceAnswer\n field={field}\n choices={options.map((option) => ({ key: optionKey(option), label: titled(option) }))}\n value={value}\n onChange={onChange}\n disabled={disabled}\n id={id}\n onChosen={onChosen}\n isChosen={(choice, v) => {\n const option = options.find((o) => optionKey(o) === choice.key);\n return option ? isTheChosen(option, v) : false;\n }}\n />\n );\n }\n // ONE PICKER FOR EVERY CHOICE COLUMN (lane CHOICE-TAILS, 2026-09-27). A column that takes other\n // values and one that takes only its own choices draw the same combobox: search the choices,\n // pick one, or type a word that is none of them and be asked (Add / Keep as typed only where\n // the column takes other values / Cancel), exactly as a grid cell asks. The record form used to\n // draw a closed drop-down for a closed column, so a person filling in a record had no way to\n // add the word they needed. Outside a grid cell (the record form, the form runner) there is no\n // `autoOpen`, so the list opens on a press; in a grid cell it opens at once and closing it commits.\n // A GRID CELL IS NO EXCEPTION (merged-grid review 2, A2): its list used to be a plain drop-down\n // with no search, so Enter opened a list a person could not type into. Every choice cell now\n // opens THIS picker — search, arrows, Enter picks, Escape closes.\n if (CHOICE_EDITOR_ADDS_WHAT_IS_TYPED) {\n return (\n <OpenChoicePicker\n field={field}\n options={options}\n value={value}\n onChange={onChange}\n disabled={disabled}\n id={id}\n autoOpen={autoOpen}\n onClose={onClose}\n onCancel={onCancel}\n initialSearch={initialSearch}\n addsChoices={addsChoices}\n allowOther={allowsOtherValues(field)}\n onChoicesChanged={() => {\n // The kept answer is stale now: the next read asks the store.\n if (client) forgetAsked(client, `field_options:${field.id}`);\n setReread((n) => n + 1);\n }}\n />\n );\n }\n if (options.length === 0) {\n // Two different facts, and a person acts on them differently: a choice\n // field whose Table is empty, and a choice field that names no Table at\n // all. One blank control for both is the silent failure.\n return (\n <p id={id} className=\"text-xs text-muted-foreground\">\n {field.options_table_id\n ? `${fieldName(field)} takes its choices from a Table that has no records yet — add the choices there and they appear here.`\n : `${fieldName(field)} does not name the Table its choices come from yet, so there is nothing to choose. A table admin sets it in the field editor.`}\n </p>\n );\n }\n\n const titleOf = (option: StoredRecord) =>\n recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n\n if (field.multi) {\n // WHAT IS PICKED, however the value says it. The document a read door hands this\n // control carries LABELS; the row holds KEYS; a screen written before this contract\n // sends IDS. `isTheChosen` knows all three, and what goes back is always the key.\n const chosen = options.filter((option) => choiceValuesOf(value).some((v) => isTheChosen(option, v)));\n const picked = new Set(chosen.map((option) => optionKey(option)));\n const toggles = (\n <div id={autoOpen ? undefined : id} className=\"flex flex-wrap gap-1\">\n {options.map((option) => (\n <Button\n key={option.id}\n type=\"button\"\n size=\"sm\"\n variant={picked.has(optionKey(option)) ? \"default\" : \"outline\"}\n disabled={disabled}\n onClick={() => {\n const next = new Set(picked);\n if (next.has(optionKey(option))) next.delete(optionKey(option));\n else next.add(optionKey(option));\n onChange(next.size === 0 ? null : [...next]);\n }}\n >\n {titleOf(option)}\n </Button>\n ))}\n </div>\n );\n if (!autoOpen) return toggles;\n // IN A GRID CELL: the list floats over the grid (portalled), so the row never grows; the cell\n // commits what is ticked when the list closes.\n return (\n <Popover\n defaultOpen\n onOpenChange={(open) => {\n if (!open) onClose?.();\n }}\n >\n <PopoverTrigger asChild>\n <Button id={id} type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 max-w-full truncate\">\n {chosen.length === 0 ? \"Choose\" : chosen.map(titleOf).join(\", \")}\n </Button>\n </PopoverTrigger>\n <PopoverContent sizing=\"content\" className=\"max-w-[20rem] p-2\" align=\"start\">\n {toggles}\n </PopoverContent>\n </Popover>\n );\n }\n\n // The SINGLE choice, the same way: what is selected is worked out from the option, not\n // from a string comparison against whatever spelling the document happened to use, and\n // what goes back is the key.\n const current = options.find((option) => isTheChosen(option, value));\n return (\n <Select\n value={current ? optionKey(current) : \"\"}\n disabled={disabled ?? false}\n onValueChange={(next) => onChange(next === \"\" ? null : next)}\n {...(autoOpen\n ? {\n // IN A GRID CELL the list opens at once and a pick is the commit (Airtable).\n defaultOpen: true,\n onOpenChange: (open: boolean) => {\n if (!open) onClose?.();\n },\n }\n : {})}\n >\n <SelectTrigger id={id} size=\"sm\">\n <SelectValue placeholder=\"Choose\" />\n </SelectTrigger>\n <SelectContent>\n {options.map((option) => (\n <SelectItem key={option.id} value={optionKey(option)}>\n {titleOf(option)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\n/**\n * A CHOICE COLUMN THAT TAKES OTHER VALUES (STORE-RULE-GAPS). The relation picker's shape —\n * a search box over the choices and a line at the foot for words that are not one of them.\n * What that line does is `decideTypedChoice` with the `custom/choice_nudge` knob: ask (Add /\n * Keep as typed / Cancel), add without asking, or keep as typed. Add REALLY adds (see\n * `ChoiceAddition` above); Keep as typed sends the words and the store keeps them as an other\n * value. A word that already names a choice (by key or label, any case) is that choice.\n */\nfunction OpenChoicePicker({\n field,\n options,\n value,\n onChange,\n disabled,\n id,\n addsChoices,\n autoOpen,\n onClose,\n onCancel,\n initialSearch,\n allowOther = true,\n onChoicesChanged,\n}: FieldEditorControlProps & { options: StoredRecord[]; allowOther?: boolean; onChoicesChanged: () => void }) {\n const client = useOptionalRecordsClient();\n const nudge = useChoiceNudge();\n // IN A GRID CELL the list is open from the start and closing it is the cell's commit.\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n const [search, setSearch] = useState(initialSearch ?? \"\");\n const [adding, setAdding] = useState(false);\n const [addRefused, setAddRefused] = useState<RecordsError | null>(null);\n const titleOf = (option: StoredRecord) =>\n recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n const held = withoutAddition(value);\n const current = choiceValuesOf(held.value);\n const pickedWords = current.map((v) => {\n const option = options.find((o) => isTheChosen(o, v));\n return option ? titleOf(option) : String(v);\n });\n // A CHOICE WEARS ITS OWN COLOUR HERE TOO (W1-B item 2): the picked chip and every option in the\n // list are the chip the grid cell draws (`choiceChipLookOf`), never the theme's accent.\n const chipOf = (option: StoredRecord | undefined, word: string) =>\n option ? choiceChipLookOf(field, optionKey(option), titleOf(option)) : choiceChipLookOf(field, word);\n const q = search.trim();\n // THE ONE RANKING (`@ai-matrx/records` `rankTypedMatches`, grids review 3): exact, starts with,\n // a word starts with, contains — `Cal` highlights Calibration, never Electrical.\n const visible = rankTypedMatches(options, q, titleOf);\n const decided = decideTypedChoice({ words: q, options, allowOther, nudge: nudge ?? \"ask\" });\n\n /** The cell takes `word`; `adding` says whether it is also added to the choices. */\n const choose = (word: string, addingIt = false) => {\n const pending = held.add.filter((w) => w.toLowerCase() !== word.toLowerCase());\n let next: unknown;\n let add: string[] = [...pending];\n if (field.multi) {\n const existing = current.map((v) => {\n const option = options.find((o) => isTheChosen(o, v));\n return option ? optionKey(option) : String(v);\n });\n const has = existing.some((v) => v.toLowerCase() === word.toLowerCase());\n const list = has ? existing.filter((v) => v.toLowerCase() !== word.toLowerCase()) : [...existing, word];\n if (addingIt && !has) add.push(word);\n add = add.filter((w) => list.some((v) => v.toLowerCase() === w.toLowerCase()));\n next = list.length === 0 ? null : list;\n } else {\n add = addingIt ? [word] : [];\n next = word;\n }\n onChange(add.length > 0 ? choiceAddition(next, add) : next);\n setSearch(\"\");\n // A SINGLE CHOICE IS DONE ON THE PICK — closed AFTER the value is handed over, because in a grid\n // cell closing is the commit and it must commit what was just picked.\n if (!field.multi) setOpen(false);\n };\n\n /** Add the typed words to the choices, and the cell takes them. */\n const addTyped = () => {\n setAddRefused(null);\n if (addsChoices || !client) {\n choose(q, Boolean(addsChoices));\n return;\n }\n // A HOST THAT SAVES WORDS ONLY (the record form): the choice is added now, through the\n // column's own door, and the cell then takes its words — which name a choice by then.\n setAdding(true);\n void client.fieldUpdate({ field_id: field.id, patch: { options_add: [q] } }).then((result) => {\n setAdding(false);\n if (!result.ok) {\n setAddRefused(result.error);\n return;\n }\n onChoicesChanged();\n choose(q);\n });\n };\n\n const offList = q !== \"\" && decided.decision !== \"chosen\" && decided.decision !== \"empty\";\n // A NEW WORD IS ONE \"CREATE\" ROW, NEVER A QUESTION (lane CELL-EDITORS, night walk 2026-10-06; Notion):\n // typing \"Webinar\" in Kind of work replaced the list with 'Add \"Webinar\" to the choices for Kind of\n // work?' and Add / Cancel. Now the list shows what matches and \"Create “Webinar”\" sits at its foot.\n // ONE FIXED SPOT, AND THE LIST FILTERED (REVIEW-FIX 7, 2026-10-06 — Notion): the Create row used to\n // jump to the top when nothing matched, and a no-match search listed every choice. Now it is always\n // the last row, under the matches only; with no match it is the only row, so one Enter creates it.\n // A column that takes no new choices says so instead.\n const foot = null;\n const add =\n offList && (decided.decision === \"ask\" || decided.decision === \"add\")\n ? { label: `Create “${q}”`, onAdd: addTyped, disabled: adding }\n : offList && decided.decision === \"keep_as_typed\"\n ? { label: `Use “${q}”`, onAdd: () => choose(q) }\n : null;\n const listed = visible;\n\n const pickedOptions = current.map((v) => options.find((o) => isTheChosen(o, v)));\n const cellChips = pickedWords.map((word, i) => {\n const chip = chipOf(pickedOptions[i], word);\n return (\n <Badge key={word} variant=\"outline\" className={cn(\"text-[11px]\", chip.className)} data-records-choice-chip=\"\">\n {word}\n </Badge>\n );\n });\n // WHAT IS PICKED, AT THE HEAD OF THE OPEN LIST, EACH WITH ITS × (Airtable, Notion, the old Sheet).\n const headChips = pickedWords.map((word, i) => {\n const option = pickedOptions[i];\n return {\n id: `${word}-${i}`,\n label: word,\n chip: chipOf(option, word).className,\n onRemove: () => {\n if (field.multi) choose(option ? optionKey(option) : String(current[i]));\n else onChange(null);\n },\n };\n });\n const anchored = autoOpen === true;\n\n return (\n <div id={id} className=\"flex flex-wrap items-center gap-1\">\n {anchored || disabled ? null : cellChips}\n {disabled ? (\n cellChips\n ) : (\n // THE ONE \"PICK OR ADD\" BUILDER (PickOrAdd.tsx) — the relation picker draws the same one.\n // In a grid cell it hangs from the cell's own chips; no button is drawn in the cell.\n <PickOrAdd\n anchored={anchored}\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n chips={headChips}\n multi={field.multi}\n triggerLabel={`Pick for ${fieldName(field)}`}\n triggerText={pickedWords.length === 0 ? \"Choose\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={(next) => {\n setSearch(next);\n setAddRefused(null);\n }}\n items={listed.map((option) => ({\n id: option.id,\n label: titleOf(option),\n chip: chipOf(option, titleOf(option)).className,\n picked: current.some((v) => isTheChosen(option, v)),\n }))}\n onPick={(optionId) => {\n const option = options.find((o) => o.id === optionId);\n if (option) choose(optionKey(option));\n }}\n empty={q === \"\" ? <p className=\"p-2 text-xs text-muted-foreground\">No choices yet — type one to add it.</p> : null}\n add={add}\n foot={foot}\n // ENTER ON A NEW WORD answers the question with its first answer — Add — exactly as Tab\n // then Enter does (grids review 3); a column that may not take it says so and Enter waits.\n footNote={\n addRefused ? (\n <RefusalLine error={addRefused} />\n ) : offList && decided.decision === \"not_a_choice\" ? (\n // never_add on a column that takes only its choices: said, never a silent nothing.\n <>\n <p data-records-typed-refusal=\"\" className=\"p-2 text-xs text-muted-foreground\">\n {notAChoiceSentence(field, [q])}\n </p>\n {autoOpen ? (\n <span data-records-choice-ask=\"\" className=\"px-2 pb-1\">\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" onClick={() => setOpen(false)}>\n Cancel\n </Button>\n </span>\n ) : null}\n </>\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n\n/** The chip a picked record shows as — REC-2's \"a record is a chip\" in one place. */\nexport function RecordChip({\n title,\n onRemove,\n className,\n}: {\n title: string;\n onRemove?: (() => void) | undefined;\n className?: string | undefined;\n}) {\n return (\n // A chip carries a RECORD'S OWN TITLE, which nobody here chose the length of —\n // \"Marisol Okonkwo — 418 Calle Puerto Vallarta, Camarillo\" is an ordinary customer\n // name. So it caps at its container and ends in an ellipsis with the whole name in\n // its tooltip, rather than being cut mid-word by whatever box it landed in\n // (lane FIX-14, 2026-09-22).\n <Badge variant=\"secondary\" className={cn(\"max-w-full gap-1 text-[11px]\", className)} title={title}>\n <span className=\"min-w-0 truncate\">{title}</span>\n {onRemove ? (\n <button type=\"button\" onClick={onRemove} aria-label={`Remove ${title}`} className=\"shrink-0 opacity-60 hover:opacity-100\">\n ×\n </button>\n ) : null}\n </Badge>\n );\n}\n\nexport type { Uuid };\n\n/** The choices a public page was handed for this question (`public_choices`), or none. */\nexport function publicChoicesOf(field: Field): Array<{ key: string; label: string }> {\n const raw = (field as unknown as { public_choices?: unknown }).public_choices;\n if (!Array.isArray(raw)) return [];\n return raw.flatMap((c) => {\n const o = c as { key?: unknown; label?: unknown };\n return typeof o.key === \"string\" && typeof o.label === \"string\" ? [{ key: o.key, label: o.label }] : [];\n });\n}\n\n/** How many choices a form lays out before it adds a search box above them. */\nexport const FORM_SEARCH_AFTER = 8;\n\n/** The keys a person presses to pick a choice, Typeform's way: A for the first, B for the second. */\nconst CHOICE_LETTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n/**\n * A CHOICE ANSWERED ON A FORM (MAKE-HOME W5b — Typeform, Tally). Every choice is a full-width row in\n * the form's own colour (the theme's primary, which the form's look sets), with its letter: pressing\n * A picks the first, B the second, and Enter goes on. The verifier walk (2026-10-02) found the\n * choices drawn as pills sized to their words in every colour of the grid's palette — a stranger's\n * intake form read as a table's cells. Past eight choices a search box sits above the rows. A single\n * choice is a radio group; several are toggles. The answer is the choice's key.\n */\nexport function ChoiceAnswer({\n field,\n choices,\n value,\n onChange,\n disabled,\n id,\n isChosen,\n onChosen,\n}: {\n field: Field;\n /** A single choice was picked (not un-picked): the form may go on. */\n onChosen?: (() => void) | undefined;\n choices: ReadonlyArray<{ key: string; label: string }>;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n /** Whether `choice` is what `v` holds; defaults to its key or label, as written. */\n isChosen?: ((choice: { key: string; label: string }, v: unknown) => boolean) | undefined;\n}) {\n const [search, setSearch] = useState(\"\");\n const held = field.multi ? choiceValuesOf(value) : value === null || value === undefined || value === \"\" ? [] : [value];\n const on = (choice: { key: string; label: string }) =>\n held.some((v) => (isChosen ? isChosen(choice, v) : String(v) === choice.key || String(v) === choice.label));\n const press = (choice: { key: string; label: string }) => {\n if (!field.multi) {\n const picking = !on(choice);\n onChange(picking ? choice.key : null);\n if (picking) onChosen?.();\n return;\n }\n const keys = choices.filter((c) => (c.key === choice.key ? !on(c) : on(c))).map((c) => c.key);\n onChange(keys.length === 0 ? null : keys);\n };\n const lettered = choices.length <= CHOICE_LETTERS.length;\n // ROVING FOCUS (lane TYPEFORM-2): one Tab stop — the chosen choice, or the first — and the arrow\n // keys move between choices; on a single choice an arrow also picks, as a radio group does.\n const tabStop = choices.find((c) => on(c))?.key ?? choices[0]?.key;\n const option = (choice: { key: string; label: string }) => {\n const chosen = on(choice);\n const letter = lettered ? CHOICE_LETTERS[choices.indexOf(choice)] : null;\n return (\n <button\n key={choice.key}\n type=\"button\"\n role={field.multi ? \"checkbox\" : \"radio\"}\n aria-checked={chosen}\n aria-label={choice.label}\n disabled={disabled}\n tabIndex={field.multi || choice.key === tabStop ? 0 : -1}\n onClick={() => press(choice)}\n data-records-choice-answer={choice.key}\n className={cn(\n \"flex min-h-11 w-full items-center gap-3 rounded-md border px-3 py-2 text-left text-base font-medium text-foreground transition-colors sm:min-h-10 sm:text-sm\",\n chosen ? \"border-primary bg-primary/10\" : \"border-primary/30 bg-primary/[0.03] hover:bg-primary/10\",\n )}\n >\n {letter ? (\n <kbd\n aria-hidden=\"true\"\n className={cn(\n \"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border font-sans text-xs font-semibold\",\n chosen ? \"border-primary bg-primary text-primary-foreground\" : \"border-primary/40 text-primary\",\n )}\n >\n {letter}\n </kbd>\n ) : null}\n <span className=\"min-w-0 flex-1 break-words\">{choice.label}</span>\n {chosen ? (\n <span aria-hidden=\"true\" className=\"shrink-0 text-primary\">\n ✓\n </span>\n ) : null}\n </button>\n );\n };\n // THE LETTER KEYS: anywhere in the question but the search box, a letter picks its choice.\n const onKeyDown = (event: React.KeyboardEvent) => {\n if (disabled || event.metaKey || event.ctrlKey || event.altKey) return;\n if ((event.target as HTMLElement).tagName === \"INPUT\") return;\n const arrow = { ArrowDown: 1, ArrowRight: 1, ArrowUp: -1, ArrowLeft: -1 }[event.key];\n if (arrow) {\n const buttons = Array.from(\n (event.currentTarget as HTMLElement).querySelectorAll<HTMLButtonElement>(\"[data-records-choice-answer]\"),\n );\n const here = buttons.indexOf(event.target as HTMLButtonElement);\n if (buttons.length === 0) return;\n event.preventDefault();\n const next = buttons[(Math.max(here, 0) + arrow + buttons.length) % buttons.length]!;\n next.focus();\n if (!field.multi) {\n const choice = choices.find((c) => c.key === next.dataset[\"recordsChoiceAnswer\"]);\n if (choice && !on(choice)) onChange(choice.key);\n }\n return;\n }\n if (!lettered) return;\n const at = CHOICE_LETTERS.indexOf(event.key.toUpperCase());\n if (event.key.length !== 1 || at < 0 || at >= choices.length) return;\n event.preventDefault();\n press(choices[at]!);\n };\n const group = { role: field.multi ? \"group\" : \"radiogroup\", \"aria-label\": fieldName(field), onKeyDown } as const;\n if (choices.length <= FORM_SEARCH_AFTER) {\n return (\n <div id={id} className=\"flex w-full flex-col gap-2\" {...group}>\n {choices.map(option)}\n </div>\n );\n }\n const q = search.trim().toLowerCase();\n const shown = q === \"\" ? choices : choices.filter((c) => c.label.toLowerCase().includes(q));\n return (\n <div id={id} className=\"flex w-full flex-col gap-2\" onKeyDown={onKeyDown}>\n <BasicInput\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder=\"Search\"\n aria-label={`Search — ${fieldName(field)}`}\n autoComplete=\"off\"\n className=\"h-11 text-base sm:h-9 sm:text-sm\"\n />\n <div className=\"flex max-h-80 w-full flex-col gap-2 overflow-y-auto\" role={group.role} aria-label={group[\"aria-label\"]}>\n {shown.map(option)}\n {shown.length === 0 ? <p className=\"text-xs text-muted-foreground\">No match</p> : null}\n </div>\n </div>\n );\n}\n","/**\n * 🚨 THE ONE DATE HELPER EVERY LAYOUT READS (lane UI-FIX-18, VERIFIER-18 H2 / M1).\n *\n * MEASURED 2026-09-24 on production, browser in America/Los_Angeles: Kitchen's start date,\n * stored `2026-04-01`, read **Apr 1** in the grid, **Mar 31** on the calendar, **3/31** in\n * the gallery, and Backyard Deck's May 1 read **4/30** in the record panel. The grid was right\n * because it formats through the design system's registry (`formatFieldValue`), which reads a\n * bare `YYYY-MM-DD` as a day on a calendar. Every other surface called `new Date(\"2026-04-01\")`\n * itself — which JavaScript parses as UTC MIDNIGHT — and then printed it in the viewer's zone,\n * so everybody west of Greenwich saw the day before.\n *\n * THE CLASS, NOT THE INSTANCE. No component in this package parses or prints a date on its\n * own any more; it asks this file, and this file asks the SAME registry the grid asks. The\n * calendar's day key is the one thing the registry does not answer, and it is answered here\n * by the same rule: a bare calendar date IS its own day (read the characters), an instant\n * (`…Z`, `…+hh:mm`) is placed on the viewer's own calendar.\n *\n * The store's own stamps — Created time and Last changed time (`fx.created_time`,\n * `fx.modified_time`) — are instants, and are printed like every other date-and-time cell\n * (VERIFIER-18 M1 found `2026-09-25T00:13:34.564Z` in the grid, the gallery and the panel).\n */\nimport { formatFieldValue, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { Field } from \"@ai-matrx/records\";\n\n/** A day on a calendar with no time and no zone — `2026-04-01`, or a zoneless local midnight. */\nconst BARE_CALENDAR_DATE = /^(\\d{4})-(\\d{2})-(\\d{2})(?:[T ]00:00(?::00(?:\\.0+)?)?)?$/;\n\ntype SystemStamp = \"autonumber\" | \"created_time\" | \"modified_time\";\n\n/** The store's own stamp this Field is, when it is one (`config.system`). */\nexport function systemStampOf(field: Pick<Field, \"type\" | \"config\">): SystemStamp | null {\n if (field.type !== \"formula\") return null;\n const system = String((field.config ?? {})[\"system\"] ?? \"\");\n return system === \"autonumber\" || system === \"created_time\" || system === \"modified_time\" ? system : null;\n}\n\n/**\n * Does this value (or, with no value, this Field) carry a TIME OF DAY as well as a date?\n *\n * A DATE IS A DATE (chair ruling, 2026-09-24). The control and the text follow the STORED\n * VALUE's shape, never `config.kind` alone: a value with no time part — `1988-06-14`, a date\n * of birth on a `kind: \"datetime\"` Field — gets a date-only control and a date-only reading\n * everywhere (grid, form, panel, calendar). With no value yet, only a Field that says so\n * outright carries a time: the older `format: \"datetime\"`, or the store's own Created / Last\n * changed stamps (instants by construction).\n */\nexport function carriesTimeOfDay(field: Pick<Field, \"type\" | \"config\" | \"format\">, value?: unknown): boolean {\n if (value !== undefined && value !== null && value !== \"\") return hasTimePart(value);\n const stamp = systemStampOf(field);\n if (stamp === \"created_time\" || stamp === \"modified_time\") return true;\n return (field.format ?? \"\").toLowerCase() === \"datetime\";\n}\n\n/**\n * THE TIME OF DAY A MOMENT CARRIES, in the reader's clock (\"3:30 PM\") — the same words the grid's\n * date-and-time cell ends in — or null for a bare day. A calendar's month card and a timeline's bar\n * show it before the title (lane 10 P4, verifier V8 #7), as Google Calendar does.\n */\nexport function timeOfDayWords(value: unknown): string | null {\n if (!hasTimePart(value)) return null;\n const at = value instanceof Date ? value : new Date(value as string | number);\n return Number.isNaN(at.getTime()) ? null : at.toLocaleTimeString(undefined, { hour: \"numeric\", minute: \"2-digit\" });\n}\n\n/** A value that names a moment in the day, not just the day. */\nexport function hasTimePart(value: unknown): boolean {\n if (value instanceof Date || typeof value === \"number\") return true;\n if (typeof value !== \"string\") return false;\n const trimmed = value.trim();\n if (BARE_CALENDAR_DATE.test(trimmed)) return false;\n return /^\\d{4}-\\d{2}-\\d{2}[T ]\\d/.test(trimmed);\n}\n\n/** Is this Field a date column at all — a dated range, or the store's own time stamp? */\nexport function isDateField(field: Pick<Field, \"type\" | \"config\">): boolean {\n const stamp = systemStampOf(field);\n if (stamp === \"created_time\" || stamp === \"modified_time\") return true;\n if (field.type !== \"range\") return false;\n const kind = String((field.config ?? {})[\"kind\"] ?? \"\");\n return kind === \"date\" || kind === \"datetime\";\n}\n\n/**\n * The format a date-ish Field draws with, or `undefined` for a Field that is not one. With a\n * value, it is that value's own shape; without, the Field's (`carriesTimeOfDay`).\n * `presentation.formatForField` answers dates through this, so the grid and every card agree.\n */\nexport function dateFormatFor(\n field: Pick<Field, \"type\" | \"config\" | \"format\">,\n value?: unknown,\n): FieldFormatConfig | undefined {\n if (!isDateField(field)) return undefined;\n return carriesTimeOfDay(field, value) ? { id: \"datetime\" } : { id: \"date\" };\n}\n\n/**\n * THE TEXT OF ONE DATE VALUE, in the viewer's language — through the design system's\n * registry, exactly as the grid prints it, in the value's own shape. `null` when the value is\n * not a date at all, so the caller can fall back to its own reading (THE FALLBACK LAW).\n */\nexport function dateText(field: Pick<Field, \"type\" | \"config\" | \"format\">, value: unknown): string | null {\n const format = dateFormatFor(field, value) ?? (isDateLike(value) ? { id: hasTimePart(value) ? \"datetime\" : \"date\" } : undefined);\n if (!format) return null;\n const result = formatFieldValue(value, format);\n return result.ok && !result.empty ? result.text : null;\n}\n\nfunction isDateLike(value: unknown): boolean {\n return typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}/.test(value.trim());\n}\n\nfunction pad(n: number): string {\n return n < 10 ? `0${n}` : String(n);\n}\n\n/**\n * THE CALENDAR DAY a value falls on, as `YYYY-MM-DD` — the key a calendar files a card under.\n *\n * A bare calendar date is its own day. An instant is placed on the VIEWER's calendar: a visit\n * logged at 5:13 PM Pacific on 24 September is on the 24th for the person in Pacific time,\n * even though it is already the 25th in UTC.\n */\nexport function calendarDayOf(value: unknown): string | null {\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n const bare = BARE_CALENDAR_DATE.exec(trimmed);\n if (bare) return `${bare[1]}-${bare[2]}-${bare[3]}`;\n if (trimmed === \"\") return null;\n } else if (typeof value !== \"number\" && !(value instanceof Date)) {\n return null;\n }\n const at = value instanceof Date ? value : new Date(value as string | number);\n if (Number.isNaN(at.getTime())) return null;\n return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;\n}\n\n/** The heading of one calendar day — `Apr 1, 2026` — built on local midnight, never UTC. */\nexport function calendarDayLabel(day: string): string {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(day);\n if (!m) return day;\n const at = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));\n return at.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n}\n\n// ---------------------------------------------------------------------------------------------\n// DAY ARITHMETIC ON THE VIEWER'S OWN CALENDAR (lane VIEWS-AND-FIELDS, sublane TL, 2026-10-02).\n// A day key is `YYYY-MM-DD`, built and read at LOCAL midnight — never `new Date(\"YYYY-MM-DD\")`,\n// which is UTC midnight and lands on the day before for everybody west of Greenwich. The timeline\n// places and moves bars with these; a move is always a whole number of days.\n\n/** The day key of a moment, on the viewer's calendar. */\nexport function dayKeyOf(at: Date): string {\n return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}`;\n}\n\n/** A day key as local midnight. */\nexport function dayAt(day: string): Date {\n const [y, m, d] = day.split(\"-\").map(Number);\n return new Date(y!, (m ?? 1) - 1, d ?? 1);\n}\n\n/** The day `n` days after (or before, when negative) `day`. */\nexport function addDays(day: string, n: number): string {\n const at = dayAt(day);\n at.setDate(at.getDate() + n);\n return dayKeyOf(at);\n}\n\n/** Whole days from `from` to `to` (negative when `to` is earlier). DST-safe: rounds the hour away. */\nexport function daysBetween(from: string, to: string): number {\n return Math.round((dayAt(to).getTime() - dayAt(from).getTime()) / 86_400_000);\n}\n","\"use client\";\n\n// src/newerKindValues.tsx — @ai-matrx/records-ui\n//\n// HOW THE NINE NEWER KINDS ARE SHOWN AND EDITED (lane 10 VIEWS-AND-FIELDS, sublane P4; champions:\n// Airtable's and SmartSuite's field types). One component per job, reached from the ONE value\n// drawing (`values.tsx`: RecordValue / renderValue / scalarText) and the ONE control\n// (`editors.tsx`: FieldControl), so the grid, the gallery, the board, the calendar, the record\n// panel and every form draw a kind the same way:\n//\n// rating stars (the registry's `rating` format, its top star read from the max Rule)\n// duration h:mm, typed as 45 min, 1:30 or 1h 30m\n// created by an initial and a name; last changed by — the same\n// status the choice chip, with its group's mark (To do ○, In progress ◐, Done ●)\n// address one line, opened in maps; edited in its five parts\n// barcode the code in monospace; on a phone that can, a photo of it fills it in\n// rich text Markdown drawn as React elements — never raw HTML, never innerHTML\n// count a whole number\n//\n// The store judges every value (`custom._kind_value_ok`); what is here only draws and reads.\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { codeSpanText, findInlineCodeSpans } from \"@ai-matrx/content-ir/source\";\nimport {\n ADDRESS_PARTS,\n NOT_A_MEMBER_WORDS,\n STATUS_GROUP_WORDS,\n addressMapUrl,\n addressText,\n durationText,\n isAddressValue,\n isPersonStamp,\n newerKindOf,\n personStampText,\n readTypedDuration,\n safeLinkHref,\n statusGroupOf,\n type AddressPart,\n type AddressValue,\n type Field,\n type PersonStamp,\n type StatusGroup,\n} from \"@ai-matrx/records\";\nimport { BasicInput, cn } from \"@ai-matrx/design-system\";\n\nconst own = (event: { stopPropagation: () => void }) => event.stopPropagation();\n\n// ── READ ───────────────────────────────────────────────────────────────────────────────────\n\n/**\n * One value of a newer kind, drawn — or `undefined` when the field is not one of the kinds drawn\n * here (the caller's own drawing applies). Never called for an empty value.\n */\nexport function newerKindValue(field: Field, value: unknown, opts: { inCell?: boolean | undefined } = {}): ReactNode | undefined {\n switch (newerKindOf(field)) {\n case \"duration\": {\n const words = durationText(value);\n return words === null ? undefined : (\n <span className=\"tabular-nums\" data-records-duration=\"\">\n {words}\n </span>\n );\n }\n case \"created_by\":\n case \"modified_by\":\n return isPersonStamp(value) ? <PersonStampChip stamp={value} /> : undefined;\n case \"address\":\n return isAddressValue(value) || typeof value === \"string\" ? <AddressLink value={value} /> : undefined;\n case \"barcode\":\n return typeof value === \"string\" ? (\n <span className=\"inline-flex min-w-0 items-center gap-1 font-mono text-xs\" data-records-barcode=\"\" title={value}>\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">\n ▮▯▮\n </span>\n <span className=\"truncate\">{value}</span>\n </span>\n ) : undefined;\n case \"rich_text\":\n return typeof value === \"string\" ? <SafeMarkdown text={value} clipped={opts.inCell === true} /> : undefined;\n case \"count\":\n return typeof value === \"number\" ? <span className=\"tabular-nums\">{value.toLocaleString()}</span> : undefined;\n default:\n return undefined;\n }\n}\n\n/**\n * Who made or last changed a record: an initial and a name — or, for a write the platform made,\n * \"System\", and for an agent's, \"Agent for\" the person it wrote for (V8 #4).\n */\nexport function PersonStampChip({ stamp }: { stamp: PersonStamp }) {\n const words = personStampText(stamp) ?? NOT_A_MEMBER_WORDS;\n const tier = stamp.actor ?? \"user\";\n const name = tier === \"user\" ? stamp.name : null;\n const initial = tier === \"system\" ? \"⚙\" : tier === \"agent\" ? \"✦\" : name && name.trim() !== \"\" ? name.trim()[0]!.toUpperCase() : \"?\";\n return (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\" data-records-person-stamp={tier}>\n <span\n aria-hidden=\"true\"\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-muted text-[10px] font-medium text-foreground\"\n >\n {initial}\n </span>\n <span className={cn(\"truncate\", tier === \"user\" && !name ? \"italic text-muted-foreground\" : \"\")}>{words}</span>\n </span>\n );\n}\n\nfunction AddressLink({ value }: { value: AddressValue | string }) {\n const words = addressText(value);\n const href = addressMapUrl(value);\n if (!words || !href) return <span className=\"text-muted-foreground\">—</span>;\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex min-w-0 items-center gap-1 text-primary hover:underline\"\n title=\"Open in maps\"\n data-records-address=\"\"\n onClick={own}\n >\n <span aria-hidden=\"true\">⌖</span>\n <span className=\"truncate\">{words}</span>\n </a>\n );\n}\n\n/** The mark a status group wears beside its choice, Linear's way. */\nexport const STATUS_GROUP_MARK: Record<StatusGroup, string> = { todo: \"○\", in_progress: \"◐\", done: \"●\" };\n\n/**\n * The group mark for one status value, with the group's name for hover; null when not a status.\n * The read puts the choice's WORDS in the cell and its KEY under `_choices` (V8 #2: every chip read\n * \"○ To do\" because the words were looked up as a key) — so the key is read from `_choices` first.\n */\nexport function statusMarkOf(\n field: Field,\n value: unknown,\n document?: Record<string, unknown> | null,\n): { mark: string; group: StatusGroup; words: string } | null {\n if (newerKindOf(field) !== \"status\" || typeof value !== \"string\") return null;\n const chosen = (document?.[\"_choices\"] as Record<string, unknown> | undefined)?.[field.key];\n const key = chosen && typeof chosen === \"object\" && typeof (chosen as { key?: unknown }).key === \"string\" ? (chosen as { key: string }).key : value;\n const group = statusGroupOf(field, key);\n return { mark: STATUS_GROUP_MARK[group], group, words: STATUS_GROUP_WORDS[group] };\n}\n\n// ── RICH TEXT: A SAFE SUBSET OF MARKDOWN, AS REACT ELEMENTS ───────────────────────────────\n\n/**\n * Inline Markdown: **bold**, _italic_ / *italic*, `code`, [words](https://…). Everything else is text.\n * Code spans are found by THE rule (`findInlineCodeSpans`, @ai-matrx/content-ir/source) and drawn first;\n * the marks are read only in the text between them.\n */\nfunction inline(text: string, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n let at = 0;\n let n = 0;\n for (const r of findInlineCodeSpans(text)) {\n if (r.start < at) continue;\n if (r.start > at) out.push(...marks(text.slice(at, r.start), `${key}-m${n++}`));\n out.push(<code key={`${key}-c${n++}`} className=\"rounded bg-muted px-1 font-mono text-[0.9em]\">{codeSpanText(text.slice(r.start, r.end))}</code>);\n at = r.end;\n }\n if (at < text.length) out.push(...marks(text.slice(at), `${key}-m${n++}`));\n return out;\n}\n\n/** The marks of inline text that holds no code span: bold, italic, links. */\nfunction marks(text: string, key: string): ReactNode[] {\n const out: ReactNode[] = [];\n const re = /(\\*\\*[^*]+\\*\\*|__[^_]+__|\\[[^\\]]+\\]\\([^)\\s]+\\)|\\*[^*\\s][^*]*\\*|_[^_\\s][^_]*_)/g;\n let last = 0;\n let i = 0;\n for (const m of text.matchAll(re)) {\n const at = m.index ?? 0;\n if (at > last) out.push(text.slice(last, at));\n const tok = m[0];\n const k = `${key}-${i++}`;\n if (tok.startsWith(\"**\") || tok.startsWith(\"__\")) out.push(<strong key={k}>{tok.slice(2, -2)}</strong>);\n else if (tok.startsWith(\"[\")) {\n const link = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(tok);\n // Read as a browser would follow it — entities and escapes decoded (V8 #5) — and only a web\n // page, an email address or a phone number becomes a link.\n const href = safeLinkHref(link?.[2] ?? \"\");\n out.push(\n href ? (\n <a key={k} href={href} target=\"_blank\" rel=\"noopener noreferrer\" className=\"text-primary underline-offset-2 hover:underline\" onClick={own}>\n {link?.[1]}\n </a>\n ) : (\n link?.[1] ?? tok\n ),\n );\n } else out.push(<em key={k}>{tok.slice(1, -1)}</em>);\n last = at + tok.length;\n }\n if (last < text.length) out.push(text.slice(last));\n return out;\n}\n\n/**\n * Markdown drawn as React elements — paragraphs, # headings, - and 1. lists, and the inline marks.\n * No HTML is ever parsed or injected: a `<` in the text is drawn as the character it is.\n */\nexport function SafeMarkdown({ text, clipped }: { text: string; clipped?: boolean }) {\n const blocks: ReactNode[] = [];\n const lines = text.replace(/\\r\\n?/g, \"\\n\").split(\"\\n\");\n let list: { ordered: boolean; items: string[] } | null = null;\n let para: string[] = [];\n const flushPara = () => {\n if (para.length > 0) {\n blocks.push(<p key={`p${blocks.length}`}>{inline(para.join(\" \"), `p${blocks.length}`)}</p>);\n para = [];\n }\n };\n const flushList = () => {\n if (list) {\n const items = list.items.map((item, i) => <li key={i}>{inline(item, `l${blocks.length}-${i}`)}</li>);\n blocks.push(\n list.ordered ? (\n <ol key={`o${blocks.length}`} className=\"ml-4 list-decimal\">{items}</ol>\n ) : (\n <ul key={`u${blocks.length}`} className=\"ml-4 list-disc\">{items}</ul>\n ),\n );\n list = null;\n }\n };\n for (const raw of lines) {\n const line = raw.trimEnd();\n const bullet = /^\\s*[-*+]\\s+(.*)$/.exec(line);\n const numbered = /^\\s*\\d+[.)]\\s+(.*)$/.exec(line);\n const heading = /^(#{1,3})\\s+(.*)$/.exec(line);\n if (bullet || numbered) {\n flushPara();\n const ordered = Boolean(numbered);\n if (list && list.ordered !== ordered) flushList();\n if (!list) list = { ordered, items: [] };\n list.items.push((bullet ?? numbered)![1]!);\n } else if (heading) {\n flushPara();\n flushList();\n blocks.push(<p key={`h${blocks.length}`} className=\"font-semibold\">{inline(heading[2]!, `h${blocks.length}`)}</p>);\n } else if (line.trim() === \"\") {\n flushPara();\n flushList();\n } else {\n flushList();\n para.push(line.trim());\n }\n }\n flushPara();\n flushList();\n return (\n <span\n className={cn(\"block min-w-0 space-y-1 whitespace-normal text-sm\", clipped ? \"max-h-[4.5em] overflow-hidden\" : \"\")}\n data-records-rich-text=\"\"\n >\n {blocks}\n </span>\n );\n}\n\n// ── EDIT ───────────────────────────────────────────────────────────────────────────────────\n\ntype ControlProps = { field: Field; value: unknown; onChange: (value: unknown) => void; disabled?: boolean | undefined; id: string };\n\n/** The control for a newer kind, or undefined when the field's base control is right for it. */\nexport function newerKindControl(props: ControlProps): ReactNode | undefined {\n switch (newerKindOf(props.field)) {\n case \"duration\":\n return <DurationControl {...props} />;\n case \"address\":\n return <AddressControl {...props} />;\n case \"barcode\":\n return <BarcodeControl {...props} />;\n case \"created_by\":\n case \"modified_by\":\n case \"count\":\n return (\n <div id={props.id} className=\"rounded border border-dashed px-2 py-1.5 text-xs text-muted-foreground\">\n {props.value === null || props.value === undefined ? \"—\" : newerKindValue(props.field, props.value)}\n </div>\n );\n default:\n return undefined;\n }\n}\n\n/** A length of time, typed the way people say it; the value is seconds. */\nfunction DurationControl({ value, onChange, disabled, id }: ControlProps) {\n const [text, setText] = useState(() => durationText(value) ?? \"\");\n const [wrong, setWrong] = useState(false);\n useEffect(() => {\n setText(durationText(value) ?? \"\");\n }, [value]);\n return (\n <span className=\"flex flex-col gap-1\">\n <BasicInput\n id={id}\n value={text}\n disabled={disabled}\n inputMode=\"numeric\"\n placeholder=\"45 min\"\n aria-invalid={wrong || undefined}\n className=\"tabular-nums\"\n onChange={(e) => {\n setText(e.target.value);\n if (e.target.value.trim() === \"\") {\n setWrong(false);\n onChange(null);\n return;\n }\n const seconds = readTypedDuration(e.target.value);\n setWrong(seconds === null);\n if (seconds !== null) onChange(seconds);\n }}\n onBlur={() => {\n if (!wrong) setText(durationText(value) ?? \"\");\n }}\n />\n {wrong ? <span className=\"text-[11px] text-destructive\">Write it like 45 min, 1:30 or 1h 30m.</span> : null}\n </span>\n );\n}\n\nconst ADDRESS_LABELS: Record<AddressPart, string> = {\n street: \"Street\",\n city: \"City\",\n region: \"State or region\",\n postal_code: \"Postal code\",\n country: \"Country\",\n};\nconst ADDRESS_EXAMPLES: Record<AddressPart, string> = {\n street: \"1420 Cedar Ridge Pkwy\",\n city: \"Boulder\",\n region: \"CO\",\n postal_code: \"80301\",\n country: \"US\",\n};\n\n/** An address in its five parts; a part left empty is left out. */\nfunction AddressControl({ value, onChange, disabled, id }: ControlProps) {\n const held: AddressValue = isAddressValue(value) ? value : typeof value === \"string\" && value.trim() !== \"\" ? { street: value } : {};\n const set = (part: AddressPart, words: string) => {\n const next: AddressValue = { ...held, [part]: words };\n const kept = Object.fromEntries(Object.entries(next).filter(([, v]) => typeof v === \"string\" && v.trim() !== \"\")) as AddressValue;\n onChange(Object.keys(kept).length === 0 ? null : kept);\n };\n return (\n <span id={id} className=\"grid grid-cols-2 gap-1.5\" data-records-address-control=\"\">\n {ADDRESS_PARTS.map((part) => (\n <BasicInput\n key={part}\n aria-label={ADDRESS_LABELS[part]}\n placeholder={ADDRESS_EXAMPLES[part]}\n className={part === \"street\" ? \"col-span-2\" : \"\"}\n value={typeof held[part] === \"string\" ? (held[part] as string) : \"\"}\n disabled={disabled}\n {...(part === \"street\" ? { autoComplete: \"street-address\" } : {})}\n onChange={(e) => set(part, e.target.value)}\n />\n ))}\n </span>\n );\n}\n\ntype Detector = { detect: (source: ImageBitmapSource) => Promise<Array<{ rawValue: string }>> };\ntype DetectorCtor = new (opts?: { formats?: string[] }) => Detector;\n\n/** The phone's own barcode reader, when it has one (Chrome on Android). Null: no scanning here. */\nfunction barcodeDetector(): DetectorCtor | null {\n const ctor = (globalThis as { BarcodeDetector?: DetectorCtor }).BarcodeDetector;\n return typeof ctor === \"function\" ? ctor : null;\n}\n\n/** A barcode, typed — and on a phone that reads barcodes, photographed. */\nfunction BarcodeControl({ value, onChange, disabled, id }: ControlProps) {\n const file = useRef<HTMLInputElement>(null);\n const [said, setSaid] = useState<string | null>(null);\n const Detect = barcodeDetector();\n return (\n <span className=\"flex flex-col gap-1\">\n <span className=\"flex items-center gap-1.5\">\n <BasicInput\n id={id}\n className=\"font-mono\"\n value={typeof value === \"string\" ? value : \"\"}\n disabled={disabled}\n placeholder=\"4006381333931\"\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n />\n {Detect && !disabled ? (\n <>\n <button\n type=\"button\"\n className=\"shrink-0 rounded-md border px-2 py-1 text-xs hover:bg-accent\"\n onClick={() => file.current?.click()}\n >\n Scan\n </button>\n <input\n ref={file}\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n className=\"hidden\"\n onChange={async (e) => {\n const photo = e.target.files?.[0];\n e.target.value = \"\";\n if (!photo) return;\n try {\n const found = await new Detect().detect(await createImageBitmap(photo));\n if (found[0]?.rawValue) {\n onChange(found[0].rawValue);\n setSaid(null);\n } else setSaid(\"No barcode in that photo. Try closer, in good light.\");\n } catch {\n setSaid(\"This phone could not read that photo. Type the code instead.\");\n }\n }}\n />\n </>\n ) : null}\n </span>\n {said ? <span className=\"text-[11px] text-muted-foreground\">{said}</span> : null}\n </span>\n );\n}\n","// src/choiceLooks.ts — @ai-matrx/records-ui · merge tranche 6f (early)\n//\n// A CHOICE WEARS THE COLOUR ITS OWNER GAVE IT.\n//\n// The older /data grid let a person paint each choice of a list (\"Completed\" green, \"Scheduled\"\n// blue), and those colours are kept on the Field itself: `display_format.options.choices`, the\n// document `custom.field_update` writes (the /data Sheet's seam writes it the same way, and a\n// column's settings here write it back). The grid used to ignore it and HASH THE WORD into a\n// colour, so a column painted green on /data came up amber here, and a colour a person set in the\n// settings changed nothing on screen — the silent half of a setting.\n//\n// Pure: no React, no store call. The Field the grid already holds carries everything.\n\nimport { newerKindOf, type Field } from \"@ai-matrx/records\";\nimport {\n CHOICE_CHIP_CLASS,\n NEUTRAL_CHIP_CLASS,\n STYLE_COLORS,\n type ChoiceColorLookup,\n type StyleColor,\n} from \"@ai-matrx/design-system/data-table\";\n\n/** One choice's look, as the Field keeps it. */\nexport interface ChoiceLook {\n value: string;\n label?: string;\n color?: StyleColor;\n}\n\n/** The Field's display document, which the store keeps beside its declared keys. */\nexport function displayFormatOf(field: Field): { id: string; options: Record<string, unknown> } | null {\n const raw = (field as unknown as { display_format?: unknown }).display_format;\n if (!raw || typeof raw !== \"object\") return null;\n const id = (raw as { id?: unknown }).id;\n if (typeof id !== \"string\" || id === \"\") return null;\n const options = (raw as { options?: unknown }).options;\n return { id, options: options && typeof options === \"object\" ? (options as Record<string, unknown>) : {} };\n}\n\nfunction isStyleColor(v: unknown): v is StyleColor {\n return typeof v === \"string\" && (STYLE_COLORS as readonly string[]).includes(v);\n}\n\n/** Every choice look the Field keeps, in its own order. A colour outside the palette is dropped. */\nexport function choiceLooksOf(field: Field): ChoiceLook[] {\n const display = displayFormatOf(field);\n const choices = display?.options[\"choices\"];\n if (!Array.isArray(choices)) return [];\n const out: ChoiceLook[] = [];\n for (const c of choices) {\n if (!c || typeof c !== \"object\") continue;\n const value = (c as { value?: unknown }).value;\n if (typeof value !== \"string\" || value.trim() === \"\") continue;\n const color = (c as { color?: unknown }).color;\n const label = (c as { label?: unknown }).label;\n out.push({\n value: value.trim(),\n ...(typeof label === \"string\" && label.trim() !== \"\" ? { label: label.trim() } : {}),\n ...(isStyleColor(color) ? { color } : {}),\n });\n }\n return out;\n}\n\n/**\n * ONE WORD, HOWEVER IT WAS WRITTEN. A moved list keeps its words as `completed` / `truck_4` and\n * shows them as `Completed` / `Truck 4`; a colour kept against either spelling is the same choice.\n */\nexport function choiceWord(value: unknown): string {\n return String(value ?? \"\")\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\");\n}\n\n/**\n * NOTION'S STATUS COLOURS, BY GROUP: To-do grey, In progress blue, Complete green. A status choice\n * the column paints nothing for wears its group's colour, so a fresh Status column reads the way\n * Notion's does with nobody picking a colour. A choice with a colour of its own keeps it\n * (`storedChoiceColor` asks the column first).\n */\nexport const STATUS_GROUP_COLOR = { todo: \"gray\", in_progress: \"blue\", done: \"green\" } as const satisfies Record<string, StyleColor>;\n\n/** The colour a status choice's GROUP gives it, or `undefined` when the column is not a Status. */\nexport function statusGroupColor(field: Field, value: unknown): StyleColor | undefined {\n if (newerKindOf(field) !== \"status\" || value === null || value === undefined || value === \"\") return undefined;\n const word = choiceWord(value);\n if (word === \"\") return undefined;\n const groups = ((field.config ?? {}) as Record<string, unknown>)[\"status_groups\"];\n if (groups && typeof groups === \"object\") {\n // the group is kept under the choice's KEY; the cell may hold its WORDS (\"In progress\" ↔ in_progress)\n for (const [key, group] of Object.entries(groups as Record<string, unknown>)) {\n if (choiceWord(key) !== word) continue;\n return group === \"in_progress\" ? STATUS_GROUP_COLOR.in_progress : group === \"done\" ? STATUS_GROUP_COLOR.done : STATUS_GROUP_COLOR.todo;\n }\n }\n return STATUS_GROUP_COLOR.todo;\n}\n\n/** The colour this Field keeps for this value, or `undefined` when it keeps none. */\nexport function storedChoiceColor(field: Field, value: unknown): StyleColor | undefined {\n if (value === null || value === undefined || value === \"\") return undefined;\n const word = choiceWord(value);\n if (word === \"\") return undefined;\n for (const look of choiceLooksOf(field)) {\n if (!look.color) continue;\n if (choiceWord(look.value) === word || (look.label && choiceWord(look.label) === word)) return look.color;\n }\n return statusGroupColor(field, value);\n}\n\n/**\n * THE COLOUR-BY LOOKUP, STORED COLOURS FIRST. A value whose column keeps a colour for it wears\n * that colour; any other value still paints, deterministically, through `fallback` — a colour-by\n * that silently did nothing would be the screen lying about a setting a person just changed.\n */\nexport function storedChoiceColorLookup(\n fields: readonly Field[],\n fallback: ChoiceColorLookup,\n): ChoiceColorLookup {\n const byKey = new Map(fields.map((f) => [f.key, f] as const));\n return (fieldKey, value) => {\n const field = byKey.get(fieldKey);\n return (field ? storedChoiceColor(field, value) : undefined) ?? fallback(fieldKey, value);\n };\n}\n\n/**\n * THE ORDER A NEW CHOICE IS PAINTED IN (Airtable): each choice added to a list takes the next\n * palette colour the list does not wear yet, so a fresh list reads as distinct chips with nobody\n * picking a colour. Grey last — it reads as \"no colour\".\n */\nexport const NEW_CHOICE_PALETTE: readonly StyleColor[] = [\"blue\", \"green\", \"amber\", \"red\", \"violet\", \"teal\", \"slate\"];\n\n/** The colour the next choice of a list takes, given the colours its choices already wear. */\nexport function nextChoiceColor(worn: ReadonlyArray<StyleColor | null | undefined>): StyleColor {\n const taken = new Set(worn.filter((c): c is StyleColor => Boolean(c)));\n const free = NEW_CHOICE_PALETTE.find((c) => !taken.has(c));\n return free ?? NEW_CHOICE_PALETTE[worn.length % NEW_CHOICE_PALETTE.length]!;\n}\n\n/**\n * THE ONE CHIP A CHOICE IS DRAWN AS — the grid cell, the picker's list and its chip, a form's\n * pills: the colour the column keeps for the value (by any of the words given — its key, its\n * label), else the neutral chip. One answer, so no surface paints a choice its own way.\n */\nexport function choiceChipLookOf(field: Field, ...words: unknown[]): { className: string; color: StyleColor | null } {\n for (const word of words) {\n const color = storedChoiceColor(field, word);\n if (color) return { className: CHOICE_CHIP_CLASS[color], color };\n }\n return { className: NEUTRAL_CHIP_CLASS, color: null };\n}\n","// src/parity.ts — @ai-matrx/records-ui\n//\n// FLD-11, the parity floor. A Field stores a BEHAVIOUR (one of five) plus\n// modifiers, unit and format; a person picked one of THIRTEEN parity types in\n// the UI. This resolves the second from the first, using the same facts the\n// store's own `custom.parity_field_types()` describes — which is generated into\n// `@ai-matrx/records` and imported here, never retyped.\n//\n// Nothing in this file decides policy. It decides which editor to draw.\n\nimport { displayFormatOf } from \"./choiceLooks\";\nimport {\n KERNEL_TABLES,\n PARITY_FIELD_TYPES,\n fieldKindFor,\n newerKindOf,\n type Field,\n type FieldKind,\n type KernelTargets,\n type ParityFieldType,\n} from \"@ai-matrx/records\";\nimport { isButtonField } from \"@ai-matrx/records\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\nimport { isSignatureField } from \"./docs\";\nimport { fieldTypeChoice, isSystemFieldKind, type PickableFieldType } from \"./fieldTypes\";\n\n/** The kernel ids come from the store's own kernel rows, never from a literal here. */\nconst kernelId = (name: string): string =>\n KERNEL_TABLES.find((t) => t.name === name)?.id ?? \"\";\nconst KERNEL_FILE_TABLE = kernelId(\"File\");\nconst KERNEL_PERSON_TABLE = kernelId(\"Person\");\n\nexport const PARITY_LABEL: Record<ParityFieldType, string> = {\n attachment: \"Attachment\",\n checkbox: \"Yes / no\",\n currency: \"Currency\",\n datetime: \"Date\",\n email: \"Email\",\n formula: \"Formula\",\n lookup: \"Lookup\",\n member: \"Person\",\n multi_select: \"Multi-select\",\n percent: \"Percent\",\n phone: \"Phone\",\n rollup: \"Rollup\",\n select: \"Select\",\n url: \"Link\",\n};\n\n/** The \"made of\" sentence the store itself publishes, for the field editor's help text. */\nexport const PARITY_MADE_OF: Record<string, string> = Object.fromEntries(\n PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of]),\n);\n\n/**\n * Plain text and plain number are behaviours with no parity type of their own.\n *\n * 🚨 THIS IS NOW AN ALIAS, AND THAT IS THE POINT (TAILS-3, 2026-09-21). The\n * classifier moved into `@ai-matrx/records` as `FieldKind` so that the editor a\n * person types into and the COERCION applied to what they typed are decided by\n * one body. They were decided by two, and the public booking page paid for it:\n * \"Vehicle Year takes a number, and it was given a string\" on every table with\n * a number field.\n */\nexport type EditorKind = FieldKind;\n\n/** The kernel ids come from the store's own kernel rows, never from a literal here. */\nconst KERNEL: KernelTargets = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };\n\n/**\n * Which editor one Field wants. Reads the Field's own declaration only — the\n * behaviour, the modifiers, the format, the relation target and the config —\n * because those are what the store stores, and a screen that guessed from a\n * value would draw a different editor for an empty record.\n *\n * It is `fieldKindFor` with this package's kernel ids bound. Nothing here\n * decides anything the core does not.\n */\nexport function editorKindFor(field: Field): EditorKind {\n return fieldKindFor(field, KERNEL);\n}\n\n/**\n * WHICH KIND A PERSON PICKED, read back off the Field the store keeps — the ONE reader every\n * \"what does this column hold\" answer goes through (the Settings column list, the column panel).\n *\n * `editorKindFor` answers which EDITOR to draw, and for two families that is not the kind a\n * person picked: a Signature is a text Field whose format is `signature` (it draws a line of\n * text), and the store's stamps — Record number, Created time, Last changed time — are formula\n * Fields whose `config.system` names the stamp. Read through the editor classifier alone, the\n * Settings list called a Signature \"Text\" and a Record number \"Worked out from other columns\"\n * (lane 10 W1-A, guard `every-pickable-kind-reads-back-as-itself.test.tsx`).\n *\n * `undefined` when the Field is none of the kinds the menu offers.\n */\nexport function pickableTypeOf(field: Field): PickableFieldType | undefined {\n if (isSignatureField(field)) return \"signature\";\n // NOTION-PROPS-3: a button is text wearing the format `button`.\n if (isButtonField(field)) return \"button\";\n // LANE 10 P4: the nine newer kinds, each a base type wearing a format (`newerKindOf`).\n const newer = newerKindOf(field);\n if (newer) return newer;\n // A RATING OR A TIME made as a plain column wearing its look (`LOOK_KINDS`): named by that kind.\n const look = displayFormatOf(field)?.id;\n if (look === \"rating\" && field.type === \"range\") return \"rating\";\n if (look === \"time\" && field.type === \"text\") return \"time\";\n const system = (field.config as Record<string, unknown> | undefined)?.[\"system\"];\n if (field.type === \"formula\" && typeof system === \"string\" && isSystemFieldKind(system)) return system;\n const kind = editorKindFor(field);\n return fieldTypeChoice(kind) ? (kind as PickableFieldType) : undefined;\n}\n\n/**\n * The type word a person sees in a header or a settings row — and it is the\n * SAME word the field panel offers, read from `FIELD_TYPE_CHOICES`, so a column\n * added as \"Money\" is never described anywhere else as \"Currency\".\n */\nexport function fieldTypeLabel(field: Field): string {\n const kind = pickableTypeOf(field) ?? editorKindFor(field);\n const known = fieldTypeChoice(kind)?.label;\n if (known) return field.multi && kind !== \"multi_select\" ? `${known} (many)` : known;\n const plain: Record<string, string> = {\n // `boolean` is the BEHAVIOUR word; `checkbox` is the type a person picks. Both are\n // written the way a person writes them, never as a raw token.\n boolean: \"Yes / no\",\n date: \"Date\",\n json: \"Structured data\",\n relation: \"Link to a record\",\n };\n // Never a raw token on a screen: an editor kind this table has not named is\n // still written the way a person writes it.\n return plain[kind] ?? humanizeIdentifier(kind);\n}\n","\"use client\";\n\n// src/docs.ts — @ai-matrx/records-ui · SCR-20, SCR-21, SCR-22\n//\n// DOCUMENTS OVER RECORDS. A template is a body whose tokens point at Fields BY\n// ID; a render is written ONCE and frozen with the SHA-256 of its own text; a\n// signature seals that exact version and is immutable once made.\n//\n// Three things this package refuses to re-implement, because the store already\n// does them and doing them twice is how two answers appear:\n// · which tokens a body contains — `custom.doc_tokens`;\n// · which of them this Table cannot answer, and why — `custom.doc_unresolved_tokens`;\n// · whether a signature still holds — `custom.doc_signature_intact`.\n//\n// The token syntax is the store's own: `{{field:<the field's id>}}`. A name\n// would be a token that silently stops resolving the day somebody renames a\n// Field, which is the exact failure REC-17 exists to prevent.\n\nimport type { Field, Uuid } from \"@ai-matrx/records\";\n\n/** The one token form, written the way the store's own pattern reads it. */\nexport function fieldToken(fieldId: Uuid): string {\n return `{{field:${fieldId}}}`;\n}\n\n/** THE DECLARATIVE SPEC an agent writes. One template, whole, in one object. */\nexport interface DocTemplateSpec {\n name: string;\n /** The body, tokens and all. */\n body: string;\n}\n\n/**\n * A template written in terms of Field KEYS — which is how an agent thinks and\n * how a person reads — turned into the store's id-based tokens. The agent writes\n * `{{title}}`; what is stored points at the Field's id, so a rename never\n * silently empties the document.\n *\n * A key this Table does not have is LEFT EXACTLY AS IT IS, so\n * `custom.doc_unresolved_tokens` names it and the screen shows the store's own\n * reason — it is never quietly deleted from the body.\n */\nexport function bodyFromKeys(body: string, fields: Field[]): string {\n const byKey = new Map(fields.map((f) => [f.key, f.id]));\n return body.replace(/\\{\\{\\s*([a-zA-Z0-9_]+)\\s*\\}\\}/g, (whole, key: string) => {\n const id = byKey.get(key);\n return id ? fieldToken(id) : whole;\n });\n}\n\n/** The reverse, for a person reading a stored body: ids shown as the Field's label. */\nexport function bodyForReading(body: string, fields: Field[]): string {\n const byId = new Map(fields.map((f) => [f.id, f.label || f.key]));\n return body.replace(/\\{\\{\\s*field:([0-9a-fA-F-]{36})\\s*\\}\\}/g, (whole, id: string) => {\n const label = byId.get(id);\n return label ? `{{${label}}}` : whole;\n });\n}\n\n/** VAL-10: a signature is a Value on a text Field whose format is `signature`. */\nexport function isSignatureField(field: Field): boolean {\n return field.type === \"text\" && (field.format ?? \"\").toLowerCase() === \"signature\";\n}\n","// src/fieldTypes.ts — @ai-matrx/records-ui\n//\n// EVERY KIND OF COLUMN THE STORE TAKES, IN THE WORDS A PERSON USES.\n//\n// The store publishes fourteen parity types and, for each, a sentence about what\n// it is MADE OF — \"REC-31: a File record reached through a relation, target the\n// kernel `File` Table\", \"FLD-9: a declared computation, on read or on write,\n// evaluated by custom.rule_eval\", \"config.via names the relation field,\n// config.pick the Value on the far side\". Those sentences are true and they are\n// for us. The 19 September verdict found them printed at the person choosing a\n// column type, alongside contract row ids, and called it what it is: machine\n// identity where a person is looking.\n//\n// So this file holds the OTHER sentence — what the type is FOR — and the field\n// panel shows that one. The store's own `made_of` stays where it belongs, in\n// `PARITY_MADE_OF`, for an engineer reading the package.\n//\n// The LIST itself is still the store's: `PARITY_FIELD_TYPES` is generated from\n// `custom.parity_field_types()`, and `assertEveryParityTypeIsExplained` (run by\n// the suite) fails the moment the store ships a fourteenth and nobody wrote a\n// sentence for it. A type with no explanation would otherwise appear with a\n// blank line under it, which is the silent version of the same defect. It caught the\n// fourteenth — `checkbox`, 2026-09-21 — exactly as it was written to.\n\nimport { DECLARABLE_FIELD_KINDS, NEWER_FIELD_KINDS, PARITY_FIELD_TYPES, type DeclarableFieldKind, type NewerFieldKind, type ParityFieldType } from \"@ai-matrx/records\";\n\n/** The three behaviours that carry no parity type of their own. */\nexport type PlainFieldType = \"text\" | \"long_text\" | \"number\";\n\n/**\n * THE ONE A PERSON COMING FROM AIRTABLE REACHES FOR FIRST, AND IT WAS NOT HERE.\n *\n * The list above offered `member` (a Person) and `attachment` (a File) — the two\n * relations whose target is a Table the PLATFORM keeps — and nothing at all for\n * \"this job belongs to that customer\". The store has taken it since 2026-09-20\n * (`custom.field_declare` with `type: \"relation\"` and a `relation_target`), the\n * Field type has named it since the same day, and `editorKindFor` has answered\n * `\"relation\"` for one since long before that. Only the menu did not offer it,\n * so the guide's section 3 told a person to pick a kind that did not exist.\n *\n * It is NOT a parity type of its own. `custom.parity_field_types()` ships\n * fourteen (the fourteenth is `checkbox`) and a relation is a BEHAVIOUR — the same behaviour `member` and\n * `attachment` are made of — so it sits beside the three plain ones as its own\n * word, and `parityTypesWithNoExplanation()` is unaffected by it in both\n * directions: it does not appear there, and it cannot hide a real gap there.\n */\nexport type RelationFieldType = \"relation\";\n\n/**\n * What a person picks in the panel — AND IT IS THE STORE'S OWN LIST, not a union\n * assembled here.\n *\n * 🚨 THE CLASS FIX (FIX-10B-F6, VERIFIER-10). This used to read\n * `ParityFieldType | PlainFieldType | RelationFieldType` — the parity floor plus two words\n * this file knew about — and that union was the whole defect. `custom.doc_sign` accepts\n * exactly one field, a text column whose format is `signature`, and it is granted to\n * `authenticated`; the Documents screen told a person in so many words to go and declare\n * one; and no list any screen could read named it, so the control did not exist and the\n * e-sign half of Documents was unreachable from the product. A kind the store takes and no\n * screen offers is invisible, and nothing failed — which is the only reason it survived.\n *\n * `custom.field_kinds()` is now the ONE registry and `DECLARABLE_FIELD_KINDS` is generated\n * from it, so the next kind the store learns arrives here as a TYPE ERROR in\n * `FIELD_TYPE_CHOICES`'s coverage and as a red `kindsWithNoChoice()` below — never as a\n * silence.\n */\nexport type PickableFieldType = DeclarableFieldKind | SystemFieldKind | \"entity_reference\" | NewerFieldKind | LookFieldKind;\n\n/**\n * A KIND THAT IS A PLAIN COLUMN WEARING A LOOK (grids review 3, lane H item 5). The store keeps a\n * column's \"Shows as\" on the Field (`display_format`, `custom.display_format_ids()` has `rating` and\n * `time`), so a Rating is a whole number shown as stars and a Time is a time of day kept as its\n * 24-hour text — declared through the ordinary door (`{ plain, display_format }`) the same way the\n * \"Shows as\" picker makes one. Offered whenever the store does not yet publish the kind as its own\n * word (`custom.field_kinds()`): a Rating the store publishes goes as `{ type: \"rating\", max }`.\n */\nexport type LookFieldKind = \"time\";\n\nexport interface LookKind {\n plain: \"number\" | \"text\";\n look: (args: { ratingMax: number }) => { id: string; options?: Record<string, unknown> };\n}\n\nexport const LOOK_KINDS: Partial<Record<PickableFieldType, LookKind>> = {\n rating: { plain: \"number\", look: ({ ratingMax }) => ({ id: \"rating\", options: { ratingMax } }) },\n time: { plain: \"text\", look: () => ({ id: \"time\" }) },\n};\n\n/** Is this kind declared as a plain column wearing a look (because the store does not publish it)? */\nexport function declaredAsLook(kind: string): boolean {\n return kind in LOOK_KINDS && !storePublishesKind(kind);\n}\n\n/**\n * LANE 10 P4: THE NINE NEWER KINDS (rating, duration, created by, last changed by, status, address,\n * barcode, formatted text, count). Each is listed in `FIELD_TYPE_CATALOGUE` below, so every reader\n * (Settings, the column panel, every layout) names a column of one by its own word; the MENU offers\n * one only once `custom.field_kinds()` publishes it (after the chair's apply and\n * `pnpm records:generate`), so a person is never offered a kind the live store would refuse.\n */\nexport function storePublishesKind(kind: string): boolean {\n return DECLARABLE_FIELD_KINDS.some((row) => (row.kind as string) === kind);\n}\n\n/**\n * LANE SC-R: a column that points at a PLATFORM thing (a note, a web site, an agent). Its menu entry\n * is drawn only once `custom.field_kinds()` publishes `entity_reference` (after the chair's apply\n * and `pnpm records:generate`), so the menu never offers a kind the live store would refuse.\n */\nexport const STORE_PUBLISHES_ENTITY_REFERENCE = DECLARABLE_FIELD_KINDS.some(\n (row) => (row.kind as string) === \"entity_reference\",\n);\n\n/**\n * THE STORE'S OWN STAMPS AS COLUMNS (GRID-PRIMITIVES G5; TABLE-PARITY H2 H3, lane\n * DEFAULT-GRID-PARITY). `custom.field_declare` takes these three WORDS and makes each a formula\n * Field whose expression is the system node (`fx.autonumber`, `fx.created_time`,\n * `fx.modified_time`, `config.system` naming which), so nobody types into them and every reader\n * that serves a worked-out value serves them. `custom.field_kinds()` does not publish them,\n * because each is a formula, not a behaviour of its own. So they are named here, sent as their\n * word through the `{ type }` arm, and a new autonumber column numbers the records already in\n * the table through `custom.autonumber_backfill`.\n */\nexport type SystemFieldKind = \"autonumber\" | \"created_time\" | \"modified_time\";\n\nexport const SYSTEM_FIELD_KINDS: readonly SystemFieldKind[] = [\"autonumber\", \"created_time\", \"modified_time\"];\n\nexport function isSystemFieldKind(id: string): id is SystemFieldKind {\n return (SYSTEM_FIELD_KINDS as readonly string[]).includes(id);\n}\n\nexport interface FieldTypeChoice {\n id: PickableFieldType;\n /** The word on the menu. */\n label: string;\n /** One line, under the word, saying what it is FOR. Never what it is made of. */\n explanation: string;\n /** The heading it sits under, so seventeen choices read as four short lists. */\n group: \"Words\" | \"Numbers and dates\" | \"Choices and people\" | \"Worked out\";\n}\n\n/**\n * EVERY KIND THIS PACKAGE CAN NAME AND DRAW, in menu order. The menu (`FIELD_TYPE_CHOICES`) is this\n * list less the kinds the live store does not take yet; every reader names a column from this one.\n */\nexport const FIELD_TYPE_CATALOGUE: FieldTypeChoice[] = [\n { id: \"text\", group: \"Words\", label: \"Text\", explanation: \"A short line of writing — a name, a reference, a title.\" },\n { id: \"long_text\", group: \"Words\", label: \"Long text\", explanation: \"Several lines — a description, notes, an address.\" },\n { id: \"rich_text\", group: \"Words\", label: \"Formatted text\", explanation: \"Notes with bold, lists and links.\" },\n { id: \"email\", group: \"Words\", label: \"Email address\", explanation: \"An email address, checked as you type and ready to write to.\" },\n { id: \"phone\", group: \"Words\", label: \"Phone number\", explanation: \"A phone number, checked as you type.\" },\n { id: \"url\", group: \"Words\", label: \"Link\", explanation: \"A web address that opens in a new tab when you click it.\" },\n { id: \"address\", group: \"Words\", label: \"Address\", explanation: \"A street address in parts, opened in maps.\" },\n { id: \"barcode\", group: \"Words\", label: \"Barcode\", explanation: \"A code a scanner reads, like a wristband or a box.\" },\n { id: \"button\", group: \"Words\", label: \"Button\", explanation: \"A button on each record that opens a link or runs an action.\" },\n\n { id: \"number\", group: \"Numbers and dates\", label: \"Number\", explanation: \"A plain number you can total up and sort by.\" },\n { id: \"currency\", group: \"Numbers and dates\", label: \"Money\", explanation: \"An amount of money, shown with its currency wherever it appears.\" },\n { id: \"percent\", group: \"Numbers and dates\", label: \"Percentage\", explanation: \"A number out of a hundred, kept between 0 and 100.\" },\n { id: \"rating\", group: \"Numbers and dates\", label: \"Rating\", explanation: \"A score in stars, set with one click.\" },\n { id: \"duration\", group: \"Numbers and dates\", label: \"Duration\", explanation: \"A length of time, typed as 45 min or 1:30.\" },\n { id: \"time\", group: \"Numbers and dates\", label: \"Time\", explanation: \"A time of day with no date — a shift start, opening hours.\" },\n { id: \"datetime\", group: \"Numbers and dates\", label: \"Date\", explanation: \"A day, or a day and a time. Dates are what the calendar view reads.\" },\n\n { id: \"select\", group: \"Choices and people\", label: \"Choice\", explanation: \"One answer from a list you write here. Choices are what the board view groups by.\" },\n { id: \"multi_select\", group: \"Choices and people\", label: \"Several choices\", explanation: \"Any number of answers from a list you write here.\" },\n { id: \"status\", group: \"Choices and people\", label: \"Status\", explanation: \"Choices grouped into To do, In progress and Done.\" },\n { id: \"checkbox\", group: \"Choices and people\", label: \"Yes / no\", explanation: \"A box you tick. Left alone it stays unanswered, which is not the same as a no.\" },\n { id: \"member\", group: \"Choices and people\", label: \"Person\", explanation: \"Somebody in this organization, picked from the people who are in it.\" },\n { id: \"attachment\", group: \"Choices and people\", label: \"File\", explanation: \"A file or a picture kept with the record.\" },\n { id: \"signature\", group: \"Choices and people\", label: \"Signature\", explanation: \"Somebody's sign-off on a document made from this record. Nobody types in it — it fills in when they sign.\" },\n { id: \"relation\", group: \"Choices and people\", label: \"Points at another record\", explanation: \"A link to records in another of your tables — the customer a job is for, the lines on an invoice.\" },\n {\n id: \"entity_reference\",\n group: \"Choices and people\",\n label: \"Points at something else on the platform\",\n explanation: \"A note, a web site, an agent, a workbook — anything you keep here that is not one of your tables.\",\n },\n\n { id: \"lookup\", group: \"Worked out\", label: \"Borrowed value\", explanation: \"A value read from a record this one points at, kept in step with it.\" },\n { id: \"rollup\", group: \"Worked out\", label: \"Total of linked records\", explanation: \"A count or a total worked out from the records this one points at.\" },\n { id: \"count\", group: \"Worked out\", label: \"Count of linked records\", explanation: \"How many records this one points at.\" },\n { id: \"formula\", group: \"Worked out\", label: \"Worked out from other columns\", explanation: \"A value this record works out for itself from its own other columns.\" },\n { id: \"autonumber\", group: \"Worked out\", label: \"Record number\", explanation: \"A number the table gives each record, one after another, never reused. Records already here are numbered in the order they were made.\" },\n { id: \"created_time\", group: \"Worked out\", label: \"Created time\", explanation: \"When each record was made. Nobody types it.\" },\n { id: \"modified_time\", group: \"Worked out\", label: \"Last changed time\", explanation: \"When each record last changed. Nobody types it.\" },\n { id: \"created_by\", group: \"Worked out\", label: \"Created by\", explanation: \"Who made each record. Nobody types it.\" },\n { id: \"modified_by\", group: \"Worked out\", label: \"Last changed by\", explanation: \"Who last changed each record. Nobody types it.\" },\n];\n\n/** The kinds the menu offers only once the live store publishes them. */\nconst GATED_KINDS = new Set<string>([\"entity_reference\", ...NEWER_FIELD_KINDS]);\n\nexport const FIELD_TYPE_CHOICES: FieldTypeChoice[] = FIELD_TYPE_CATALOGUE.filter(\n (c) => !GATED_KINDS.has(c.id) || storePublishesKind(c.id) || c.id in LOOK_KINDS,\n);\n\nexport const FIELD_TYPE_GROUPS: FieldTypeChoice[\"group\"][] = [\n \"Words\",\n \"Numbers and dates\",\n \"Choices and people\",\n \"Worked out\",\n];\n\nconst BY_ID = new Map<string, FieldTypeChoice>(FIELD_TYPE_CATALOGUE.map((c) => [c.id, c]));\n\nexport function fieldTypeChoice(id: string): FieldTypeChoice | undefined {\n return BY_ID.get(id);\n}\n\n/** The three that are a plain behaviour rather than one of the fourteen. */\nexport function isPlainFieldType(id: string): id is PlainFieldType {\n return id === \"text\" || id === \"long_text\" || id === \"number\";\n}\n\n/**\n * The one that is a relation a person aims themselves. It is neither plain nor\n * one of the thirteen, so every caller that branched on `isPlainFieldType`\n * alone has to answer this question too — which is why it is a named function\n * and not an inline string comparison at four call sites.\n */\nexport function isRelationFieldType(id: string): id is RelationFieldType {\n return id === \"relation\";\n}\n\n/**\n * One of FLD-11's fourteen, which is what `parity_type` on a declaration means.\n *\n * Read from the store's own generated floor, never from a list here — because a kind that\n * is NOT one of the fourteen (plain text, a person-aimed relation, a signature) has to be\n * declared by its WORD (`type`) and a panel that sent `parity_type` for it would be refused\n * \"There is no field type called …\". That is the shape of the F6 defect: the panel's `save`\n * had exactly two branches, relation and plain, and everything else fell into `parity_type`.\n */\nexport function isParityFieldType(id: string): id is ParityFieldType {\n return PARITY_FIELD_TYPES.some((row) => row.parity_type === id);\n}\n\n/**\n * THE GUARD THIS FILE NEEDS, because the list it explains is generated.\n *\n * Returns the parity types the store ships that nothing here explains. The\n * suite asserts it is empty; a fourteenth type would otherwise reach the menu\n * with a blank line under it and nobody would notice until a person did.\n *\n * `relation` is deliberately NOT one of the thirteen and therefore never\n * appears in this answer: `PARITY_FIELD_TYPES` is the store's own generated\n * list and a behaviour that carries no parity type is not in it.\n */\nexport function parityTypesWithNoExplanation(): string[] {\n return PARITY_FIELD_TYPES.map((row) => row.parity_type).filter((type) => !BY_ID.has(type));\n}\n\n/**\n * 🚨 THE GUARD THAT CLOSES THE CLASS (FIX-10B-F6).\n *\n * `parityTypesWithNoExplanation()` above watches the parity FLOOR, and the floor was never\n * the whole list: the store also declares plain text, long text, number, a person-aimed\n * relation and a signature, and for months nothing anywhere compared the panel's menu with\n * THAT. So `signature` — the one field `custom.doc_sign` accepts, on a door granted to\n * every signed-in person, named to the person by the Documents screen itself — was absent\n * from the menu and every check stayed green.\n *\n * This returns the kinds `custom.field_kinds()` publishes that this panel does not offer.\n * The suite asserts it is empty, so a kind the store learns tomorrow either reaches the\n * person or turns a test red the same day. It is the class, not the instance: it would have\n * caught `signature`, and it will catch the twentieth kind nobody has thought of yet.\n */\nexport function kindsWithNoChoice(): string[] {\n return DECLARABLE_FIELD_KINDS.map((row) => row.kind).filter((kind) => !BY_ID.has(kind));\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// THE WORDS ON THE TWO BUTTONS, IN ONE PLACE — because they used to be the SAME\n// WORDS in two places, and that cost somebody their column.\n//\n// 🚨 THE DEFECT (TAILS-5, 2026-09-21, measured while driving the panel headless\n// on Rincon Plumbing's Summerland branch). The Jobs toolbar's control that OPENS\n// the field panel read exactly \"Add field\", and the panel's own SAVE button read\n// exactly \"Add field\" too — `FieldEditor` says \"Save field\" only when EDITING an\n// existing column, so on the create path the two were character-identical. The\n// toolbar control is a TOGGLE: pressing it while the panel is open closes the\n// panel and throws away everything typed into it. So a person who typed a column\n// name, chose a type, picked the target table and its display columns, then\n// looked up at the words they were told to press, could lose all of it — with no\n// sentence, no request sent, and nothing to say it had happened. A walk written\n// by an agent lost the column twice that way and spent a round diagnosing the\n// store before reading the two labels side by side.\n//\n// WHY THEY LIVE HERE AND NOT IN `@ai-matrx/design-system`. The words are RECORDS\n// vocabulary — \"field\", \"column\" — and the design system knows nothing about\n// either; a labels module there would be a domain word in a generic package, and\n// the next person adding a button would not find it. This file is already the\n// one place that owns what a person READS about a column (`FIELD_TYPE_CHOICES`\n// is right above), and both surfaces that draw these buttons are in this\n// package. One module, one import each, and `fieldTypes.test.ts` asserts the two\n// can never be the same string again.\n//\n// THE RULE: the control that OPENS a panel and the control that COMMITS it never\n// read the same words. The opener is an invitation; the committer says what it\n// will make.\n\n/** The toolbar control that OPENS the add-a-column panel. An invitation. */\nexport const ADD_FIELD_OPEN_LABEL = \"Add column\";\n\n/** The panel's own primary, on the CREATE path. It says what pressing it makes. */\nexport const ADD_FIELD_SAVE_LABEL = \"Create column\";\n\n/** The panel's own primary when an existing column is being changed. */\nexport const EDIT_FIELD_SAVE_LABEL = \"Save column\";\n","// src/names.ts — @ai-matrx/records-ui\n//\n// WHAT A PERSON READS, NEVER WHAT THE MACHINE STORES.\n//\n// Measured on the real screens (independent verdict, 19 September): a table row\n// read `Saved views · 9 fields · records_ui_view`, a relation cell read a bare\n// `8f2c…` identifier, a header read `stage` because the Field's label was\n// blank, and the type word on a column tooltip read `long_text`. Airtable,\n// Notion and Linear never show a person an internal name; the verdict called\n// this one of the three things a first-time user feels within a minute.\n//\n// So every place this package prints something a person reads goes through one\n// of these three functions. They are deliberately dumb: they choose the best\n// human string that IS AVAILABLE and, when none is, say what the thing is\n// rather than printing the token. No screen in this package formats a name of\n// its own any more.\n\nimport type { Field, ReadRow, RecordDocument, Table } from \"@ai-matrx/records\";\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\n\n/** The name of one Field, as a header, a form label or a peek's term. */\nexport function fieldName(field: Field): string {\n const label = (field.label ?? \"\").trim();\n // A LABEL THAT IS ONLY A MACHINE KEY is not a name (merged-grid review 2026-09-26): a table made\n // by an import or an agent kept `label: \"job_no\"`, and the header read `job_no`. A key joined by\n // underscores is written the way a person writes it (\"Job no\"). A single lowercase word the\n // owner typed (\"mobile\", \"title\") is their own words and is shown as they wrote it.\n if (label !== \"\" && label === field.key && /^[a-z0-9]+(?:[_.-][a-z0-9]+)+$/.test(label)) return humanizeIdentifier(label);\n if (label !== \"\") return label;\n const name = (field.name ?? \"\").trim();\n if (name !== \"\") return name;\n return humanizeIdentifier(field.key);\n}\n\n/** The name of one Table, as a card, a heading or a breadcrumb. */\nexport function tableName(table: Table): string {\n const name = (table.name ?? \"\").trim();\n if (name !== \"\") return name;\n const singular = (table.label_singular ?? \"\").trim();\n if (singular !== \"\") return singular;\n return humanizeIdentifier(table.slug ?? \"\");\n}\n\n/**\n * The name of one RECORD, for a chip, a card, a relation cell or a peek title.\n *\n * `titleKey` is the Table's own `title_field` when the caller knows the Table —\n * that is the store's answer to \"what makes this record a chip\" (REC-2) — and\n * the conventional keys are tried after it. A record with nothing readable is\n * NOT shown as a truncated uuid: it says it has no name yet, because \"8f2c1b0a\"\n * tells a person nothing and looks like a bug.\n */\nexport function recordName(\n document: RecordDocument | undefined,\n titleKey?: string | null,\n fallback = \"Untitled\",\n): string {\n const data = (document ?? {}) as Record<string, unknown>;\n const keys = [titleKey, \"title\", \"name\", \"label\", \"full_name\", \"subject\", \"summary\"].filter(\n (key): key is string => typeof key === \"string\" && key !== \"\",\n );\n for (const key of keys) {\n const value = data[key];\n // AN ID IS NEVER A NAME, AND THIS FUNCTION USED TO RETURN ONE (TAILS-2, 2026-09-21).\n // A Table's title column may be a RELATION, and a relation's stored value IS the other\n // record's id (FLD-6 / REL-1) — so `recordName` handed every caller a bare uuid for\n // every Table titled that way, which is how the board's unplaced list came to read\n // \"11 records are not in any of these columns — ca5f1ac7-…\". A caller that can resolve\n // the id resolves it (`scalarText` with the label lookup); a caller that cannot is\n // better off reading the next column, and then the fallback, than a hex number.\n if (typeof value === \"string\" && value.trim() !== \"\" && !looksLikeId(value.trim())) {\n return value.trim();\n }\n if (typeof value === \"number\") return String(value);\n }\n return fallback;\n}\n\n\n/**\n * Is this string the store's id for something, rather than words a person wrote?\n *\n * The same question `custom._card_words` asks on the database, with the same regex, so the\n * screen and the store agree about what is a name (TAILS-2, 2026-09-21).\n */\nexport function looksLikeId(value: unknown): boolean {\n return typeof value === \"string\" && isUuidShape(value.trim());\n}\n\n/** The same question for a row the read door returned. */\nexport function rowName(row: ReadRow | undefined, titleKey?: string | null, fallback = \"Untitled\"): string {\n return recordName(row?.document, titleKey, fallback);\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════════════\n// NAMING A RECORD WHOSE TABLE YOU ALREADY HOLD — ONE CALL, NOT A COPY PER SCREEN.\n// ═══════════════════════════════════════════════════════════════════════════════════════\n//\n// 🚨 WHY THESE TWO EXIST (lane RELATION-DISPLAY-2, 2026-09-21).\n//\n// `check:one-reference-builder` shipped with a baseline of SIX, and its own header said the\n// number was not zero because \"moving six surfaces onto the store door is real work\". Three\n// of the six were not asking the store's question at all. `Grid.tsx` names the row a person\n// is looking at for the Talk action; `Peek.tsx` names the record being peeked at;\n// `PortalsPanel.tsx` names the rows of the portal's own client Table; and this repo's\n// `TryEverythingScreen.tsx` does the same in two places. NONE of them is resolving a\n// RELATION — they hold the Table and they hold the document, and there is nothing to ask a\n// door about. What they were each doing by hand was the two-line join between them:\n//\n// recordName(row.document, table.title_field)\n//\n// Written out five times in four files, which is how a Table whose title column is `cname`\n// came to read \"Untitled\" on one screen and correctly on the next. It is the same question\n// as the store's, one rung down the ladder, and the same one answer should serve it — so it\n// lives HERE, in the file the guard exempts BY CONSTRUCTION as the primitive itself, and\n// every screen calls it instead of re-deriving it.\n//\n// WHAT THESE ARE NOT. They are not a second resolver and must never become one. They take a\n// Table a caller ALREADY HAS and a document it ALREADY HAS. The moment a caller is holding\n// an ID and wants words, that is the store's question and the answer is\n// `client.relationWords` / `client.relationWordsMany` — which ask the read-access ladder\n// BEFORE they read a name, apply that column's own display spec, and return the withheld\n// sentence for a record the reader may not open. Nothing in here can do any of that, and\n// nothing in here should try.\n\n/** A Table as far as naming is concerned — its own declared title column (REC-2). */\ntype TitledTable = Pick<Table, \"title_field\"> | null | undefined;\n\n/**\n * THE NAME OF A RECORD WHOSE TABLE YOU ALREADY HOLD.\n *\n * `table` is the Table the record belongs to; its `title_field` is the store's answer to\n * \"what makes this record a chip\" (REC-2) and is tried first, then the conventional keys,\n * then the fallback. A Table that has not loaded yet is `null` and the conventional keys\n * still answer — a name arriving a tick late is better than a screen that shows nothing.\n */\nexport function recordNameIn(\n table: TitledTable,\n document: RecordDocument | undefined,\n fallback = \"Untitled\",\n): string {\n return recordName(document, table?.title_field ?? null, fallback);\n}\n\n/**\n * THE NAME A CHANGE NOTICE USES — the record as it is AFTER the change (merged-grid tails,\n * 2026-09-26). Typing a first name into a row's label column read \"Changed Title on Untitled\":\n * the notice named the row from the document held before the write. The row is called what it is\n * called now; only when the change emptied its name does the notice use the name it had.\n */\nexport function changedRecordName(\n table: TitledTable,\n document: RecordDocument | undefined,\n key: string,\n after: unknown,\n): string {\n const now = recordName({ ...((document ?? {}) as Record<string, unknown>), [key]: after } as RecordDocument, table?.title_field ?? null, \"\");\n return now !== \"\" ? now : recordNameIn(table, document);\n}\n\n/** The same, for a row the read door returned. */\nexport function rowNameIn(table: TitledTable, row: ReadRow | undefined, fallback = \"Untitled\"): string {\n return recordName(row?.document, table?.title_field ?? null, fallback);\n}\n\n/**\n * WHAT A RELATION CHIP SAYS WHEN THE RECORD IT POINTS AT IS NOT YOURS.\n *\n * A relation joins two records in two tables, and holding one end says nothing\n * about the other: a Job shared with you may point at a Client nobody shared.\n * The chip then has three possible answers and only one of them is honest —\n * the target's TITLE is a leak, a bare id is a bug with a hex number in it, and\n * a permanent \"Loading…\" is a lie that never resolves.\n *\n * This is the SAME sentence `platform.relation_withheld_label()` answers on the\n * database, word for word, so a person reads one wording whether the screen or\n * the store worked it out. Changing it changes both (RELATION-DECLARE,\n * 2026-09-20).\n */\nexport const WITHHELD_RECORD_LABEL = \"A record you have not been given access to\";\n/**\n * WHEN THE STORE COULD NOT BE ASKED (a 503, a dropped connection) the name is UNREAD, not\n * withheld: saying \"not given access\" for a failed read lies about the data (W1.1 verifier,\n * 2026-10-02). This is what a reference reads until a later read answers.\n */\nexport const UNREAD_RECORD_LABEL = \"Couldn't load this name\";\n\n/**\n * THE PLURAL A PERSON READS, NEVER A MACHINE'S \"…ss\" (VERIFIER-16 M3 / VERIFIER-17 M3).\n *\n * A table the store or the mover never gave a real plural carries `name + \"s\"` — so a table\n * already named in the plural reads \"Customerss\", \"Status optionss\". That word was made by a\n * machine appending one letter, and it says nothing the name does not; it is never shown.\n * Returns the table's own plural when a person (or the example library) wrote one, and `null`\n * when the only plural on record is that appended letter.\n */\nexport function realPlural(table: { name?: string | null; label_singular?: string | null; label_plural?: string | null }): string | null {\n const plural = (table.label_plural ?? \"\").trim();\n if (plural === \"\") return null;\n for (const base of [table.name, table.label_singular]) {\n const b = (base ?? \"\").trim();\n if (b !== \"\" && plural === `${b}s`) return null;\n }\n return plural;\n}\n\n/**\n * ONE RECORD'S NOUN, IN A SENTENCE (\"Book a 30-minute visit\") — lane HANDOVER, 2026-09-28.\n *\n * Cedar Ridge Physical Therapy's booking page was titled \"Book a 30-minute Visits appointment\":\n * the table's NAME (a plural, a heading) was put where one record's noun goes. The noun is the\n * table's own singular (\"Visit\"), else its name, else the fallback; a Title-case word is written\n * the way a sentence writes it (\"visit\"), an acronym is kept (\"MRI scan\").\n */\nexport function singularNoun(\n table: { name?: string | null; label_singular?: string | null } | null | undefined,\n fallback = \"record\",\n): string {\n const word = (table?.label_singular ?? \"\").trim() || (table?.name ?? \"\").trim() || fallback;\n return word\n .split(/\\s+/)\n .map((w) => (/^[A-Z][a-z'’-]*$/.test(w) ? w.toLowerCase() : w))\n .join(\" \");\n}\n\n/**\n * A plural for a sentence (\"Check in ran on 2 appointments\"): the table's real plural, else the\n * singular with an \"s\" only when that does not double a final \"s\".\n */\nexport function pluralNoun(table: { name?: string | null; label_singular?: string | null; label_plural?: string | null } | null | undefined, fallback = \"record\"): string {\n const real = table ? realPlural(table) : null;\n if (real) return real;\n const singular = (table?.label_singular ?? \"\").trim() || fallback;\n return /s$/i.test(singular) ? singular : `${singular}s`;\n}\n\n\n// ═══════════════════════════════════════════════════════════════════════════════════════\n// WHAT A CARD IS TITLED BY (lane UI-FIX-18, VERIFIER-18 H5).\n// ═══════════════════════════════════════════════════════════════════════════════════════\n//\n// MEASURED 2026-09-24 on production: *ZZZ UI-QUICK-1 Rincon-style Jobs* (title column `title`)\n// grouped by Stage titled every kanban card \"false\" or \"true\". The board took the FIRST Field\n// the read door answered that was not the group column — here the *Urgent* checkbox — as the\n// title. A card is named by what names its record: the Table's own `title_field` first (REC-2),\n// then the conventional name keys, then the first words column in declared order. A yes/no\n// column, the column the board is grouped by and the store's own stamps never title a card.\n\nconst CONVENTIONAL_TITLE_KEYS = [\"title\", \"name\", \"label\", \"full_name\", \"subject\", \"summary\"];\n\nfunction canTitle(field: Field, excluded: ReadonlySet<string>): boolean {\n if (excluded.has(field.key)) return false;\n if (field.type === \"boolean\") return false;\n if (field.type === \"formula\" && (field.config ?? {})[\"system\"]) return false;\n return true;\n}\n\n/**\n * THE FIELD A CARD IS TITLED BY — kanban, calendar, gallery and pipeline alike.\n *\n * Order: the Table's `title_field` → a conventional name key (`title`, `name`, …) → the first\n * text column in declared `sort` order → the first other column that can title (never a\n * checkbox, never the group column, never a system stamp). `undefined` when nothing can, and\n * the card falls back to `rowName`, which says \"Untitled\" rather than \"false\".\n */\nexport function cardTitleField(\n fields: readonly Field[],\n titleKey: string | null | undefined,\n exclude: readonly (string | null | undefined)[] = [],\n): Field | undefined {\n const excluded = new Set(exclude.filter((k): k is string => typeof k === \"string\" && k !== \"\"));\n const ordered = [...fields].sort((a, b) => (a.sort ?? 100) - (b.sort ?? 100) || a.key.localeCompare(b.key));\n const byKey = (key: string) => ordered.find((f) => f.key === key && canTitle(f, excluded));\n if (titleKey) {\n const declared = byKey(titleKey);\n if (declared) return declared;\n }\n for (const key of CONVENTIONAL_TITLE_KEYS) {\n const found = byKey(key);\n if (found) return found;\n }\n return (\n ordered.find((f) => f.type === \"text\" && canTitle(f, excluded)) ?? ordered.find((f) => canTitle(f, excluded))\n );\n}\n","\"use client\";\n\n// src/RelationPicker.tsx — @ai-matrx/records-ui · SCR-N-2\n//\n// THE ONE GENERIC RELATION PICKER. Before it, every relation-shaped field in\n// the product had a type-specific picker (image, file, url, scope) and a plain\n// `relation` field was not editable at all.\n//\n// It reads the target Table's records through the read door, shows each one as\n// its own chip (REC-2: the title field is what makes a record a chip), and\n// respects `relation_max` by saying the number rather than silently dropping a\n// pick.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { Field, ReadRow, RecordsError, Table, Uuid } from \"@ai-matrx/records\";\nimport { rankTypedMatches } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { BasicInput, Button, cn } from \"@ai-matrx/design-system\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { RecordChip } from \"./editors\";\nimport { UNREAD_RECORD_LABEL, WITHHELD_RECORD_LABEL, fieldName } from \"./names\";\nimport { RefusalLine, RefusalNotice } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { tellApart } from \"./tellApart\";\n\nexport interface RelationPickerProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n /**\n * WHETHER A PERSON MAY MAKE THE THING SHE IS LOOKING FOR (RELATION-CREATE, 2026-09-22).\n *\n * On by default, because that is what this control is for on every surface a\n * person fills a record in: the grid cell, the generated form, a public form\n * runner. The one surface that passes `false` is the filter builder — picking\n * a value to FILTER by is not a reason to put a new customer in the book, and\n * a Create button there would write a row nobody asked for.\n */\n allowCreate?: boolean | undefined;\n /**\n * A SINGLE LINK'S PICK IS ITS COMMIT in a grid cell (Enter on the highlighted match, or a click):\n * called after a one-record column picks a record, so the cell saves without a second Save.\n */\n onPicked?: (() => void) | undefined;\n /**\n * IN A GRID CELL the list is open from the start and hangs from the cell (lane CELL-EDITORS,\n * 2026-10-06): no \"Pick\" button over a Save / Cancel row. Closing it is the cell's commit.\n */\n autoOpen?: boolean | undefined;\n /** The list closed: the cell commits what is picked. */\n onClose?: (() => void) | undefined;\n /** Escape in a grid cell's list: the cell's cancel — nothing is written (`PickOrAdd.onEscape`). */\n onCancel?: (() => void) | undefined;\n}\n\n/**\n * The sentence this control shows on a screen served to somebody with NO ACCOUNT.\n *\n * VERIFIER-10 finding F1, on production: a published job-request form whose\n * first question was a relation answered HTTP 500 to a stranger, because this\n * control asked `useRecordsClient` for a client that the public arm of\n * `FormRunner` deliberately never mounts — the browser on that page holds no\n * key, knows no organization and may not read a row. That is CORRECT; what was\n * wrong was asking for it with the hook that throws.\n *\n * A picker here cannot exist: searching the owner's records is exactly the read\n * `custom.form_public` refuses a stranger, and a control that offered it would\n * be the leak. So the question is ABSENT and says so, with what to do instead,\n * and the rest of the form is still answerable.\n */\nexport const NO_STORE_ON_THIS_SCREEN_REASON =\n \"This question points at a record in somebody's own data, and a page answered without an \" +\n \"account is never allowed to search that. Leave it blank — whoever receives your answer will \" +\n \"fill it in.\";\n\nexport function RelationPicker({ field, value, onChange, disabled, id, className, allowCreate = true, onPicked, autoOpen, onClose, onCancel }: RelationPickerProps) {\n // NOT `useRecordsClient`. See NO_STORE_ON_THIS_SCREEN_REASON above: this\n // control is drawn on the public form runner, which mounts no store client at\n // all, and the hook that throws took the whole page down with it.\n const client = useOptionalRecordsClient();\n const [rows, setRows] = useState<ReadRow[] | null>(null);\n // WHAT EACH ROW AND EACH PICKED ID IS CALLED — the store's answer, keyed by id.\n // Never derived here: see the block above the effect below.\n const [words, setWords] = useState<Record<string, string>>({});\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n const [search, setSearch] = useState(\"\");\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Closing the list — a pick, Escape, a click away — is what a grid cell commits on.\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n // ── MAKING THE ONE THAT IS NOT THERE YET (RELATION-CREATE, 2026-09-22).\n // A person filling in a Job whose customer has never been written down had\n // exactly one thing to read here — \"Nothing in that table matches.\" — and\n // nowhere to go: leave the record, find the Customers table, add a row, come\n // back, re-open the picker, search again. Airtable and Notion both end that\n // list with \"Create <what you typed>\", and so does this one now. It is added\n // HERE, in the one generic relation picker, so the grid cell, the generated\n // record form, the form runner and every future relation surface inherit it\n // from the same control instead of each growing its own.\n const [target, setTarget] = useState<Table | null>(null);\n const [targetRefusal, setTargetRefusal] = useState<RecordsError | null>(null);\n const [creating, setCreating] = useState(false);\n const [newTitle, setNewTitle] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [createRefusal, setCreateRefusal] = useState<RecordsError | null>(null);\n\n const picked = useMemo<string[]>(\n () => (Array.isArray(value) ? value.map(String) : value === null || value === undefined ? [] : [String(value)]),\n [value],\n );\n\n // ── THE TARGET'S ROWS, ON MOUNT AND NOT ON OPEN (RELATION-DECLARE, 2026-09-20).\n // This used to wait for the popover, so every chip on every relation cell read\n // \"Loading…\" until somebody clicked Pick — a word that never resolved, on a\n // screen nobody was going to click. A chip is a NAME; it is read far more often\n // than it is changed, so what it needs is fetched when the cell is drawn.\n //\n // WHAT IT NO LONGER FETCHES IS THE TABLE (lane RELATION-DISPLAY-2, 2026-09-21).\n // It used to read `tableList()` for the target's `title_field` and name every row\n // and every chip itself — the third of three copies of that derivation, and the\n // reason a column configured to read \"Maria Chen — Rincon\" still offered a flat\n // list of two identical \"Maria Chen\"s to pick between. The picker now shows the\n // SAME WORDS THE CELL SHOWS, because they come from the same place: this column's\n // own display spec, resolved by the store, with the ladder asked first.\n useEffect(() => {\n const target = field.relation_target;\n if (!target || !client) return;\n let cancelled = false;\n void client.list({ table_id: target as Uuid, limit: 200 }).then((result) => {\n if (cancelled) return;\n if (result.ok) setRows(result.data.rows);\n else setRefusal(result.error);\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.relation_target]);\n\n // ── AND WHAT EVERY ONE OF THEM IS CALLED — IN ONE CALL.\n // The rows this reader may see AND the ids already picked go to the store together.\n // A picked id that is not in the visible page is the interesting case: a Job shared\n // with you may point at a Client nobody shared, and the two possibilities — \"further\n // down a long list\" and \"not hers\" — have different sentences. The door tells them\n // apart, because the ladder runs inside it; a name assembled out here has already\n // been read. An id the door gives no words for reads the same sentence the store\n // itself gives (`platform.relation_withheld_label()`): never the title, never a bare\n // id, and never a \"Loading…\" that resolves for nobody.\n useEffect(() => {\n if (!rows || !client) return;\n const wanted = [...new Set([...rows.map((row) => row.id), ...picked])].filter(\n (id) => words[id] === undefined,\n );\n if (wanted.length === 0) return;\n let cancelled = false;\n void client\n .relationWordsMany({ field_id: field.id, record_ids: wanted as Uuid[] })\n .then((result) => {\n if (cancelled) return;\n const learned: Record<string, string> = {};\n for (const id of wanted) {\n const said = result.ok ? result.data[id] : undefined;\n // A FAILED read is unread, never withheld — only an answer of nothing is withheld.\n learned[id] = !result.ok\n ? UNREAD_RECORD_LABEL\n : typeof said === \"string\" && said !== \"\"\n ? said\n : WITHHELD_RECORD_LABEL;\n }\n setWords((current) => ({ ...current, ...learned }));\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id, rows, picked, words]);\n\n // ── THE TARGET TABLE, READ ONLY WHEN SOMEBODY OPENS THE PICKER.\n // Deliberately NOT on mount: `RelationPicker` is drawn on every relation cell\n // of every row, and the read above was cut back to the rows for exactly that\n // reason (RELATION-DISPLAY-2). What a create needs — the Table's own name and\n // its `title_field` — is only needed once a person has opened the control, so\n // it is fetched then and cached for the life of the cell.\n useEffect(() => {\n if (!open || !allowCreate || target || targetRefusal || !client) return;\n const id = field.relation_target;\n if (!id) return;\n let cancelled = false;\n void client.tableList().then((result) => {\n if (cancelled) return;\n if (!result.ok) {\n setTargetRefusal(result.error);\n return;\n }\n const found = result.data.find((t) => t.id === id) ?? null;\n if (found) setTarget(found);\n else\n setTargetRefusal(\n refusalOf(\n \"door\",\n \"That Table is not one you can open, so a new record cannot be added to it from here.\",\n ),\n );\n });\n return () => {\n cancelled = true;\n };\n }, [client, open, allowCreate, target, targetRefusal, field.relation_target]);\n\n if (!client) {\n // ABSENT AND HONEST, never a dead popover. No store client is mounted on\n // this screen at all, which on a public form is the correct posture.\n return (\n // The Field's own name is already printed above this control by\n // `FieldLabel`, so the sentence does not say it a second time.\n <p id={id} className={cn(\"text-xs text-muted-foreground\", className)}>\n {NO_STORE_ON_THIS_SCREEN_REASON}\n </p>\n );\n }\n\n if (!field.relation_target) {\n // Absent, and honest about why: a relation with no declared target is a\n // Field the store has not finished, not a picker that \"has no options\".\n return (\n <p className=\"text-xs text-muted-foreground\">\n {fieldName(field)} points at records, but it does not say which Table yet, so there is nothing to pick\n from. A table admin sets its target in the field editor.\n </p>\n );\n }\n\n // A chip carries the record's NAME. Before `names.ts`, a relation whose target had\n // not loaded yet drew `8f2c1b0a` — a bare identifier, which the verdict of 19\n // September counted among the three things a first-time user feels within a minute.\n // It now reads THIS COLUMN'S OWN WORDS, resolved by the store: the same string the\n // cell shows, so what a person picks from and what they then read back are never two\n // different answers. A record that is not this reader's says so in the store's own\n // words instead of waiting forever.\n const titleOf = (recordId: string) => words[recordId] ?? \"Loading…\";\n const full = field.multi && field.relation_max !== null && picked.length >= field.relation_max;\n\n const toggle = (recordId: string) => {\n if (!field.multi) {\n const choosing = picked[0] !== recordId;\n onChange(choosing ? recordId : null);\n setOpen(false);\n // After the draft has taken the pick, so the cell saves what was just chosen.\n if (choosing && onPicked) setTimeout(onPicked, 0);\n return;\n }\n const next = new Set(picked);\n if (next.has(recordId)) next.delete(recordId);\n else if (!full) next.add(recordId);\n onChange(next.size === 0 ? null : [...next]);\n };\n\n // WHAT THE NEW ONE IS CALLED IN THE BUTTON — the Table's own singular label if\n // it has one, its name otherwise. Never a hardcoded \"item\": a person adding a\n // customer reads \"New customer\".\n const targetWord = (target?.label_singular ?? \"\").trim() || (target?.name ?? \"\").trim() || \"record\";\n\n const create = async (rawTitle: string) => {\n const title = rawTitle.trim();\n const tableId = field.relation_target;\n if (!tableId || title === \"\" || busy) return;\n if (!target) {\n // Cannot happen from the rendered control (it draws only once the Table is\n // in hand), and if it ever does the person is told rather than ignored.\n setCreateRefusal(refusalOf(\"unreachable\", \"Still reading that Table.\", \"Try again in a moment.\"));\n return;\n }\n const titleField = target.title_field;\n if (!titleField) {\n // ABSENT AND HONEST, never a dead button: REC-2 says a record without a\n // title column cannot be a chip, so a row made here would come back\n // nameless. The remedy names who can fix it and where.\n setCreateRefusal(\n refusalOf(\n \"not_supported\",\n `${target.name} has no column that names a record yet, so a new one would have nothing to show here.`,\n \"A table admin picks its title column in that table's settings.\",\n ),\n );\n return;\n }\n setBusy(true);\n setCreateRefusal(null);\n const written = await client.recordWrite({ table_id: tableId as Uuid, data: { [titleField]: title } });\n if (!written.ok) {\n setBusy(false);\n setCreateRefusal(written.error);\n return;\n }\n const createdId = String(written.data);\n // THE NEW ROW AND ITS WORDS COME BACK FROM THE STORE, never assembled here:\n // this column's display spec may join two of the target's columns, and the\n // only body that knows that is the door (`custom.relation_words_many`). The\n // words effect above picks the new id up because `picked` now carries it.\n const refreshed = await client.list({ table_id: tableId as Uuid, limit: 200 });\n if (refreshed.ok) setRows(refreshed.data.rows);\n setBusy(false);\n setCreating(false);\n setNewTitle(\"\");\n setSearch(\"\");\n toggle(createdId);\n };\n\n // Two records with one name carry the words that tell them apart (see tellApart.ts),\n // and a search reads those words too — \"Sunset\" finds the Patricia Marsh on Sunset Blvd.\n const apart = tellApart(rows ?? [], titleOf);\n // THE ONE RANKING (`rankTypedMatches`, grids review 3): the name ranks exact, starts with, a word\n // starts with, contains; the words that tell two apart only ever find a record.\n const visible = rankTypedMatches(rows ?? [], search, (row) => [titleOf(row.id), apart.get(row.id) ?? \"\"]);\n\n const anchored = autoOpen === true;\n const cellChips = picked.map((recordId) => (\n <RecordChip\n key={recordId}\n title={titleOf(recordId)}\n {...(disabled || anchored ? {} : { onRemove: () => toggle(recordId) })}\n />\n ));\n\n return (\n // Never wider than where it is drawn (a grid cell beside a sticky column: B3-07) — chips truncate, the button wraps.\n <div className={cn(\"flex min-w-0 max-w-full flex-wrap items-center gap-1\", className)}>\n {anchored && !disabled ? null : cellChips}\n {disabled ? null : (\n // THE ONE \"PICK OR ADD\" BUILDER (PickOrAdd.tsx) — the choice editor draws the same one.\n // In a grid cell it hangs from the cell's own chips; what is picked heads the list with its ×.\n <PickOrAdd\n anchored={anchored}\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n multi={field.multi}\n chips={picked.map((recordId) => ({ id: recordId, label: titleOf(recordId), onRemove: () => toggle(recordId) }))}\n triggerId={id}\n triggerLabel={`Pick for ${fieldName(field)}`}\n triggerText={picked.length === 0 ? \"Pick\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={setSearch}\n items={visible.map((row) => ({\n id: row.id,\n label: titleOf(row.id),\n detail: apart.get(row.id) ?? null,\n picked: picked.includes(row.id),\n title: apart.has(row.id) ? `${titleOf(row.id)} — ${apart.get(row.id)}` : titleOf(row.id),\n attrs: { \"data-relation-candidate\": row.id },\n }))}\n onPick={toggle}\n notice={\n <>\n {refusal ? <RefusalLine error={refusal} className=\"p-2\" /> : null}\n {!rows && !refusal ? <p className=\"p-2 text-xs text-muted-foreground\">Reading…</p> : null}\n {full ? (\n <p className=\"p-2 text-xs text-muted-foreground\">\n {fieldName(field)} can point at {field.relation_max} at most. Remove one to add another.\n </p>\n ) : null}\n </>\n }\n empty={rows ? <p className=\"p-2 text-xs text-muted-foreground\">Nothing in that table matches.</p> : null}\n add={\n allowCreate && !full && !targetRefusal && target && !creating\n ? {\n label: search.trim() !== \"\" ? `Create “${search.trim()}”` : `New ${targetWord}`,\n disabled: busy,\n // TYPED SOMETHING THAT IS NOT THERE? That IS the name. The champions\n // (Airtable, Notion) make the search text the new record's title in one\n // press; an empty box asks for one.\n onAdd: () => {\n if (search.trim() !== \"\") void create(search);\n else {\n setNewTitle(\"\");\n setCreating(true);\n }\n },\n }\n : null\n }\n foot={\n !allowCreate || full ? undefined : targetRefusal ? (\n <RefusalLine error={targetRefusal} className=\"p-2\" />\n ) : !target ? (\n <p className=\"p-2 text-xs text-muted-foreground\">Reading that table…</p>\n ) : creating ? (\n <div className=\"flex items-center gap-1 p-1\">\n <BasicInput\n autoFocus\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n void create(newTitle);\n }\n }}\n placeholder={`New ${targetWord}`}\n className=\"h-7 flex-1 text-xs\"\n aria-label={`Name the new ${targetWord}`}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"default\"\n disabled={busy || newTitle.trim() === \"\"}\n onClick={() => void create(newTitle)}\n >\n {busy ? \"Creating…\" : \"Create\"}\n </Button>\n </div>\n ) : undefined\n }\n footNote={\n allowCreate && !full && createRefusal ? (\n // The typed title is still in the search box: the notice owns the\n // two doors out (lane REFUSAL-SWEEP).\n <RefusalNotice\n error={createRefusal}\n className=\"mt-1 max-w-72\"\n onKeepEditing={() => setCreateRefusal(null)}\n onDiscard={() => {\n setCreateRefusal(null);\n setSearch(\"\");\n }}\n />\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n","\"use client\";\n\n// src/PickOrAdd.tsx — @ai-matrx/records-ui\n//\n// THE ONE \"PICK OR ADD\" BUILDER (lane STORE-RULE-GAPS, 2026-09-23).\n//\n// A button that opens a popover with a search box, the list of what can be picked, and — when\n// what was typed is not there — one line at the foot that makes it: Create “<typed>” for a\n// relation (a new record in the Table it points at), Add “<typed>” for a choice column that\n// takes other values (a new choice, added by the store as typed). The champions (Airtable,\n// Notion, Linear) end a picker's list with exactly that line, and they draw it the same way\n// everywhere, so this package draws it ONCE: `RelationPicker` and the open choice editor in\n// `editors.tsx` are both built from this, and neither carries a copy of the layout.\n//\n// What stays with the caller is what differs: which items there are, what picking one means,\n// what the add line says and does, and any state of its own above the list (a refusal, a\n// \"Reading…\", a ceiling) or at the foot (a name box, a refusal of the add).\n\nimport { useEffect, useRef, useState, type KeyboardEvent, type ReactNode } from \"react\";\nimport { PersonAvatar, PersonChip } from \"./personChip\";\nimport { BasicInput, Button, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ScrollArea, cn } from \"@ai-matrx/design-system\";\n\n/** What a list row and its chips need of a glyph: drawn in the text colour, never a font. */\nfunction Glyph({ d, className }: { d: string; className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={className}>\n <path d={d} />\n </svg>\n );\n}\nconst TICK = \"m5 12 4 4L19 6\";\nconst CROSS = \"M18 6 6 18M6 6l12 12\";\nconst PLUS = \"M12 5v14M5 12h14\";\n\nexport interface PickOrAddItem {\n id: string;\n label: string;\n /** A second line that tells two same-named items apart. */\n detail?: string | null | undefined;\n picked: boolean;\n /** The tooltip; defaults to the label. */\n title?: string | undefined;\n /**\n * The item drawn AS A CHIP in these classes — a choice in the colour its column keeps for it\n * (`choiceChipLookOf`), so the list reads the way the cell does. Absent: plain words.\n */\n chip?: string | undefined;\n /** Attributes a caller's tests and walks select by (e.g. `data-relation-candidate`). */\n attrs?: Record<string, string> | undefined;\n /** The row cannot be picked right now (a pick still being written). */\n disabled?: boolean | undefined;\n /** The row is a PERSON: their initials in a circle before the name (`personChip.tsx`). */\n person?: boolean | undefined;\n}\n\n/** A picked value, drawn at the head of the open list with its × (Airtable, Notion). */\nexport interface PickOrAddChip {\n id: string;\n label: string;\n /** The chip's colour classes (`choiceChipLookOf`); absent: the plain record chip. */\n chip?: string | undefined;\n /** Takes it off. Absent: the chip is shown and cannot be taken off here. */\n onRemove?: (() => void) | undefined;\n /** A PERSON: drawn as the person chip, never the record chip. */\n person?: boolean | undefined;\n}\n\nexport interface PickOrAddProps {\n /** The trigger's accessible name, e.g. \"Pick for Category\". */\n triggerLabel: string;\n /**\n * The trigger's height. \"field\" (the default) is the height of the text box beside it in a form\n * (WALK3-FIX, 2026-10-07: Pick/Choose sat 4px shorter than the date box in the same grid row);\n * \"compact\" keeps the small button a filter row or a chooser draws.\n */\n triggerSize?: \"field\" | \"compact\" | undefined;\n /** The trigger's visible word, e.g. \"Pick\", \"Change\", \"Choose\". */\n triggerText: string;\n triggerId?: string | undefined;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n search: string;\n onSearch: (search: string) => void;\n items: PickOrAddItem[];\n onPick: (id: string) => void;\n /** Above the list: a refusal, a \"Reading…\", a ceiling reached. */\n notice?: ReactNode;\n /** When the list is empty. */\n empty?: ReactNode;\n /** The add line at the foot. Absent = no add line. */\n add?: { label: string; onAdd: () => void; disabled?: boolean | undefined } | null | undefined;\n /** The foot's own state, drawn in place of the add line when there is one (a name box, a \"Reading that table…\"). */\n foot?: ReactNode;\n /** Under the add line: a refusal of the add, with its own doors. */\n footNote?: ReactNode;\n /**\n * ENTER WITH NOTHING TO PICK when the foot is the caller's own (a choice cell's Add / Keep as\n * typed / Cancel question): what the question's first answer does (grids review 3, 2026-09-30: a\n * new choice word + Enter did nothing, while Tab then Enter added it). Absent: the add line.\n */\n onEnterWithNoMatch?: (() => void) | undefined;\n /**\n * ESCAPE PUTS EVERYTHING BACK (REVIEW-FIX 2, 2026-10-06). In a grid cell closing the list is the\n * cell's commit, so Escape — which only closed it — wrote whatever the list held, a choice taken\n * off by Backspace included. When given, Escape (from the search box or Radix's own dismiss) calls\n * this INSTEAD of closing: the cell's cancel, which writes nothing and shows what it held.\n */\n onEscape?: (() => void) | undefined;\n /**\n * IN A GRID CELL (lane CELL-EDITORS, 2026-10-06). No trigger button is drawn: the list hangs from\n * `children` — what the cell already shows — the way Airtable's and the old Sheet's lists hang from\n * the cell. Elsewhere (a record form) the trigger button opens it.\n */\n anchored?: boolean | undefined;\n /** What the anchored cell shows under its open list (its chips). */\n children?: ReactNode;\n /** What is picked, at the head of the open list, each with its × (Backspace takes off the last). */\n chips?: PickOrAddChip[] | undefined;\n /**\n * SEVERAL CAN BE PICKED: a pick keeps the list open, and Enter on an empty search — before the\n * arrows chose a row — finishes (the old Sheet's B2-04: Enter used to toggle the first row forever).\n */\n multi?: boolean | undefined;\n}\n\n/**\n * THE LIST'S OWN KEYS (merged-grid review 2, 2026-09-27, A2 — Airtable / Linear / Notion). While a\n * picker is open it owns its keystrokes: the search box takes letters and Space, ArrowUp/ArrowDown\n * move the highlight, Enter picks the highlighted row, Escape closes. TAB IS NOT ITS KEY (lane\n * CELL-EDITORS): it goes on to the cell, which saves and moves to the next one, as in every grid —\n * and in a form it moves to the next question. No other key leaks into the grid or the page behind.\n */\nexport function useListKeys(args: {\n count: number;\n /** Changes whenever what the list shows changes (the search): the highlight goes back to the top. */\n resetOn: unknown;\n onPick: (index: number) => void;\n /** Enter with nothing to pick (no match): the add line, when there is one. */\n onNothing?: (() => void) | undefined;\n onClose: () => void;\n /** Enter before the arrows moved (a several-choice list with an empty search): finish. */\n onFinish?: (() => void) | undefined;\n /** Backspace on an empty search: take off the last picked one. */\n onBackspaceEmpty?: (() => void) | undefined;\n /** Whether the search box is empty (Backspace and the finishing Enter read it). */\n searchEmpty?: boolean | undefined;\n}) {\n const { count, resetOn, onPick, onNothing, onClose, onFinish, onBackspaceEmpty, searchEmpty } = args;\n const [highlight, setHighlight] = useState(0);\n /** The arrows (not the pointer) chose the row: Enter then picks it rather than finishing. */\n const [moved, setMoved] = useState(false);\n useEffect(() => {\n setHighlight(0);\n setMoved(false);\n }, [resetOn]);\n const at = count === 0 ? -1 : Math.min(highlight, count - 1);\n const onKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n // Tab belongs to the cell (save and move on) or the form (the next question).\n if (event.key === \"Tab\") return;\n // THE OPEN PICKER OWNS EVERY OTHER KEY: never the grid's shortcut, never the cell's Enter commit.\n event.stopPropagation();\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setMoved(true);\n if (count > 0) setHighlight((h) => (Math.min(h, count - 1) + 1) % count);\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setMoved(true);\n if (count > 0) setHighlight((h) => (Math.min(h, count - 1) - 1 + count) % count);\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n if (onFinish && searchEmpty && !moved) onFinish();\n else if (at >= 0) onPick(at);\n else onNothing?.();\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n onClose();\n } else if (event.key === \"Backspace\" && searchEmpty && onBackspaceEmpty) {\n event.preventDefault();\n onBackspaceEmpty();\n }\n };\n return { highlight: at, setHighlight, onKeyDown };\n}\n\n/** One row of an open list: a fill when highlighted (it follows the pointer), a tick when picked. */\nexport function PickRow({\n label,\n detail,\n title,\n chip,\n picked,\n highlighted,\n disabled,\n attrs,\n icon,\n person,\n onPick,\n onPoint,\n}: {\n label: string;\n detail?: string | null | undefined;\n title?: string | undefined;\n chip?: string | undefined;\n picked: boolean;\n highlighted: boolean;\n disabled?: boolean | undefined;\n attrs?: Record<string, string> | undefined;\n /** A glyph in the tick's place (the add line's +). */\n icon?: \"plus\" | undefined;\n /** A person row: their circle before the name. */\n person?: boolean | undefined;\n onPick: () => void;\n onPoint: () => void;\n}) {\n const ref = useRef<HTMLButtonElement | null>(null);\n // THE HIGHLIGHT IS ALWAYS IN VIEW: the arrows walk past the list's visible edge and it follows.\n useEffect(() => {\n if (highlighted) ref.current?.scrollIntoView?.({ block: \"nearest\" });\n }, [highlighted]);\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"option\"\n aria-selected={picked}\n disabled={disabled ?? false}\n onClick={onPick}\n onMouseMove={onPoint}\n title={title ?? label}\n {...(attrs ?? {})}\n data-pick-highlighted={highlighted ? \"\" : undefined}\n className={cn(\n \"flex w-full min-w-0 items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:opacity-50\",\n highlighted ? \"bg-accent text-accent-foreground\" : \"\",\n )}\n >\n <span className=\"flex size-3.5 shrink-0 items-center justify-center\">\n {picked ? <span data-pick-tick=\"\" className=\"contents\"><Glyph d={TICK} className=\"size-3.5\" /></span> : null}\n {icon === \"plus\" ? <Glyph d={PLUS} className=\"size-3.5 text-muted-foreground\" /> : null}\n </span>\n {person ? <PersonAvatar name={label} size=\"md\" /> : null}\n <span className=\"min-w-0 flex-1\">\n {chip ? (\n <span className={cn(\"inline-flex max-w-full truncate rounded-md border px-1.5 py-0.5 text-xs font-medium\", chip)} data-records-choice-chip=\"\">\n {label}\n </span>\n ) : (\n <span className=\"block truncate\">{label}</span>\n )}\n {detail ? (\n <span className=\"block truncate text-xs text-muted-foreground\" data-tell-apart=\"\">\n {detail}\n </span>\n ) : null}\n </span>\n </button>\n );\n}\n\n/** What is picked, at the head of an open list: each a chip with its ×. */\nexport function PickChips({ chips }: { chips: PickOrAddChip[] }) {\n if (chips.length === 0) return null;\n return (\n <div className=\"flex flex-wrap gap-1 px-1 pb-1\" data-pick-chips=\"\">\n {chips.map((c) =>\n c.person ? (\n <PersonChip key={c.id} name={c.label} onRemove={c.onRemove} />\n ) : (\n <span\n key={c.id}\n data-pick-chip=\"\"\n title={c.label}\n className={cn(\n \"inline-flex max-w-full items-center gap-1 rounded-md border px-1.5 py-0.5 text-xs font-medium\",\n c.chip ?? \"bg-secondary text-secondary-foreground\",\n )}\n >\n <span className=\"min-w-0 truncate\">{c.label}</span>\n {c.onRemove ? (\n <button\n type=\"button\"\n aria-label={`Remove ${c.label}`}\n onClick={c.onRemove}\n className=\"shrink-0 rounded-sm opacity-60 hover:opacity-100\"\n >\n <Glyph d={CROSS} className=\"size-3\" />\n </button>\n ) : null}\n </span>\n ),\n )}\n </div>\n );\n}\n\nexport function PickOrAdd({\n triggerSize = \"field\",\n triggerLabel,\n triggerText,\n triggerId,\n open,\n onOpenChange,\n search,\n onSearch,\n items,\n onPick,\n notice,\n empty,\n add,\n foot,\n footNote,\n onEnterWithNoMatch,\n anchored,\n children,\n chips,\n multi,\n onEscape,\n}: PickOrAddProps) {\n // THE ADD LINE IS THE LIST'S LAST ROW (the old Sheet's \"Use / Add …\", Notion's \"Create\"): ranked\n // after every real match, so it never takes Enter from one, and the arrows reach it.\n const addRow = add && !foot ? add : null;\n const count = items.length + (addRow ? 1 : 0);\n /** Where the add row sits among the rows the keys walk: always after every item (one fixed spot). */\n const addAt = addRow ? items.length : -1;\n const itemAt = (index: number) => index;\n const removable = (chips ?? []).filter((c) => c.onRemove);\n const keys = useListKeys({\n count,\n resetOn: search,\n onPick: (index) => {\n if (index === addAt) {\n if (addRow && !addRow.disabled) addRow.onAdd();\n return;\n }\n const item = items[itemAt(index)];\n if (item && !item.disabled) onPick(item.id);\n },\n onNothing: onEnterWithNoMatch ?? (add && !add.disabled ? add.onAdd : undefined),\n onClose: () => (onEscape ? onEscape() : onOpenChange(false)),\n ...(multi ? { onFinish: () => onOpenChange(false) } : {}),\n ...(removable.length > 0 ? { onBackspaceEmpty: () => removable[removable.length - 1]?.onRemove?.() } : {}),\n searchEmpty: search === \"\",\n });\n const hasFoot = Boolean(foot) || Boolean(footNote);\n const addRowNode = addRow ? (\n <PickRow\n label={addRow.label}\n picked={false}\n icon=\"plus\"\n disabled={addRow.disabled}\n attrs={{ \"data-pick-add\": \"\" }}\n highlighted={addAt === keys.highlight}\n onPick={addRow.onAdd}\n onPoint={() => keys.setHighlight(addAt)}\n />\n ) : null;\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n {anchored ? (\n <PopoverAnchor asChild>\n <div data-pick-anchor=\"\" className=\"flex min-h-6 w-full min-w-0 flex-wrap items-center gap-1\" aria-label={triggerLabel}>\n {children}\n </div>\n </PopoverAnchor>\n ) : (\n <PopoverTrigger asChild>\n <Button id={triggerId} type=\"button\" size=\"sm\" variant=\"outline\" className={triggerSize === \"field\" ? \"h-9\" : undefined} aria-label={triggerLabel}>\n {triggerText}\n </Button>\n </PopoverTrigger>\n )}\n {/*\n * NO WIDTH HERE. The one picker primitive asks the design system for CONTENT sizing\n * and the system decides how wide that is (lane FIX-14): a `w-64` pasted on one\n * surface is what cut `Create “Marisol Okonkwo — 418 Calle Pu` mid-word. Content sizing\n * is never narrower than what it hangs from, so in a cell it is at least the cell's width.\n */}\n <PopoverContent\n sizing=\"content\"\n padding=\"xs\"\n align=\"start\"\n side=\"bottom\"\n sideOffset={anchored ? 2 : 4}\n animated={false}\n data-matrx-cell-editor=\"\"\n // Every key inside the open list is the list's (see `useListKeys`) — except Tab.\n onKeyDown={(event) => {\n if (event.key !== \"Tab\") event.stopPropagation();\n }}\n // Radix dismisses on Escape before the search box hears it: a cell's Escape is its cancel.\n onEscapeKeyDown={(event) => {\n if (!onEscape) return;\n event.preventDefault();\n onEscape();\n }}\n // The cell keeps its own focus story; closing never throws focus back at a trigger.\n onCloseAutoFocus={(event) => {\n if (anchored) event.preventDefault();\n }}\n >\n {chips ? <PickChips chips={chips} /> : null}\n <BasicInput\n value={search}\n onChange={(e) => onSearch(e.target.value)}\n onKeyDown={keys.onKeyDown}\n placeholder=\"Search\"\n aria-label={`Search — ${triggerLabel}`}\n autoFocus\n autoComplete=\"off\"\n className=\"mb-1 h-8 text-sm\"\n />\n {notice}\n <ScrollArea className=\"max-h-64\">\n <div role=\"listbox\" aria-label={triggerLabel} aria-multiselectable={multi ? true : undefined}>\n {items.map((item, index) => (\n <PickRow\n key={item.id}\n label={item.label}\n detail={item.detail}\n title={item.title}\n chip={item.chip}\n picked={item.picked}\n disabled={item.disabled}\n attrs={item.attrs}\n person={item.person}\n highlighted={index === keys.highlight}\n onPick={() => onPick(item.id)}\n onPoint={() => keys.setHighlight(index)}\n />\n ))}\n {addRowNode}\n </div>\n {items.length === 0 && empty ? empty : null}\n </ScrollArea>\n {hasFoot ? (\n <div className=\"mt-1 border-t pt-1\">\n {foot}\n {footNote}\n </div>\n ) : null}\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\n// src/personChip.tsx — @ai-matrx/records-ui\n//\n// A PERSON LOOKS LIKE A PERSON (lane CELL-EDITORS, night walk 2026-10-06). A person cell's chip was the\n// same purple chip a link to a record wears, and the person list had no faces, so \"Dr. Maria Chen\" and\n// a linked \"Maria Chen — Rincon\" customer read the same. A person is a round pill with their initials in\n// a circle and their name — never the link chip — in the cell, at the head of the open list, on every\n// row of the list and on the record page. Notion and Airtable draw people this way.\n\nimport { cn } from \"@ai-matrx/design-system\";\n\n/** Up to two letters for a person's circle: the first letters of their first two words, or of an email. */\nexport function initialsOf(name: string): string {\n const words = name.replace(/@.*$/, \"\").split(/[\\s._-]+/).filter((w) => /\\p{L}|\\d/u.test(w));\n const letters = words\n .filter((w) => !/^(dr|mr|mrs|ms|prof)\\.?$/i.test(w))\n .slice(0, 2)\n .map((w) => (w.match(/[\\p{L}\\d]/u)?.[0] ?? \"\").toUpperCase());\n return letters.join(\"\") || \"?\";\n}\n\n/** The circle with a person's initials. */\nexport function PersonAvatar({ name, size = \"sm\" }: { name: string; size?: \"sm\" | \"md\" }) {\n return (\n <span\n aria-hidden=\"true\"\n data-records-person-avatar=\"\"\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded-full bg-foreground/10 font-medium text-foreground/80\",\n size === \"md\" ? \"size-5 text-[10px]\" : \"size-4 text-[9px]\",\n )}\n >\n {initialsOf(name)}\n </span>\n );\n}\n\n/** A person, as a cell, a list head and a record page show them: a round pill, their circle, their name. */\nexport function PersonChip({ name, onRemove, className }: { name: string; onRemove?: (() => void) | undefined; className?: string | undefined }) {\n return (\n <span\n data-records-person-chip=\"\"\n title={name}\n className={cn(\"inline-flex min-w-0 max-w-full items-center gap-1 rounded-full bg-muted py-0.5 pl-0.5 pr-2 text-[11px] text-foreground\", className)}\n >\n <PersonAvatar name={name} />\n <span className=\"min-w-0 truncate\">{name}</span>\n {onRemove ? (\n <button type=\"button\" onClick={onRemove} aria-label={`Remove ${name}`} className=\"shrink-0 opacity-60 hover:opacity-100\">\n ×\n </button>\n ) : null}\n </span>\n );\n}\n","\"use client\";\n\n// src/Refusal.tsx — @ai-matrx/records-ui\n//\n// THE ONE PLACE A REFUSAL IS SHOWN. It renders what `plainWords.ts` returns and\n// NOTHING ELSE — no `error.message`, no `error.hint`, no `error.sqlstate` in a\n// place a person reads. That is deliberate and it is the whole guard: a\n// formatter every screen has to go through is a formatter nobody bypasses, and\n// this component is the only door onto the screen a refusal has.\n//\n// The history, so it is not undone by accident. The fifth pass found the store's\n// HINT — written for whoever fixes the caller — printed at the person (\"FLD-11:\n// a lookup and a rollup both travel along a relation. config.via names a\n// relation Field of this same table, by its key.\"). The pass after it filtered\n// the hint and left the MESSAGE verbatim, on the reasonable grounds that the\n// store writes good messages. The sixth pass then found the machine identity\n// inside the MESSAGE — the access refusals are built by `format()` from the\n// door's own name — and printed at the person again, from the other half.\n//\n// So neither half is trusted by shape of ORIGIN any more. Both go through one\n// filter that judges by the shape of the TEXT, and what it drops is kept for an\n// engineer on the notice and in a screen-reader-only line, never deleted.\n\nimport type { ReactNode } from \"react\";\nimport type { RecordsError } from \"@ai-matrx/records\";\nimport { Alert, AlertDescription, AlertTitle, ErrorBox, cn } from \"@ai-matrx/design-system\";\n\nimport { isMachineIdentity, peopleHint, refusalForAPerson, refusalLineForAPerson } from \"./plainWords\";\n\n/**\n * Kept for callers outside this package that already ask the question. The\n * answer is `plainWords.ts`'s, so there is one shape list and not two.\n */\nexport function hintIsMachineIdentity(hint: string): boolean {\n return isMachineIdentity(hint);\n}\n\n/** The hint a PERSON should read, or null when it is written for an engineer. */\nexport function hintForAPerson(hint: string | null | undefined): string | null {\n const said = (hint ?? \"\").trim();\n if (said === \"\") return null;\n if (isMachineIdentity(said)) return null;\n return peopleHint(said) === null ? null : said;\n}\n\nexport function RefusalNotice({\n error,\n className,\n actions,\n onKeepEditing,\n onDiscard,\n}: {\n error: RecordsError;\n className?: string | undefined;\n actions?: ReactNode | undefined;\n /**\n * KEEP EDITING / DISCARD (lane REFUSAL-SWEEP, 2026-09-23). Pass these ONLY where\n * an editor is open holding what the person typed and the refusal is about that\n * text: the notice then owns the two doors out, so the notice — never a clock —\n * decides how long the typed text is kept. Keep editing hands the person back\n * to their text; Discard throws it away and puts back what was there. A surface\n * with nothing typed to keep passes neither and gets no buttons.\n */\n onKeepEditing?: (() => void) | undefined;\n onDiscard?: (() => void) | undefined;\n}) {\n const plain = refusalForAPerson(error);\n const doors =\n onKeepEditing || onDiscard ? (\n <div className=\"flex flex-wrap items-center gap-1 pt-0.5\" data-refusal-doors=\"\">\n {onKeepEditing ? (\n <button\n type=\"button\"\n data-refusal-keep-editing=\"\"\n className=\"rounded border px-2 py-0.5 text-xs hover:bg-muted\"\n onClick={onKeepEditing}\n >\n Keep editing\n </button>\n ) : null}\n {onDiscard ? (\n <button\n type=\"button\"\n data-refusal-discard=\"\"\n className=\"rounded border px-2 py-0.5 text-xs hover:bg-muted\"\n onClick={onDiscard}\n >\n Discard\n </button>\n ) : null}\n </div>\n ) : null;\n return (\n <Alert\n variant=\"destructive\"\n role=\"alert\"\n data-refusal-notice=\"\"\n className={cn(\"text-xs\", className)}\n // The host's error actions (copy for AI) get the store's own error — code,\n // SQLSTATE, hint — through the slot, never on the page (UI-FIX-19).\n errorFacts={{ message: plain.sentence, title: plain.title, error, origin: \"records-ui/RefusalNotice\" }}\n // 🚨 ENGINEER TEXT RIDES A DATA ATTRIBUTE, NEVER A TOOLTIP OR A HIDDEN LINE (UI-FIX-19,\n // VERIFIER-20 b). It was the notice's `title` and an `sr-only` paragraph: the Birchwood owner\n // hovering the refusal of her restore read \"SQLSTATE 23514. Hint: STORE-TAILS-3: …\", and a\n // copy of the page carried it. Whoever debugs it reads the attribute.\n {...(plain.forEngineers ? { \"data-for-engineers\": plain.forEngineers } : {})}\n {...(error.sqlstate ? { \"data-sqlstate\": error.sqlstate } : {})}\n >\n {/* THE STORE'S OWN SENTENCE IS THE HEADING when it gave one (UI-FIX-19): \"That value was not\n accepted\" over the real reason read as the reason. The generic title heads a notice only\n when nothing of the store's words survived. */}\n <AlertTitle className=\"text-xs font-medium\">{plain.storeSaid ? plain.sentence : plain.title}</AlertTitle>\n <AlertDescription className=\"space-y-1 text-xs\">\n {/* 🚨 A NOTICE NEVER SAYS THE SAME THING TWICE (lane LIMITS-FIX-UI, 2026-09-21).\n When every clause of the store's message was machine identity there is\n nothing of its own words left, and `refusalForAPerson` honestly falls back to\n the title — which this then printed AGAIN underneath it. A dental practice's\n owner read, on his own record: \"You do not have access to this. You do not\n have access to this. Ask somebody who administers this to share it with you\n at the level you need.\" Twice is not more true; it reads as a stutter, and it\n pushes the one useful line — the remedy — further down the box. */}\n {plain.storeSaid || plain.sentence.replace(/\\.$/, \"\") === plain.title ? null : <p>{plain.sentence}</p>}\n {/* NEVER A DEAD END: what happened, and then what to do about it. */}\n <p className=\"opacity-80\">{plain.remedy}</p>\n {actions}\n {doors}\n </AlertDescription>\n </Alert>\n );\n}\n\n/** A small inline one, for a cell or a field where a block would break the layout. */\nexport function RefusalLine({ error, className }: { error: RecordsError; className?: string | undefined }) {\n const plain = refusalForAPerson(error);\n return (\n <ErrorBox\n data-refusal-line=\"\"\n className={cn(\"text-xs text-destructive\", className)}\n message={refusalLineForAPerson(error)}\n error={error}\n origin=\"records-ui/RefusalLine\"\n // Engineer text on a data attribute, never a tooltip (UI-FIX-19).\n {...(plain.forEngineers ? { \"data-for-engineers\": plain.forEngineers } : {})}\n />\n );\n}\n","// src/plainWords.ts — @ai-matrx/records-ui\n//\n// THE ONE FORMATTER EVERY REFUSAL PASSES THROUGH.\n//\n// WHAT A PERSON READ (independent verdict, sixth pass, 19-20 September):\n//\n// \"You do not have access to this table, so custom.applicable_fields has\n// nothing to show you.\"\n// \"config.via names a relation Field of this same table, by its key… The\n// store's code for this was 23514.\"\n//\n// The verdict's third measured gap against Airtable, Notion and Linear was\n// exactly this: \"The machinery still shows through… two column types answer\n// with a contract row id and a SQL error number. Airtable, Notion and Linear\n// never show a person an internal name.\"\n//\n// WHY FILTERING THE HINT WAS NOT ENOUGH. The previous pass filtered the store's\n// HINT — the half written for whoever fixes the caller — and printed the\n// MESSAGE verbatim, because the store writes good messages. Most of them are\n// good. But the store's access refusals are built by `format()` from the DOOR'S\n// OWN NAME (`assert_client_may_change`: \"…so % may not write to it\", with the\n// door name substituted in), so the machine identity is IN the sentence a\n// person reads and no amount of hint-filtering reaches it.\n//\n// SO: ONE function, here, and every screen in this package renders what it\n// returns and nothing else. It does three things and refuses to do a fourth:\n//\n// 1. It KEEPS the store's own words wherever they are a person's words. The\n// store writes the best sentences in this feature (\"Being a member of the\n// organization is not by itself permission to rewrite somebody else's\n// row\") and this package does not rewrite them.\n// 2. It DROPS the clause that carries machine identity, by SHAPE — a\n// schema-qualified object, a document path, a contract row id, a SQLSTATE,\n// a uuid, a bare snake_case token. Dropped, never deleted: it joins the\n// SQLSTATE on the notice for whoever has to debug it.\n// 3. It ADDS a REMEDY — the sentence that says what to do now — keyed off the\n// store's own refusal code, because a refusal with nothing to do about it\n// is a dead end with an explanation.\n//\n// 4. It does NOT invent a diagnosis. When every clause of a message is\n// machine identity there is nothing honest left to say about the specifics,\n// so it says what happened in general terms and offers the remedy. Making\n// something up would be worse than the identifier it replaced.\n//\n// The guard for all of this is `demo/plain-words.test.tsx` plus the sweep in\n// `demo/honest.test.tsx`, which reads the RENDERED text of the real screens and\n// fails on any of the shapes below. A formatter nobody is forced through is a\n// formatter somebody bypasses next week.\n\nimport type { RecordsError } from \"@ai-matrx/records\";\n\n/**\n * MACHINE IDENTITY, BY SHAPE — never by a list of the sentences we happen to\n * have seen, because the next refusal is one nobody has read yet.\n *\n * `FLD-11:` / `REC-29:` / `AGT-7:` a contract row id\n * `custom.field_declare` a schema-qualified database object\n * `config.via` / `data.fields` a path inside a stored document\n * `retention_days` a document key, snake_case\n * `8f2c1b0a-…` a uuid\n * `23514` / `PT409` a SQLSTATE\n * `STORE-TAILS-3:` / `UI-FIX-19:` a build lane's tag (UI-FIX-19)\n */\nexport const MACHINE_IDENTITY: RegExp[] = [\n /\\b[A-Z]{2,4}-\\d{1,3}\\b/,\n // A build lane's tag: capital words joined by hyphens, then a colon (\"STORE-TAILS-3:\",\n // \"MOVE-AND-OUTSIDER:\"). A person never reads which lane wrote a sentence.\n /\\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+:/,\n /\\b(?:custom|platform|iam|history|public|auth|campaign_watch)\\.[a-z_]+/,\n /\\b(?:config|data|document|spec|patch)\\.[a-z_]+/,\n /\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/i,\n /\\b[a-z][a-z0-9]*(?:_[a-z0-9]+)+\\b/,\n // Five characters of digits and capitals, at least one a digit — so `23514`\n // and `PT409` match and an emphatic `NEVER` does not.\n /\\b(?=[0-9A-Z]{5}\\b)(?=[0-9A-Z]*\\d)[0-9A-Z]{5}\\b/,\n];\n\n/** Whether any shape above appears in this text. */\nexport function isMachineIdentity(text: string): boolean {\n return MACHINE_IDENTITY.some((shape) => shape.test(text));\n}\n\n/**\n * Every fragment of `text` that a person should never have been shown. Used by\n * the suite to say WHAT it found rather than only that it found something.\n */\nexport function machineIdentityIn(text: string): string[] {\n const found: string[] = [];\n for (const shape of MACHINE_IDENTITY) {\n const all = new RegExp(shape.source, shape.flags.includes(\"g\") ? shape.flags : `${shape.flags}g`);\n for (const hit of text.matchAll(all)) if (hit[0]) found.push(hit[0]);\n }\n return [...new Set(found)];\n}\n\n/** What the notice is called. The store's code, in the words of what went wrong. */\nconst TITLE: Record<string, string> = {\n stale_write: \"Someone else wrote first\",\n door: \"You do not have access to this\",\n door_absent: \"That is not built yet\",\n refused_by_rule: \"That value was not accepted\",\n invalid_argument: \"That was not accepted\",\n not_found: \"Not there any more\",\n missing_reference: \"That points at something that is not there\",\n already_exists: \"That already exists\",\n not_supported: \"That cannot be done here\",\n store_limit: \"This has got as big as it can\",\n // 🚨 NOT \"THE SWITCH IS OFF\" (lane 7 W1 fix round 1). PGRST202 / PGRST205 land here, and the\n // commonest cause is a door this screen asks for that the database it talks to does not serve\n // YET — a release in flight. Telling the person her organization has its store switched off was\n // false (the switch is answered by its own door, `platform.unified_data_store_on`). Honest:\n // nothing happened, and it is ours, and it passes.\n store_not_served: \"This isn't available right now\",\n unreachable: \"We could not reach your data\",\n needs_approval: \"This is waiting on someone's approval\",\n stale_read: \"Your view of this is a moment behind\",\n timed_out: \"That took too long to answer\",\n internal: \"Something went wrong at our end\",\n};\n\n/**\n * WHAT TO DO NOW. One sentence per refusal code, and it is the whole reason\n * this file exists rather than a regular expression in `Refusal.tsx`: a\n * sentence that names what went wrong and nothing to do about it is a dead end.\n */\nconst REMEDY: Record<string, string> = {\n stale_write:\n \"Look at what they wrote. Keep theirs, or try again and yours goes on top.\",\n door:\n \"Ask somebody who administers this to share it with you at the level you need.\",\n door_absent:\n \"There is nothing to do here yet. It is on our list, not yours.\",\n refused_by_rule: \"Change the value so it passes, then try again.\",\n invalid_argument: \"Change what you entered, then try again.\",\n not_found:\n \"It may have been deleted. Go back to the list and open it again from there.\",\n missing_reference: \"Pick something that is still there.\",\n already_exists: \"Use a different name.\",\n not_supported: \"There is another way to do this — ask, and we will point you at it.\",\n store_limit: \"Split it up, or ask us to raise the ceiling for your organization.\",\n store_not_served: \"Nothing was changed. Try again in a few minutes.\",\n // 🚨 NOTHING WAS WRITTEN AND NOTHING WAS REFUSED (lane TAILS-6). The call\n // never arrived, so \"try again\" is the honest instruction rather than a\n // consolation — and saying nothing changed is the half a person actually\n // worries about.\n unreachable:\n \"Nothing was changed. Check your connection and open this again.\",\n needs_approval:\n \"Nothing was changed yet. The people who can approve it have been asked.\",\n stale_read: \"Open this again in a moment and it will be up to date.\",\n // 🚨 ONE REMEDY THAT IS TRUE OF EVERY DOOR (lane CHAIR-STORE-PERF, 2026-10-03). The store cancels the\n // WHOLE statement at its clock, so a timed-out door wrote nothing — a create, a column add and a page\n // read alike. \"Try a smaller page\" was written for the page read and was printed to a person adding\n // one row to a three-row table (clone walk, 2026-10-03; the clock was a lock another lane's\n // rehearsal held, not the row). A door whose page can shrink says so in its own hint, which wins here.\n timed_out: \"Nothing was changed. Try again in a moment.\",\n internal:\n \"Nothing you did caused this. Try again, and tell us if it keeps happening.\",\n};\n\n/**\n * 🚨 A HINT THIS PACKAGE OR ITS CLIENT WROTE IS NOT A PERSON'S REMEDY.\n *\n * `refusalForAPerson` prefers the DOOR's own hint over the table above, because\n * the door that refused knows more about the way out than a code does. That is\n * right — but it assumed every hint came from the store. It did not: until\n * `@ai-matrx/records` 0.47.0 the client appended its OWN note to `hint` when it\n * met a SQLSTATE it did not know, and the machine-identity filter let it\n * through whenever the code was not exactly five characters (an empty code from\n * a dropped connection, or an HTTP status like `404`). So the Checklists tab of\n * a plumbing company's jobs table told its owner:\n *\n * @ai-matrx/records did not recognise SQLSTATE from checklistTemplates\n *\n * The client no longer writes there. This is the guard on the other side, by\n * SHAPE and not by that one sentence: a hint that talks about a package, a\n * SQLSTATE, or a `camelCaseDoor` is engineer text wherever it came from, and it\n * joins the engineer's line instead of a person's screen.\n */\nexport const ENGINEER_TEXT: RegExp[] = [\n /@ai-matrx\\//,\n /\\bSQLSTATE\\b/i,\n /\\bPostgREST\\b/i,\n /\\bIndexedDB\\b/i,\n // `<RecordsUiProvider>` — a component, on a screen.\n /<\\/?[A-Z][A-Za-z0-9]*\\s*\\/?>/,\n // `savedViews`, `openRecords`, `onReask` — an identifier, however it is\n // quoted. English does not write camelCase; code does.\n /\\b[a-z][a-z0-9]*[A-Z][A-Za-z0-9]*\\b/,\n // A backticked token is a thing you type into an editor, not a thing you do.\n /`[A-Za-z_][A-Za-z0-9_.]*`/,\n // \"bind X on Y\", \"pass X\", \"import X\" — an instruction to whoever maintains\n // the app, arriving on the screen of somebody who cannot act on it.\n /\\bbind\\s+[`'\"A-Za-z]/i,\n];\n\n/**\n * THE ONE GUARD ON A DOOR'S HINT. True when the hint is developer text and must never be\n * printed at a person: engineer shapes (package, SQLSTATE, component, camelCase, backticked\n * token), a code fence, stack-like lines, or a block too long to be one remedy (over 600).\n * Machine clauses INSIDE an otherwise plain hint are cut by `plainSentence`, not by this.\n */\nexport function isDeveloperHint(hint: string): boolean {\n const text = hint.trim();\n if (text === \"\") return false;\n if (text.includes(\"```\")) return true;\n if (/\\n\\s+at\\s+\\S+/.test(text)) return true;\n if (text.length > 600) return true;\n return isEngineerText(text);\n}\n\n/** The hint a person may read: cleaned to people's sentences, or null. The one place that decides. */\nexport function peopleHint(hint: string | null | undefined): string | null {\n const said = (hint ?? \"\").trim();\n if (said === \"\" || isDeveloperHint(said)) return null;\n return plainSentence(said).kept;\n}\n\n/** Whether this sentence was written for whoever maintains the code. */\nexport function isEngineerText(text: string): boolean {\n return ENGINEER_TEXT.some((shape) => shape.test(text));\n}\n\n/** The one shape every screen in this package renders a refusal from. */\nexport interface PlainRefusal {\n /** The heading. Never the store's code. */\n title: string;\n /**\n * What happened, in the store's own words where they are a person's words\n * and in ours where they are not. Never empty.\n */\n sentence: string;\n /** What to do now. Never empty. */\n remedy: string;\n /**\n * TRUE when `sentence` is the store's own words (UI-FIX-19): a notice is then HEADED by that\n * sentence, never by the generic `title` over it.\n */\n storeSaid: boolean;\n /**\n * Everything a person should not read, kept for whoever has to debug it: the\n * SQLSTATE, the hint written for a caller, and any clause dropped above.\n * Kept on the notice's `data-for-engineers` attribute only (UI-FIX-19): never a\n * tooltip, never text a screen can copy or read aloud; never deleted.\n */\n forEngineers: string;\n}\n\n/**\n * A sentence with its machine clauses taken out — or null when nothing honest\n * is left. Clauses are split on the joins the store's own `format()` templates\n * use (\"…, so custom.x may not write to it\", \"… — FLD-11: …\").\n */\nfunction withoutMachineClauses(sentence: string): { kept: string | null; dropped: string[] } {\n const dropped: string[] = [];\n // 🚨 A PARENTHETICAL ID IS EXCISED, NOT A REASON TO BIN THE SENTENCE AROUND IT\n // (lane LIMITS-FIX-UI, 2026-09-21). The store's own way out for a colleague who\n // is not in the organization — \"Invite them to the organization, share with\n // their organization instead (VIS-23), or, if they are a client rather than a\n // colleague, put them in a portal\" — was thrown away WHOLE because of those\n // eight characters, so a plumbing company trying to show one customer her own\n // jobs was told nothing at all about what to do instead. A contract id in\n // brackets is a footnote: lift it out and the sentence around it is a person's\n // sentence. It is still kept for the engineer, below.\n const footnotes: string[] = [];\n const withoutFootnotes = sentence.replace(/\\s*\\((?:see\\s+)?[A-Z]{2,5}-[A-Z0-9-]{1,8}\\)/g, (hit) => {\n footnotes.push(hit.trim());\n return \"\";\n });\n dropped.push(...footnotes);\n const clauses = withoutFootnotes\n .split(/(?:,\\s+so\\s+|\\s+—\\s+|\\s+--\\s+|\\s*\\|\\s*)/)\n .map((clause) => clause.trim())\n .filter((clause) => clause !== \"\");\n const kept = clauses.filter((clause) => {\n if (!isMachineIdentity(clause)) return true;\n dropped.push(clause);\n return false;\n });\n if (kept.length === 0) return { kept: null, dropped };\n // 🚨 A CLEANER THAT DROPPED NOTHING CHANGES NOTHING (same lane, same day).\n //\n // The split above is on the joins the store's `format()` templates use, and\n // \", so \" is one of them — which is also how ordinary English joins two\n // clauses. So \"That person is not in this organization, so they cannot be\n // given access to this table yet.\" came back out as \"That person is not in\n // this organization. they cannot be given access to this table yet.\" — a\n // sentence nobody wrote, with a lower-case word after a full stop, shown to\n // every person every time. Nothing was dropped from it; there was nothing to\n // clean. When that is true the sentence is returned exactly as the store wrote\n // it, and this function's re-joining only ever runs on a sentence it actually\n // took something out of.\n if (dropped.length === 0) return { kept: sentence.trim(), dropped };\n let joined = kept.join(\". \").replace(/\\.\\.+/g, \".\").trim();\n if (!/[.!?]$/.test(joined)) joined = `${joined}.`;\n return { kept: joined, dropped };\n}\n\n/**\n * THE PEOPLE-FACING SENTENCE OF A STORE MESSAGE, AND NOTHING AFTER IT (lane\n * RECORDS-UI-REFUSAL-TEXT, 2026-10-01). A refusal's message is one plain sentence,\n * then ` — ` and developer detail, or a second sentence written for whoever fixes the\n * caller. A person reads the first sentence only; the rest rides `forEngineers`.\n */\nfunction peopleSentence(message: string): { kept: string | null; dropped: string[] } {\n const [lead = \"\", ...tail] = message.split(/\\s+—\\s+|\\s+--\\s+/);\n // A full stop after an abbreviation or an initial (\"Ask Dr. Whitfield\", \"e.g. a quote\") is not an end.\n const sentences = lead.trim().split(/(?<=(?<!\\b(?:Dr|Mr|Mrs|Ms|St|vs|No|e\\.g|i\\.e|etc|[A-Z]))[.!?])\\s+/);\n const first = sentences[0] ?? \"\";\n const rest = [...sentences.slice(1), ...tail].map((part) => part.trim()).filter((part) => part !== \"\");\n const cleaned = plainSentence(first);\n return { kept: cleaned.kept, dropped: [...cleaned.dropped, ...rest] };\n}\n\n/**\n * THE ONE SENTENCE A PERSON READS FOR A REFUSAL — the store's first sentence, or the\n * title when nothing of it is a person's words. Never the hint, details, code or\n * SQLSTATE. Every place that needs a refusal as a string (a toast, a cell, a banner)\n * calls this and nothing else; `check:records-ui-refusal-text` fails on a raw\n * `error.message` / `error.hint` render anywhere else.\n */\nexport function refusalSentence(error: Pick<RecordsError, \"message\"> & Partial<RecordsError>): string {\n return refusalForAPerson(error as RecordsError).sentence;\n}\n\n/** Every sentence of a message, cleaned; the ones that cannot be cleaned are dropped. */\nfunction plainSentence(message: string): { kept: string | null; dropped: string[] } {\n const dropped: string[] = [];\n const kept: string[] = [];\n for (const raw of message.split(/(?<=[.!?])\\s+/)) {\n const sentence = raw.trim();\n if (sentence === \"\") continue;\n const cleaned = withoutMachineClauses(sentence);\n dropped.push(...cleaned.dropped);\n if (cleaned.kept) kept.push(cleaned.kept);\n }\n return { kept: kept.length === 0 ? null : kept.join(\" \"), dropped };\n}\n\n/** The example a pattern refusal carries in its detail, when it carries one. */\nfunction exampleOf(error: RecordsError): string | null {\n const detail = (error as { detail?: unknown }).detail;\n if (!detail || typeof detail !== \"object\") return null;\n const example = (detail as { example?: unknown }).example;\n return typeof example === \"string\" && example.trim() !== \"\" ? example.trim() : null;\n}\n\n/**\n * THE FORMATTER. Every refusal a screen in this package shows goes through\n * here, and nothing in this package renders `error.message` directly.\n */\nexport function refusalForAPerson(error: RecordsError): PlainRefusal {\n const code = error.code ?? \"internal\";\n // A refusal THIS package wrote (`refusals.ts` marks it `ours`) is whole people-facing prose, a\n // count then a reason; only a door's message is cut after its first sentence.\n const ours = (error as { ours?: unknown }).ours === true;\n const hint = plainSentence(String(error.hint ?? \"\"));\n const message = ours ? plainSentence(String(error.message ?? \"\")) : peopleSentence(String(error.message ?? \"\"));\n\n const title = TITLE[code] ?? \"The store refused this\";\n\n // 🚨 ONE REMEDY, AND IT IS THE DOOR'S OWN WHEN THE DOOR HAS ONE (lane\n // LIMITS-FIX-UI, 2026-09-21).\n //\n // The table below is a FALLBACK, not an answer. `custom.share_grant` refuses a\n // colleague who is not in the organization with its own three ways forward —\n // *\"Invite them to the organization, share with their organization instead, or,\n // if they are a client rather than a colleague, put them in a portal\"* — and\n // this formatter used to print that AND then \"Change the value so it passes,\n // then try again\", which is not a thing anybody can do about a membership. Two\n // remedies, one of them wrong, is worse than one: a person follows the last\n // sentence they read. The door that refused knows more about the way out than\n // a table keyed on a code does, so its hint wins whenever it survived the\n // machine-identity filter, and the table answers when it did not.\n // 🚨 THE DOOR'S HINT IS THE REMEDY WHEN IT READS AS A PERSON'S SENTENCE (chair ruling,\n // 2026-10-01, restoring the 2026-09-21 one-remedy ruling). A hint that is developer text (a\n // SQL state, a snake_case name, a uuid, a code fence, a stack, a package or component name)\n // is never printed: it rides `forEngineers` and the code's table sentence is the remedy.\n const hintIsForEngineers = isDeveloperHint(String(error.hint ?? \"\"));\n // STORE-RULE-GAPS: a pattern that carries an example hands it over as DATA\n // (`detail.example`), because an example is the person's own shape of value.\n const example = exampleOf(error);\n const remedy =\n (example ? `Enter it like ${example}.` : null) ??\n (hintIsForEngineers ? null : hint.kept) ??\n REMEDY[code] ??\n REMEDY[\"internal\"]!;\n\n // The store's own sentence for what happened. Its hint is the REMEDY above\n // rather than more of this, so the two halves never say the same thing twice.\n // A STORE MESSAGE IS NEVER ENGINEER TEXT; a stand-in written by a client can\n // be, and a person must not read it. It still reaches the engineer's line.\n const messageIsForEngineers = isEngineerText(String(error.message ?? \"\"));\n const said = (messageIsForEngineers ? \"\" : (message.kept ?? \"\")).trim();\n\n const forEngineers = [\n error.sqlstate ? `SQLSTATE ${error.sqlstate}.` : null,\n // The client's own note about a class it did not recognise, or a call that\n // never reached the store. It is rendered out of sight, never as a sentence.\n error.diagnostic ? error.diagnostic : null,\n messageIsForEngineers ? `Message: ${error.message}` : null,\n error.hint && (hintIsForEngineers || hint.kept !== error.hint) ? `Hint: ${error.hint}` : null,\n message.dropped.length > 0 || hint.dropped.length > 0\n ? `Dropped from the person's view: ${[...message.dropped, ...hint.dropped].join(\" | \")}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return {\n title,\n // Nothing invented. When every clause was machine identity the title says\n // what happened and the remedy says what to do; a made-up diagnosis would\n // be worse than the identifier it replaced.\n sentence: said === \"\" ? `${title}.` : said,\n remedy,\n storeSaid: said !== \"\",\n forEngineers,\n };\n}\n\n/**\n * The same answer as one line, for a cell or a field where a block would break\n * the layout. Still one sentence and one remedy — never the sentence alone,\n * because half of this formatter's job is the thing to do next.\n */\nexport function refusalLineForAPerson(error: RecordsError): string {\n const plain = refusalForAPerson(error);\n // TWO SENTENCES, NOT ONE RUN-ON (VERIFIER-15/16): the store's rule message has no\n // full stop (\"Pressure (psi) has to be at least 0\"), and joining it to the remedy\n // read \"…at least 0 Send this column somewhere else\". A line ends its sentence.\n const sentence = plain.sentence.trim();\n const ended = sentence === \"\" || /[.!?…:]$/.test(sentence) ? sentence : `${sentence}.`;\n return `${ended} ${plain.remedy}`.trim();\n}\n","// src/refusals.ts — @ai-matrx/records-ui\n//\n// THE ONE BUILDER FOR A REFUSAL THIS PACKAGE WRITES ITSELF (lane REFUSAL-SWEEP,\n// 2026-09-23).\n//\n// `RefusalNotice` takes a `RecordsError`, and the store's own refusals arrive as\n// one. But twenty-six places in this package refused something IN THE BROWSER —\n// an answer not filled in, a file the browser could not read, a spreadsheet that\n// could not be written, a picker that could not list its choices — and each of\n// them held a bare string and printed it in red: no heading, no remedy, and in\n// five of them the store's `error.message` verbatim, straight past the\n// machine-identity filter every other screen goes through.\n//\n// So a refusal this package writes is built HERE, as the same object the store\n// hands back, and drawn by the same `RefusalNotice`. A person cannot tell which\n// half of the system said no and has no reason to care; `plainWords.ts` still\n// judges the sentence by shape, and the remedy is the one THIS call site knows\n// (the hint wins over the code's generic remedy — see `refusalForAPerson`).\n\nimport type { RecordsError, RecordsErrorCode } from \"@ai-matrx/records\";\n\n/**\n * A refusal in this package's own words.\n *\n * @param code what KIND of refusal — picks the notice's title and its fallback remedy.\n * @param sentence what happened, for a person.\n * @param remedy what to do now, when this call site knows better than the code's default.\n * @param diagnostic an engineer's note (a thrown message, a status) — rendered out of sight.\n */\nexport function refusal(\n code: RecordsErrorCode,\n sentence: string,\n remedy?: string | null,\n diagnostic?: string | null,\n): RecordsError {\n return {\n code,\n message: sentence,\n ours: true,\n ...(remedy ? { hint: remedy } : {}),\n ...(diagnostic ? { diagnostic } : {}),\n } as RecordsError;\n}\n\n/**\n * A refusal made from something THROWN in the browser. The thrown text is an\n * engineer's (a parser's \"Unexpected token } in JSON at position 14\", a\n * library's stack) and goes out of sight; the person reads `sentence`.\n */\nexport function refusalFromThrown(\n thrown: unknown,\n sentence: string,\n remedy?: string | null,\n code: RecordsErrorCode = \"internal\",\n): RecordsError {\n const said = thrown instanceof Error ? thrown.message : String(thrown ?? \"\");\n return refusal(code, sentence, remedy, said ? `Thrown: ${said}` : null);\n}\n\n/**\n * The store's refusal when there is one, otherwise this package's own sentence —\n * for the call sites whose answer MAY carry an error (`res.error?.message ?? \"…\"`\n * was the old shape, and it printed the store's message raw).\n */\nexport function refusalOr(error: RecordsError | null | undefined, code: RecordsErrorCode, sentence: string): RecordsError {\n return error ?? refusal(code, sentence);\n}\n\n/**\n * Whatever a host callback threw, as a refusal: the store's own `RecordsError`\n * when that is what arrived (it is drawn with its own words and remedy), and\n * otherwise `refusalFromThrown` — the thrown text out of sight, `sentence` in view.\n */\nexport function asRefusal(\n thrown: unknown,\n sentence: string,\n remedy?: string | null,\n code: RecordsErrorCode = \"internal\",\n): RecordsError {\n const t = thrown as Partial<RecordsError> | null | undefined;\n if (t && typeof t === \"object\" && typeof t.code === \"string\" && typeof t.message === \"string\" && !(thrown instanceof Error)) {\n return t as RecordsError;\n }\n return refusalFromThrown(thrown, sentence, remedy, code);\n}\n","// src/tellApart.ts — @ai-matrx/records-ui · lane RECORDS-UI-FIX (2026-09-23)\n//\n// TWO RECORDS WITH ONE NAME ARE TOLD APART, NEVER LISTED AS TWINS.\n//\n// 🚨 WHAT A PERSON MET (guide re-walk, VERIFIER-15/16 LOW): Rincon's linked-record\n// picker listed Patricia Marsh, Robert Marsh, Maria Chen \"and the rest\" twice each.\n// They are not duplicates: Rincon's Customers table holds two Patricia Marshes — 156\n// Willow Way and 261 Sunset Blvd — and the picker drew only the name, so a dispatcher\n// could not tell which one she was attaching to a job. Airtable's record picker shows\n// the record's other fields for exactly this reason.\n//\n// So when names collide, each colliding row gets ONE short line from its own document:\n// the first column whose values differ across the rows that share the name (an\n// address, a phone), and a second one only when the first still leaves two alike.\n// A name nobody else holds gets nothing — the list stays a list of names.\n\nimport type { ReadRow } from \"@ai-matrx/records\";\n\nfunction shown(value: unknown): string | null {\n if (value === null || value === undefined) return null;\n if (typeof value === \"string\") return value.trim() === \"\" ? null : value.trim();\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return null;\n}\n\n/** For every row whose name another row also has: the words that tell it apart. */\nexport function tellApart(rows: ReadRow[], nameOf: (id: string) => string): Map<string, string> {\n const byName = new Map<string, ReadRow[]>();\n for (const row of rows) {\n const name = nameOf(row.id).trim().toLowerCase();\n byName.set(name, [...(byName.get(name) ?? []), row]);\n }\n const out = new Map<string, string>();\n for (const [name, group] of byName) {\n if (group.length < 2) continue;\n const keys = [\n ...new Set(\n group.flatMap((row) =>\n Object.keys(row.document ?? {}).filter((k) => !k.startsWith(\"_\") && shown(row.document?.[k]) !== null),\n ),\n ),\n ].filter((k) => group.some((row) => (shown(row.document?.[k]) ?? \"\").toLowerCase() !== name));\n const valuesOf = (k: string) => group.map((row) => shown(row.document?.[k]) ?? \"\");\n const differs = keys.filter((k) => new Set(valuesOf(k)).size > 1);\n const whole = differs.find((k) => new Set(valuesOf(k)).size === group.length);\n const chosen = whole ? [whole] : differs.slice(0, 2);\n if (chosen.length === 0) continue;\n for (const row of group) {\n const words = chosen.map((k) => shown(row.document?.[k])).filter((w): w is string => w !== null);\n if (words.length > 0) out.set(row.id, words.join(\" · \"));\n }\n }\n return out;\n}\n","// src/buttonCell.tsx — @ai-matrx/records-ui\n//\n// A BUTTON COLUMN ON SCREEN (lane NOTION-PROPS-3; champions: Notion's and Airtable's Button). Drawn the same\n// in a grid cell, a card and a record page (`RecordValue` hands every button here): the column's label in\n// its colour. A press goes to the store (`custom.button_press`) and its answer is said beside the button,\n// in a popover, so nothing on the page moves:\n//\n// a link opens in a new tab (and, when the browser blocks it, is offered as a link)\n// a row action says it ran, or the store's refusal\n// an automation says its run's status and words\n// nothing set says what to set up, and opens the column's settings\n//\n// A public page has no store client: the button is drawn, says it works only for signed-in people, and\n// never pretends to run.\n\nimport { useState, type MouseEvent, type PointerEvent } from \"react\";\nimport { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Popover, PopoverContent, PopoverTrigger, cn } from \"@ai-matrx/design-system\";\nimport { CHOICE_CHIP_CLASS, NEUTRAL_CHIP_CLASS, isStyleColor } from \"@ai-matrx/design-system/data-table\";\nimport { buttonNeeds, buttonOf, type ButtonPressed, type Field, type RecordsError, type Uuid } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { RefusalLine } from \"./Refusal\";\nimport { FieldEditor } from \"./FieldEditor\";\nimport { fieldName } from \"./names\";\n\ntype Said =\n | { kind: \"needs\"; says: string }\n | { kind: \"ran\"; says: string; link?: string | undefined }\n | { kind: \"refused\"; error: RecordsError }\n | { kind: \"public\" };\n\n/** What a press answered, in words a person reads. */\nexport function buttonPressWords(label: string, pressed: ButtonPressed): string {\n if (pressed.do === \"open_url\") return `${label} opened ${pressed.url}`;\n if (pressed.do === \"run_action\") {\n const n = Number(pressed.result?.ran ?? 1);\n return `${label} ran on ${n === 1 ? \"this record\" : `${n} records`}.`;\n }\n const status = pressed.status ?? \"ran\";\n return [`${pressed.automation ?? label}: ${status}.`, pressed.says].filter(Boolean).join(\" \");\n}\n\nconst stop = (event: MouseEvent | PointerEvent) => event.stopPropagation();\n\nexport function ButtonValue({ field, recordId, inCell }: { field: Field; recordId?: string | null | undefined; inCell?: boolean | undefined }) {\n const client = useOptionalRecordsClient();\n const b = buttonOf(field);\n const [busy, setBusy] = useState(false);\n const [said, setSaid] = useState<Said | null>(null);\n const [settingUp, setSettingUp] = useState(false);\n if (!b) return null;\n const color = isStyleColor(b.color) ? CHOICE_CHIP_CLASS[b.color] : NEUTRAL_CHIP_CLASS;\n const needs = buttonNeeds(b);\n const tableId = field.entity_definition_id;\n\n const press = async () => {\n if (!client || !recordId) return setSaid({ kind: \"public\" });\n if (needs) return setSaid({ kind: \"needs\", says: needs });\n setBusy(true);\n const answered = await client.buttonPress({ record_id: recordId as Uuid, field_id: field.id });\n setBusy(false);\n if (!answered.ok) return setSaid({ kind: \"refused\", error: answered.error });\n const pressed = answered.data;\n if (pressed.do === \"open_url\") {\n const opened = typeof window !== \"undefined\" ? window.open(pressed.url, \"_blank\", \"noopener,noreferrer\") : null;\n // `noopener` makes window.open answer null even when the tab opened, so the link is always offered.\n return setSaid({ kind: \"ran\", says: opened ? `${b.label} opened.` : `${b.label} is ready:`, link: pressed.url });\n }\n setSaid({ kind: \"ran\", says: buttonPressWords(b.label, pressed) });\n };\n\n return (\n <>\n <Popover open={said !== null} onOpenChange={(open) => (open ? null : setSaid(null))}>\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n size=\"xs\"\n variant=\"outline\"\n data-records-button={field.key}\n data-records-button-unset={needs ? \"\" : undefined}\n aria-busy={busy || undefined}\n disabled={busy}\n className={cn(\"max-w-full gap-1 border px-2 font-medium\", inCell ? \"h-5\" : \"h-6\", color, needs && \"border-dashed opacity-80\")}\n onPointerDown={stop}\n onDoubleClick={stop}\n onClick={(event) => {\n event.stopPropagation();\n event.preventDefault();\n void press();\n }}\n >\n <span className=\"truncate\">{b.label}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-72 space-y-2 p-3 text-sm\" onClick={stop} onPointerDown={stop} data-records-button-said={said?.kind}>\n {said?.kind === \"refused\" ? <RefusalLine error={said.error} /> : null}\n {said?.kind === \"public\" ? <p>Buttons run for signed-in people.</p> : null}\n {said?.kind === \"ran\" ? (\n <p className=\"break-words\">\n {said.says}{\" \"}\n {said.link ? (\n <a href={said.link} target=\"_blank\" rel=\"noopener noreferrer\" className=\"text-primary underline\">\n {said.link}\n </a>\n ) : null}\n </p>\n ) : null}\n {said?.kind === \"needs\" ? (\n <>\n <p>{said.says}</p>\n {tableId ? (\n <Button\n type=\"button\"\n size=\"sm\"\n data-records-button-set-up=\"\"\n onClick={() => {\n setSaid(null);\n setSettingUp(true);\n }}\n >\n Set up {b.label}\n </Button>\n ) : null}\n </>\n ) : null}\n </PopoverContent>\n </Popover>\n {settingUp && tableId ? (\n <Dialog open onOpenChange={(open) => (open ? null : setSettingUp(false))}>\n <DialogContent className=\"max-h-[85vh] overflow-y-auto sm:max-w-2xl\" onClick={stop} onPointerDown={stop}>\n <DialogHeader>\n <DialogTitle>{`Column settings · ${fieldName(field)}`}</DialogTitle>\n <DialogDescription className=\"sr-only\">What the button does</DialogDescription>\n </DialogHeader>\n <FieldEditor tableId={tableId} field={field} onSaved={() => setSettingUp(false)} onCancel={() => setSettingUp(false)} />\n </DialogContent>\n </Dialog>\n ) : null}\n </>\n );\n}\n","// src/columnName.ts — @ai-matrx/records-ui · Sheet retirement (lane data-tables-grid-overhaul; the\n// Sheet's `column-name-taken.ts`, deleted in matrx-frontend 1c4e8b0d0d).\n//\n// A NAME ANOTHER COLUMN ALREADY HAS IS SAID WHILE IT IS TYPED. The store refuses it on Save\n// (`custom.field_declare`: same label, case and surrounding spaces ignored); the columns are already\n// on screen, so the name box says it as the person types. Names compare as a person reads them:\n// case, surrounding spaces and runs of spaces do not make two names different. The store stays the\n// final judge — this offers, it never blocks.\n//\n// RESERVED NAMES: the store keeps only `_`-prefixed keys for itself (`_actor`, `_values`), and a\n// key derived from a name never starts with `_` (`keyFor`), so no typed name can reach one. There is\n// no reserved-name line to say; one that refused \"id\" would refuse what the store takes.\n\nconst said = (name: string) => name.trim().replace(/\\s+/g, \" \");\n\n/** The other column's name when `name` reads the same as one of `others`, else null. */\nexport function columnNameTakenBy(name: string, others: readonly string[]): string | null {\n const wanted = said(name).toLocaleLowerCase();\n if (wanted === \"\") return null;\n const hit = others.find((other) => said(other).toLocaleLowerCase() === wanted);\n return hit === undefined ? null : said(hit);\n}\n\n/** The line the name box shows, short layout text. */\nexport function columnNameTakenLine(taken: string, noun: \"column\" | \"field\" = \"column\"): string {\n return `Another ${noun} is already called “${taken}”`;\n}\n","\"use client\";\n\n// src/FieldEditor.tsx — @ai-matrx/records-ui · SCR-9\n//\n// ADDING A COLUMN, WHICH IS THE FIRST THING ANYBODY DOES WITH A TABLE.\n//\n// On 19 September this panel refused every column a person tried to add — a\n// Number and a Date with \"the table does not declare a field called day_rate —\n// declare it there first\", a Person as though it were a formula, and a choice\n// list with \"has to say which table its choices come from\" and nowhere to say\n// it. One cause: the panel assembled a Field DOCUMENT itself and wrote it with\n// the ordinary record writer, which can neither tell the Table about the field\n// nor stamp the row as a field. Both of those are the store's to do, and now it\n// does them: `custom.field_declare` takes what a person knows — a type, a name,\n// and for a choice list the choices — and turns it into the document its own\n// guards demand.\n//\n// So this panel's whole job is to collect an INTENTION. It never writes a\n// behaviour, a format, a unit, a relation target, a relation maximum, a\n// compute_on or a pattern Rule; every one of those is the store's answer to the\n// type a person picked, and a screen that answered them itself is a second\n// place for the thirteen types to be wrong.\n//\n// The key is derived from the name and shown, never demanded: a blank, unmarked,\n// required box that refused the first attempt every time is what a person hit\n// before anything else on this panel.\n//\n// THE SIXTEENTH TYPE (independent verdict, fifth pass, 19 September). Fifteen\n// of the sixteen went in. \"Total of linked records\" did not: the panel\n// explained honestly that the table had no column pointing at several records\n// — and left Add field live, so pressing it sent a rollup with no relation on\n// it and the store answered \"the field Total hours has to say which relation it\n// reads through — FLD-11: … config.via names a relation Field of this same\n// table, by its key.\" A contract row id and three database words, at the\n// person.\n//\n// THE SEVENTEENTH TYPE (independent verifier, 2026-09-20). The kind list had\n// sixteen entries and not one of them was \"Points at another record\". The only\n// relations on offer were Person and File, which point at the PLATFORM's own\n// tables — so the first thing anybody arriving from Airtable reaches for, \"this\n// job belongs to that customer\", could not be built on this screen at all,\n// while the store had taken it since that morning. It is here now, and it asks\n// the ONE question it needs: which table. The tables come from the store\n// (`tableList`, the same door TablesHome reads), never from a guess here, so a\n// person is only ever offered a table they may actually know.\n//\n// AND \"CAN HOLD MORE THAN ONE\" WAS A DEAD CONTROL ON AN EXISTING COLUMN. It\n// carried `disabled={editing}`, so the tick would not go down; and the editing\n// branch of `save()` built a patch that never mentioned `multi`, so even a tick\n// that went down sent nothing. Underneath both sat the store: `custom.field_update`\n// read `multi` only inside its behaviour arm, so a patch carrying `multi` alone\n// was answered \"saved\" and changed nothing. All three are closed — the door by\n// lane FIX-7B-FIELD's migration (matrx-frontend\n// `migrations/campaign/fix7b_field_multi_arm.sql`, which gives\n// `custom.field_update`'s SETTINGS branch an arm for `multi` and moves a\n// relation's `relation_max` with it), the two here — and the roll-up panel's own remedy\n// sentence (\"Tick 'Can hold more than one' on Photos\") now names a control that\n// works.\n//\n// Both halves are closed here. The picker now offers EVERY relation column this\n// table has, not only the ones that hold several, and says in one plain\n// sentence what a single-valued one cannot do — because \"Crew lead\" IS the\n// column a person means, and hiding it taught them nothing. And the panel never\n// sends a declaration it already knows the store must refuse: `whatIsMissing`\n// asks, in this panel's own words, what has not been answered yet, the sentence\n// sits under the button, and the button says so rather than failing.\n\nimport { columnNameTakenBy, columnNameTakenLine } from \"./columnName\";\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport {\n type ContextPolicy,\n type Field,\n type FieldPatch,\n type FieldRule,\n type FieldSensitivity,\n type NewEntityFieldDeclaration,\n type NewFieldDeclaration,\n type RelationDisplay,\n type RecordsError,\n type RuleExpression,\n type Uuid,\n} from \"@ai-matrx/records\";\nimport {\n tableShapeChanged,\n useEntityFieldMutation,\n useEntityFieldRights,\n useEntityFields,\n useFieldMutation,\n useFields,\n useRecords,\n useRecordsClient,\n useReverseColumns,\n useTable,\n type ReverseColumn,\n} from \"@ai-matrx/records/react\";\nimport { announceRecordChanged } from \"@ai-matrx/records/core\";\nimport type { ChoiceRehome, ChoicesRehomed, RecordsError as ChoiceSaveError } from \"@ai-matrx/records\";\nimport {\n BasicInput,\n Button,\n Checkbox,\n Label,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectTrigger,\n SelectValue,\n Separator,\n cn,\n} from \"@ai-matrx/design-system\";\nimport { editorKindFor, pickableTypeOf } from \"./parity\";\nimport {\n ADD_FIELD_SAVE_LABEL,\n EDIT_FIELD_SAVE_LABEL,\n FIELD_TYPE_CATALOGUE,\n FIELD_TYPE_CHOICES,\n LOOK_KINDS,\n declaredAsLook,\n FIELD_TYPE_GROUPS,\n fieldTypeChoice,\n isParityFieldType,\n isPlainFieldType,\n isRelationFieldType,\n isSystemFieldKind,\n type FieldTypeChoice,\n type LookFieldKind,\n type PickableFieldType,\n} from \"./fieldTypes\";\nimport { ReferenceBuilder } from \"./ReferenceBuilder\";\nimport { FormulaTextEditor } from \"./FormulaTextEditor\";\nimport { EntityReferenceKindPicker, whatIsMissingForEntityReference } from \"./EntityReferenceKindPicker\";\nimport { RefusalNotice } from \"./Refusal\";\nimport { SourceArchivedNotice } from \"./SourceArchivedNotice\";\nimport { ConditionGroup, conditionInWords, conditionIsDrawable, type ConditionField } from \"./Condition\";\nimport { FieldRetype } from \"./FieldRetype\";\nimport { FieldRulePreview, rulesChanged } from \"./FieldRulePreview\";\nimport { formulaTextNow } from \"./formulaNames\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { CHOICE_EDITOR_ADDS_WHAT_IS_TYPED, FieldControl } from \"./editors\";\nimport { useTableRights } from \"./host\";\nimport { choiceLookForNewList, choiceLookFromList } from \"./ColumnLook\";\nimport { ChoiceListEditor, choiceListPatch, choiceRowsFrom, whatTheChoiceListIsMissing, type ChoiceListRow } from \"./ChoiceListEditor\";\nimport {\n BarcodeSymbologyQuestion,\n RatingMaxQuestion,\n STATUS_STARTING_CHOICES,\n StatusGroupsQuestion,\n statusGroupRows,\n} from \"./NewerKindQuestions\";\nimport { FieldFormatPicker, formatPatch, startingChoice, type FormatChoice } from \"./FieldFormatPicker\";\nimport { fieldName } from \"./names\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\nimport { archiveConfirmSentence, readersSentence } from \"./archiveWords\";\nimport { nextFieldSort } from \"./gridMenus\";\nimport {\n FIELD_RULE_KIND_LABEL,\n FIELD_RULE_KIND_VALUES,\n FIELD_SENSITIVITY_LABEL,\n CONTEXT_POLICY_LABEL,\n ROLLUP_AGG_LABEL,\n ROLLUP_AGG_VALUES,\n FORMULA_OP_LABEL,\n FORMULA_OP_JOINS,\n FORMULA_OP_VALUES,\n} from \"./enumLabels\";\nimport { autonumberPrefixOf, buttonOf, type ButtonSettings } from \"@ai-matrx/records\";\nimport { ButtonSettingsEditor } from \"./ButtonSettings\";\nimport { FIELD_SENSITIVITIES, CONTEXT_POLICIES, DECLARABLE_FIELD_KINDS, optionKey, ratingMaxOf, rulesWithTopStar, type StatusGroup } from \"@ai-matrx/records\";\n\n// Every array below is DERIVED from `enumLabels.ts` — the value order a person\n// sees on the menu, plus the ONE label map for its enum. No panel keeps its own\n// copy of the words; see `enumLabels.ts` for the canonical source of each.\n\nexport const RULE_KINDS = FIELD_RULE_KIND_VALUES.map((kind) => ({ kind, label: FIELD_RULE_KIND_LABEL[kind] }));\n\n/** FLD-12, in the words the setting actually means to the person setting it. */\nexport const SENSITIVITIES = FIELD_SENSITIVITIES.map((value) => ({ value, label: FIELD_SENSITIVITY_LABEL[value] }));\n\nexport const AGENT_VISIBILITY = CONTEXT_POLICIES.map((value) => ({ value, label: CONTEXT_POLICY_LABEL[value] }));\n\nexport const ROLLUP_OPERATIONS = ROLLUP_AGG_VALUES.map((value) => ({\n value: value as NonNullable<NewFieldDeclaration[\"agg\"]>,\n label: ROLLUP_AGG_LABEL[value],\n}));\n\n/**\n * F5 (VERIFIER-11). The one spelling of the separator control, and its default.\n * Exported because the panel, its suite and the published tarball all have to be talking\n * about the same words.\n */\nexport const FORMULA_SEPARATOR_LABEL = \"Joined by\";\n/** What this panel says over an existing worked-out column, rather than nothing. */\nexport const EDITING_A_WORKED_OUT_COLUMN = \"Written as a formula. Edit it below.\";\nexport const FORMULA_DEFAULT_SEPARATOR = \" — \";\n\nexport const FORMULA_OPERATIONS = FORMULA_OP_VALUES.map((value) => ({\n value,\n label: FORMULA_OP_LABEL[value],\n joins: FORMULA_OP_JOINS[value],\n}));\n\n/**\n * WHAT A FIELD OF A STANDARD TABLE CAN BE — every kind that HOLDS a value there (lane 7 W1, fix\n * round 1). The store's own kind registry (`custom.field_kinds()`, generated into\n * `DECLARABLE_FIELD_KINDS`) says what each kind is made of; a kind whose behaviour is `formula` —\n * Borrowed value, Total, Count, Worked out, and the stamps (Record number, Created / Last changed\n * time), which are formula words — is worked out by `custom.rule_eval` over a custom record, and a\n * standard row is never worked out. Measured on the clone 2026-10-02 (a CRM company; every kind\n * declared, a realistic value written through `custom.entity_row_write`, read back through\n * `custom.entity_record_read`): every other kind came back holding its value; every formula kind\n * came back null. So a record page offers exactly the kinds that hold a value, read from the\n * store's registry — one source, no hand list. A kind the registry does not publish is not offered.\n */\nconst STORE_BEHAVIOUR = new Map<string, string>(DECLARABLE_FIELD_KINDS.map((row) => [row.kind as string, row.behavior as string]));\n\n/** True when a field of this kind holds a value on a standard table's row. */\nexport function holdsAValueOnAStandardTable(kind: string): boolean {\n if (isSystemFieldKind(kind)) return false;\n const behaviour = STORE_BEHAVIOUR.get(kind);\n return behaviour !== undefined && behaviour !== \"formula\";\n}\n\n/** What a record page's Add field offers: `fieldTypes.ts`'s choices, less what cannot hold a value there. */\nexport const STANDARD_TABLE_FIELD_CHOICES: FieldTypeChoice[] = FIELD_TYPE_CHOICES.filter((c) =>\n holdsAValueOnAStandardTable(c.id),\n);\n\n/** The record page's commit button. A record page has fields, not columns. */\nexport const ADD_STANDARD_FIELD_SAVE_LABEL = \"Create field\";\n\n/**\n * A COLUMN'S DEFAULT (Sheet parity, DATA-V2-BASICS-2): what a new record that does not name this\n * column starts with. The store keeps it on the Field (`default`) and fills it in\n * `custom.record_write`; `custom.field_update` takes it in its settings arm. Offered only on the\n * kinds a person types or picks one value into — a worked-out column, a link, a file, a person or\n * a signature has no fixed value to start from.\n */\nconst KINDS_WITH_A_DEFAULT: ReadonlySet<string> = new Set([\n \"text\", \"long_text\", \"email\", \"phone\", \"url\", \"number\", \"currency\", \"percent\", \"rating\",\n \"duration\", \"time\", \"datetime\", \"select\", \"multi_select\", \"status\", \"checkbox\",\n]);\n\nexport function takesADefault(field: Field): boolean {\n return KINDS_WITH_A_DEFAULT.has(String(pickableTypeOf(field) ?? editorKindFor(field)));\n}\n\n/** The default as the store keeps it: an empty box, blank words or an empty list is \"no default\". */\nexport function defaultToKeep(value: unknown): unknown {\n if (value === undefined || value === null) return null;\n if (typeof value === \"string\") {\n const words = value.trim();\n return words === \"\" ? null : words;\n }\n if (Array.isArray(value) && value.length === 0) return null;\n return value;\n}\n\n/**\n * \"EVERY VALUE MUST BE DIFFERENT\" — the store's `unique` rule (FLD-3 / B1), enforced on every write\n * under an advisory lock (`custom._unique_rule_holds`), whose refusal names the column and the value.\n * Offered on the kinds whose one value can be compared as words; a list of several, a tick, a link\n * or a worked-out column cannot be \"the same as\" another in a way a person means.\n */\nconst KINDS_THAT_CAN_BE_UNIQUE: ReadonlySet<string> = new Set([\n \"text\", \"long_text\", \"email\", \"phone\", \"url\", \"barcode\", \"number\", \"currency\", \"percent\", \"datetime\", \"time\", \"duration\", \"select\",\n]);\n\nexport function canBeUnique(type: string, multi: boolean): boolean {\n return !multi && KINDS_THAT_CAN_BE_UNIQUE.has(type);\n}\n\n/** The rules with the unique rule on or off — one at most, every other rule kept in place. */\nexport function withUnique(rules: readonly FieldRule[], on: boolean): FieldRule[] {\n const rest = rules.filter((r) => r.kind !== \"unique\");\n return on ? [...rest, { kind: \"unique\" }] : rest;\n}\n\nexport const UNIQUE_LABEL = \"Every value must be different\";\nexport const DEFAULT_LABEL = \"New records start with\";\n\n/** `Day rate` → `day_rate`. Shown, so nothing about it is a surprise. */\nexport function keyFor(label: string): string {\n const token = label\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, 48);\n if (token === \"\") return \"\";\n return /^[a-z]/.test(token) ? token : `f_${token}`;\n}\n\ninterface FieldEditorCommon {\n /**\n * The name the host's page gives this table's records (\"Contact\"), when the store's own label\n * is not the word a person reads there. Shown in the header and in place of the store's label\n * inside its refusal sentence.\n */\n tableLabel?: string | undefined;\n onSaved?: (() => void) | undefined;\n onCancel?: (() => void) | undefined;\n /** Called after the store has accepted the removal, so the list can re-read. */\n onRemoved?: (() => void) | undefined;\n className?: string | undefined;\n /**\n * A NEW column that starts as this kind (and name) — a host's own type menu (Spaces' \"New property\"\n * → Formula / Rollup) opens the panel already on the kind the person picked. Ignored when `field`\n * or `copyOf` is given.\n */\n startAs?: { type: PickableFieldType; label?: string | undefined } | undefined;\n}\n\n/**\n * ONE EDITOR FOR BOTH KINDS OF TABLE (lane 7 STANDARD-TABLES, wave 1; Doctrine R13).\n *\n * A column of one of an organization's own tables is named by its Table's uuid (`tableId`). A\n * custom field of a STANDARD table — a CRM contact, a deal, any registry Entity or Detail — has no\n * Table record and is named by its registry token (`entityToken`). Both are the same primitive to\n * a person: the same palette (`fieldTypes.ts`), the same questions, the same governance (who sees\n * it, whether an assistant reads it, what counts as a good value). The only difference is which\n * store door takes the declaration — `custom.field_declare` or `custom.entity_field_declare`,\n * which resolves the spec through the same `custom._field_document_for` — and who may change the\n * shape: the table's own Owner/Admin level, or the organization's admins\n * (`custom.entity_field_rights`, whose sentence is shown as it is).\n *\n * A standard table's field is DECLARED here; editing an existing one stays with the record page's\n * own section (rename, remove), because the edit arms below (choice re-homing, retype, look) are\n * custom-table doors.\n */\nexport type FieldEditorProps = FieldEditorCommon &\n (\n | {\n tableId: Uuid;\n entityToken?: undefined;\n /** The Field being edited. Absent means a new one. */\n field?: Field | undefined;\n /**\n * DUPLICATE PROPERTY (Notion N5): a NEW column that starts as a copy of this one — its kind,\n * choices and colours, unit, link, formula and rules — named \"<name> (1)\". Ignored when\n * `field` is given.\n */\n copyOf?: Field | undefined;\n }\n | {\n /** The standard table's registry token (REC-33), e.g. `party`, `crm_deal`. */\n entityToken: string;\n tableId?: undefined;\n field?: undefined;\n copyOf?: undefined;\n }\n );\n\n/**\n * THE SENTENCE FOR A COLUMN THE STORE TOOK AND THE TABLE HAS NOT GOT.\n *\n * Crew C, on fifty-one real national parks: \"Every 'Add field' attempt appeared to\n * succeed on screen (no error text), but a direct fields() read afterward showed only\n * the table's default Title column.\" The panel closed on the DOOR'S answer, and the\n * grid then drew \"This table has no columns yet\" over real, complete data. A screen\n * that reports a success it has not confirmed is the one thing a person cannot recover\n * from, because they move on.\n */\nconst COLUMN_DID_NOT_LAND_SENTENCE =\n \"The store accepted this column and the table does not have it yet. Nothing was lost — \" +\n \"your record values are untouched — but the column is not there, so this panel is staying open.\";\nconst COLUMN_DID_NOT_LAND_REMEDY =\n \"Press Save again; if it keeps happening, tell us, because the store and the table \" +\n \"disagree and that is ours to fix.\";\nexport const COLUMN_DID_NOT_LAND = `${COLUMN_DID_NOT_LAND_SENTENCE} ${COLUMN_DID_NOT_LAND_REMEDY}`;\n\nexport function FieldEditor(props: FieldEditorProps) {\n const { field, onSaved, onCancel, onRemoved, className } = props;\n const entityToken = props.entityToken ?? null;\n const onEntity = entityToken !== null;\n // A standard table has no Table uuid; the subpanels that take one (the relation builder's\n // \"this table\" mark, the formula checker) are handed the empty id and answer for no table.\n const tableId = (props.tableId ?? \"\") as Uuid;\n // Every hook is called on every render; the one that does not apply is asked about nothing.\n const table = useTable(onEntity ? null : tableId);\n const tableFields = useFields(onEntity ? null : tableId);\n const entityFields = useEntityFields(entityToken);\n const fields = onEntity ? entityFields : tableFields;\n const tableRights = useTableRights(onEntity ? null : table.data);\n const entityRights = useEntityFieldRights(entityToken);\n const tableMutation = useFieldMutation();\n const entityMutation = useEntityFieldMutation();\n const mutation = onEntity\n ? { saving: entityMutation.saving, error: entityMutation.error }\n : { saving: tableMutation.saving, error: tableMutation.error };\n const client = useRecordsClient();\n /** May this person change the shape of this table — and if not, the sentence saying why. */\n const mayShape = onEntity ? entityRights.data?.may_declare === true : tableRights.structure;\n const whyNot = onEntity ? (entityRights.data?.reason ?? null) : tableRights.why(\"structure\");\n const storeLabel = onEntity ? (entityRights.data?.label ?? null) : (table.data?.name ?? null);\n const tableLabel = props.tableLabel ?? storeLabel;\n /** The kinds this menu offers: a standard table's are the ones that hold a value there. */\n const offered = onEntity ? STANDARD_TABLE_FIELD_CHOICES : FIELD_TYPE_CHOICES;\n /**\n * WHO MAY SEE A STANDARD TABLE'S FIELD (lane 7 ruling via the chair, 2026-10-02). A standard row's\n * `custom_fields` column is read by every member the table's own row security admits, so the\n * store cannot yet hold a value back from some of them; until it can, it refuses the two levels\n * that promise to (`confidential`, `restricted`) on a standard token, and this panel does not\n * offer them there. A custom table keeps all four. If the store refuses anyway, its sentence is\n * shown by the refusal notice below like any other.\n */\n const sensitivities = onEntity\n ? SENSITIVITIES.filter((row) => row.value === \"public\" || row.value === \"internal\")\n : SENSITIVITIES;\n\n /** What the panel's answers start from: the Field being edited, or the one being duplicated. */\n const copyOf = field ? undefined : props.copyOf;\n const start = field ?? copyOf;\n const startAs = start ? undefined : props.startAs;\n const [label, setLabel] = useState(field?.label ?? (copyOf ? `${copyOf.label} (1)` : (startAs?.label ?? \"\")));\n const [type, setType] = useState<PickableFieldType>(() => (startAs ? startAs.type : startingType(start)));\n const [required, setRequired] = useState(start?.required ?? false);\n const [multi, setMulti] = useState(start?.multi ?? false);\n const [dated, setDated] = useState(start?.dated ?? false);\n const [sensitivity, setSensitivity] = useState(String(start?.sensitivity ?? \"internal\"));\n const [contextPolicy, setContextPolicy] = useState(String(start?.context_policy ?? \"include\"));\n const [rules, setRules] = useState<FieldRule[]>(start?.rules ?? []);\n // What a new record starts with (Sheet parity). Held as the column's own value shape.\n const [startsWith, setStartsWith] = useState<unknown>(start?.default ?? null);\n // LANE 10 P4: a rating's top star, a status's groups (by choice words), a barcode's code type.\n const [ratingMax, setRatingMax] = useState(() => (start ? ratingMaxOf(start) : 5));\n // What the store will judge on Save: a rating's top star travels as its `max` check.\n const savedRules = useMemo(\n () => (field ? (type === \"rating\" ? rulesWithTopStar(field.rules ?? [], ratingMaxOf(field)) : (field.rules ?? [])) : []),\n [field, type],\n );\n const editedRules = useMemo(() => (type === \"rating\" ? rulesWithTopStar(rules, ratingMax) : rules), [type, rules, ratingMax]);\n const [statusGroups, setStatusGroups] = useState<Record<string, StatusGroup>>({});\n // An existing status column's choices: option id → the key the store keeps its group under.\n const [statusKeys, setStatusKeys] = useState<Record<string, string>>({});\n const [symbology, setSymbology] = useState(String(start?.config?.[\"symbology\"] ?? \"\"));\n // NOTION-PROPS-3: a button's settings, a record number's prefix, a self-link's dependency switch.\n const buttonStart = useMemo(() => buttonOf(start) ?? { label: \"\" }, [start]);\n const [buttonSettings, setButtonSettings] = useState<ButtonSettings>(buttonStart);\n const prefixStart = autonumberPrefixOf(start as Parameters<typeof autonumberPrefixOf>[0]);\n const [numberPrefix, setNumberPrefix] = useState(prefixStart);\n const dependencyStart = start?.config?.[\"dependency\"] === true;\n const [dependency, setDependency] = useState(dependencyStart);\n useEffect(() => {\n if (!field || type !== \"status\") return;\n let live = true;\n void client.fieldOptions({ field_id: field.id }).then((got) => {\n if (live && got.ok) setStatusKeys(Object.fromEntries((got.data ?? []).map((o) => [String(o.id), optionKey(o)])));\n });\n return () => {\n live = false;\n };\n }, [client, field, type]);\n // A NEW Status column starts with Notion's three choices, one in each group (lane 10 P4).\n useEffect(() => {\n if (field || type !== \"status\") return;\n setNewChoices((rows) =>\n rows.length > 0 ? rows : STATUS_STARTING_CHOICES.map((c, i) => ({ id: null, words: c.words, row: `status-${i}` })),\n );\n }, [field, type]);\n // STORE-RULE-GAPS: a choice list may take values that are not one of its\n // choices (the older grid's allowOther). Off unless the column says so.\n const [allowOther, setAllowOther] = useState(start?.config?.[\"allow_other\"] === true);\n // A NEW choice column's choices, one row each with its colour (the same editor an existing\n // column's settings draw — lane VIEWS-AND-FIELDS W1-B).\n const [newChoices, setNewChoices] = useState<ChoiceListRow[]>([]);\n // DUPLICATE PROPERTY: the copy starts with the original's choices, in their colours and order.\n const copyOfId = copyOf?.id ?? null;\n useEffect(() => {\n if (!copyOf || !copyOfId) return;\n let live = true;\n void client.fieldOptions({ field_id: copyOfId }).then((got) => {\n if (!live || !got.ok) return;\n const rows = choiceRowsFrom(got.data ?? [], copyOf);\n if (rows.length > 0) setNewChoices(rows.map((r, i) => ({ ...r, id: null, row: `copy-${i}` })));\n });\n return () => {\n live = false;\n };\n // The original is read once, by its id.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, copyOfId]);\n // CHOICE-COLUMN-EDIT: an EXISTING choice column's choices, one row each, as the store answered\n // them (`start`) and as the person has them now (`choiceList`). Null until they are read.\n const [choiceList, setChoiceList] = useState<ChoiceListRow[] | null>(null);\n const [choiceListStart, setChoiceListStart] = useState<ChoiceListRow[] | null>(null);\n // CHOICE-TAILS: where the records of each removed choice go (by option id), and — once a save\n // moved, kept or cleared some — what it did and its undo, said here before the panel closes.\n const [rehome, setRehome] = useState<Record<string, ChoiceRehome>>({});\n const [rehomed, setRehomed] = useState<{ said: string; undo: ChoicesRehomed[\"undo\"] | null } | null>(null);\n const [rehomeRefused, setRehomeRefused] = useState<ChoiceSaveError | null>(null);\n const [unit, setUnit] = useState(start?.unit ?? \"$\");\n const [withTime, setWithTime] = useState(String(start?.config?.[\"kind\"] ?? \"date\") === \"datetime\");\n const [via, setVia] = useState(String(start?.config?.[\"via\"] ?? \"\"));\n const [pick, setPick] = useState(String(start?.config?.[\"pick\"] ?? \"\"));\n const [agg, setAgg] = useState<NonNullable<NewFieldDeclaration[\"agg\"]>>(\n (start?.config?.[\"agg\"] as NewFieldDeclaration[\"agg\"]) ?? \"count\",\n );\n const [of, setOf] = useState(String(start?.config?.[\"of\"] ?? \"\"));\n // CHAIR-UI-STORE item 1: WHICH of the linked records a total adds up — `config.filter`, in the\n // saved view's own Rule grammar over the far table, built in the one condition builder.\n const savedRollupFilter = (field?.config?.[\"filter\"] ?? null) as RuleExpression | null;\n const [rollupFilter, setRollupFilter] = useState<RuleExpression | null>(\n field ? savedRollupFilter : ((copyOf?.config?.[\"filter\"] ?? null) as RuleExpression | null),\n );\n const rollupFilterChanged = JSON.stringify(rollupFilter) !== JSON.stringify(savedRollupFilter);\n // THE ONE QUESTION A LINK NEEDS: which table. Never guessed, never typed.\n const [relationTarget, setRelationTarget] = useState(String(start?.relation_target ?? \"\"));\n // NOTION-PROPS — \"Show on <table>\": a new link is a column on BOTH tables (Notion's two-way relation),\n // on by default; off leaves the read-only back-link the other table already shows.\n const [showOnOther, setShowOnOther] = useState(true);\n // NOTION-PROPS — SUB-ITEMS: a new link to THIS table may name each record's parent (`subItems.tsx`).\n const [nestsSubItems, setNestsSubItems] = useState(false);\n const [reverseRefused, setReverseRefused] = useState<RecordsError | null>(null);\n const otherTable = useTable(!field && type === \"relation\" && relationTarget !== \"\" ? (relationTarget as Uuid) : null);\n // REL-DISP: and WHICH OF ITS COLUMNS this one shows. Null means the target\n // Table's own reference column, which is what every relation did before.\n const [display, setDisplay] = useState<RelationDisplay | null>(start?.display ?? null);\n // ── THE WORKED-OUT COLUMN, READ BACK OFF THE FIELD IT IS EDITING (lane STORE-TAILS-2).\n // These three used to start at \"concat\" / [] / — even when the panel was opened on an\n // existing formula, so opening one to rename it and pressing save rewrote its expression\n // into a formula that reads nothing. `formulaExprOf` reads the one shape this panel\n // writes and the store keeps.\n const [formulaOp, setFormulaOp] = useState(() => formulaOpOf(start));\n const [formulaFields, setFormulaFields] = useState<string[]>(() => formulaFieldIdsOf(start));\n // F5 (VERIFIER-11): WHAT GOES BETWEEN THEM. Greenline's route sheet read `GL-2034mow_edge`\n // — the machine's word AND no separator, because nothing on this panel ever asked for one.\n // The store takes `{\"op\":\"concat\",\"separator\":\" — \",\"args\":[…]}`; this is where a person\n // says it. An em dash by default, because a joined label is read by somebody and every\n // label anyone actually wants has something between its parts.\n const [formulaSeparator, setFormulaSeparator] = useState(() => formulaSeparatorOf(start));\n // SC-R: which kinds of platform thing an entity-reference column may point at.\n const [allowedTypes, setAllowedTypes] = useState<string[]>(() => entityReferenceKindsOf(start));\n // K2 (lane DEFAULT-GRID-PARITY): THE FORMULA IN THE LANGUAGE A PERSON TYPES. A column that\n // already carries text opens on it; a new one starts on the picker and may switch.\n // …IN TODAY'S COLUMN NAMES (review 2, C3): `{Quote}` reads `{Quote amount}` after the rename —\n // the store keeps the formula by field id, so the text is drawn from the ids (`formulaNames.ts`).\n const startingFormulaText = start\n ? formulaTextNow(String(start.config?.[\"formula_text\"] ?? \"\"), start.config?.[\"expr\"] ?? (start as { expr?: unknown }).expr, fields.data)\n : \"\";\n const [formulaText, setFormulaText] = useState(startingFormulaText);\n // The columns arrive after the panel opens: an untouched formula follows them to today's names.\n const shownFormula = useRef(startingFormulaText);\n useEffect(() => {\n if (shownFormula.current === startingFormulaText) return;\n setFormulaText((typed) => (typed === shownFormula.current ? startingFormulaText : typed));\n shownFormula.current = startingFormulaText;\n }, [startingFormulaText]);\n // A host's own \"Formula\" choice (`startAs`) opens on writing one, the way Notion's formula editor does.\n const [formulaWritten, setFormulaWritten] = useState(() => startingFormulaText.trim() !== \"\" || Boolean(field) || startAs?.type === \"formula\");\n /** The store's verdict on `formulaText`: true, false, or null while it is asked. */\n const [formulaOk, setFormulaOk] = useState<boolean | null>(null);\n const [askingToRemove, setAskingToRemove] = useState(false);\n /** A Save press or leaving the name box: only then does the footer say what is missing (WALK3-FIX). */\n const [attempted, setAttempted] = useState(false);\n // HOW THE COLUMN LOOKS (merge tranche 6a): what a plain column shows as — the Field's own\n // `display_format`, sent in the same settings patch as the rest. A choice's colour rides on its\n // row of the choice editor (`choiceLookFromList`).\n const [showsAs, setShowsAs] = useState<FormatChoice>(() => (start ? startingChoice(start) : { format: null, retype: null }));\n /** The store refused to number the records already here (H2). */\n const [backfillError, setBackfillError] = useState<RecordsError | null>(null);\n /** The store took the column and the table does not have it. See `save`. */\n const [notLanded, setNotLanded] = useState(false);\n\n // WHAT IT HOLDS AFTER A RETYPE (grids review 3, lane H item 5): \"Change what this column holds\"\n // converts through the store and the table's columns are read again — the panel follows the\n // Field as the store now has it, so \"What it holds\" never keeps saying \"Number\" over a column that\n // holds words until a reload.\n const liveField = field ? (fields.data?.find((f) => f.id === field.id) ?? field) : undefined;\n const heldAs = liveField\n ? JSON.stringify([liveField.type, liveField.config?.[\"kind\"] ?? null, liveField.format ?? null, liveField.multi ?? false, liveField.unit ?? null])\n : \"\";\n const seededAs = useRef(heldAs);\n useEffect(() => {\n if (!liveField || seededAs.current === heldAs) return;\n seededAs.current = heldAs;\n setType(startingType(liveField));\n setShowsAs(startingChoice(liveField));\n setMulti(liveField.multi ?? false);\n setUnit(liveField.unit ?? \"$\");\n setWithTime(String(liveField.config?.[\"kind\"] ?? \"date\") === \"datetime\");\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [heldAs]);\n\n const others = useMemo(\n () => (fields.data ?? []).filter((f) => f.id !== field?.id),\n [fields.data, field?.id],\n );\n // THE COLUMNS A LOOKUP OR A ROLLUP READS THROUGH: the link-like ones — a link to another table's\n // records, a Person, a File — which the store resolves a borrowed value or a total through (a\n // Person lookup reads the person's name; a count through a Person counts them). Never a\n // platform reference (`entity_reference`), whose `{token, id}` the store reads nothing through,\n // and never a plain column. `sourceKindOf` says which, so the list names a person or a file.\n const relations = useMemo(() => others.filter((f) => sourceKindOf(f) !== null), [others]);\n // CHAIR-UI-STORE item 2: A BACK-LINK IS A TOTAL'S NATURAL SOURCE. \"Booked visits per patient\"\n // counts the Appointments that link here — the reverse column REL-9 shows on this table. The\n // store reads a roll-up through it (`custom._back_link_relation`); a borrowed value reads ONE\n // record, so a back-link (many) is offered to a total only.\n const reverse = useReverseColumns(onEntity ? null : tableId);\n const backLinks = useMemo(() => (reverse.data ?? []).map(backLinkAsSource), [reverse.data]);\n const totalSources = useMemo(() => [...relations, ...backLinks], [relations, backLinks]);\n const sourcesFor = (kind: PickableFieldType) => (kind === \"rollup\" || kind === \"count\" ? totalSources : relations);\n const choice = fieldTypeChoice(type);\n const editing = Boolean(field);\n // A LINK COLUMN'S REMOVE NAMES THE TOTALS READING THROUGH IT, on the table it points at (their\n // `via` is this column's back-link key) — the same count and sentence the back-link dialog gives.\n const farFieldsOfLink = useFields(field && sourceKindOf(field) === \"link\" && !onEntity ? ((field.relation_target ?? null) as Uuid | null) : null);\n const farTable = useTable(field && sourceKindOf(field) === \"link\" && !onEntity ? ((field.relation_target ?? null) as Uuid | null) : null);\n const linkReaders = useMemo(\n () => (field ? readingThroughLink(field, farFieldsOfLink.data ?? []) : []),\n [field, farFieldsOfLink.data],\n );\n // G3 (lane 5's dry run, 2026-10-02): THE TITLE NAMES THE RECORD, ONE NAME EACH (REC-2). A title\n // saved as \"can hold more than one\" made the import refuse every row (\"… holds many values, so\n // it takes a list\"). So the tick is never offered on the table's title column, and a save from\n // it always says one value — which also mends a title the store had kept as a list.\n const isTitle = Boolean(field) && !onEntity && table.data?.title_field === field?.key;\n const offersMany = multiApplies(type) && !isTitle;\n // The key is DERIVED, never asked for and never shown: the blank, unmarked,\n // required box it replaced refused the first attempt on this panel every\n // time, and the line that printed the derived token instead was the last\n // machine identity on this screen. `keyFor` stays exported for callers that\n // need to predict it; a person does not.\n\n // SCR-4: a person who does not administer the table never sees this panel.\n if (!mayShape) {\n // A standard table's right is still being read: nothing yet, rather than a refusal it has not given.\n if (onEntity && entityRights.loading) return null;\n return (\n <p className={cn(\"text-xs text-muted-foreground\", className)}>\n {/* Honest, not dead: the reason, in a sentence — what level it takes\n and who can give it to you. */}\n {props.tableLabel && storeLabel && whyNot ? whyNot.split(storeLabel).join(props.tableLabel) : whyNot}\n </p>\n );\n }\n\n const options = newChoices.map((r) => r.words.trim()).filter((word) => word !== \"\");\n // LANE 10 P4: A STATUS's choices each sit in a group. A new Status column starts with Notion's\n // three; every choice shown (new or existing) has its group, read from the column or guessed\n // from its words, and changed here.\n // V8 #3: rows named by option id (an existing choice) or words (a new one); only what changed is sent,\n // and the store MERGES it into the groups the column keeps.\n const shownStatusRows =\n type !== \"status\" ? [] : statusGroupRows(field, editing ? (choiceList ?? []) : newChoices, statusKeys, statusGroups);\n const statusGroupsSent = Object.fromEntries(shownStatusRows.filter((r) => !editing || r.ref in statusGroups || !(r.ref in statusKeys)).map((r) => [r.ref, r.group]));\n const statusGroupsChanged = type === \"status\" && editing && Object.keys(statusGroupsSent).length > 0;\n\n /**\n * WHAT THIS PANEL STILL NEEDS, in the words of the panel that asked for it.\n *\n * Never the store's sentence: the store refuses by contract row and document\n * path, which is right for a caller and wrong for a person. `null` means the\n * declaration is complete as far as this screen can tell — the store is still\n * the one that decides, and whatever it says then is shown as it always was.\n */\n const formulaChanged = formulaText.trim() !== startingFormulaText.trim();\n const formulaMissing =\n type !== \"formula\" || !formulaWritten\n ? null\n : editing && !formulaChanged\n ? null\n : formulaText.trim() === \"\"\n ? \"Write the formula this column works out.\"\n : formulaOk === false\n ? \"The formula has a mistake — it is marked above.\"\n : formulaOk === null\n ? \"Checking the formula…\"\n : null;\n /** What the thing being made is called here: a table's column, a record page's field. */\n const noun: \"column\" | \"field\" = onEntity ? \"field\" : \"column\";\n /** Another column's name, when the one typed reads the same (said live; `columnName`). */\n const nameTaken = columnNameTakenBy(label, others.map(fieldName));\n const listsChoices = type === \"select\" || type === \"multi_select\" || type === \"status\";\n const missing = editing\n ? (formulaMissing ?? (listsChoices ? whatTheChoiceListIsMissing(choiceList) : null))\n : (formulaMissing ??\n (listsChoices ? whatTheChoiceListIsMissing(newChoices) : null) ??\n (type === \"formula\" && formulaWritten\n ? null\n : whatIsMissing(\n type === \"count\"\n ? { type: \"rollup\", label, options, via, pick, agg: \"count\", of, relations: totalSources, formulaFields, relationTarget, allowedTypes, noun }\n : { type, label, options, via, pick, agg, of, relations: sourcesFor(type), formulaFields, relationTarget, allowedTypes, noun },\n )));\n\n // A formula's own check speaks as it is written; everything else waits for an attempt.\n const missingShown: string | null = missing && (attempted || formulaMissing) ? missing : null;\n /** What Remove does, said on the destructive button itself (its tooltip), before it happens. */\n const removeConsequence = field\n ? `${archiveConfirmSentence(`the field \\u201c${fieldName(field)}\\u201d`)} Its values stay in every record and come back with it.${\n linkReaders.length > 0 ? ` ${readersSentence(linkReaders.length, farTable.data?.name ?? null)}` : \"\"\n }`\n : \"\";\n\n const save = async () => {\n // A declaration this panel already knows is incomplete is not sent. The\n // person gets the sentence beside the button, now, instead of a refusal\n // written for a caller, a second later.\n if (missing) return;\n if (editing && field) {\n const chooses = type === \"select\" || type === \"multi_select\" || type === \"status\";\n // Each choice's colour rides on its row; a re-worded choice keeps its colour (`choiceLookFromList`).\n const look = chooses && choiceList && choiceListStart ? choiceLookFromList(field, choiceListStart, choiceList) : null;\n // \"SHOWS AS\" (tranche 6e): the look, and for an Other kind the column's new type word.\n const shownAs = chooses ? undefined : formatPatch(field, showsAs);\n // THE DEFAULT, sent only when it changed; an emptied box sends `null`, which clears it. The\n // door's settings arm takes `default` (the Sheet's seam writes it); `FieldPatch` does not\n // declare the key yet (store gap, reported), the same way `display_format` rides below.\n const defaultNow = defaultToKeep(startsWith);\n const defaultChanged = takesADefault(field) && JSON.stringify(defaultNow) !== JSON.stringify(defaultToKeep(field.default));\n const patch: FieldPatch & { display_format?: unknown; default?: unknown } = {\n ...(defaultChanged ? { default: defaultNow } : {}),\n // The column's look travels in the same settings patch (`display_format`), so a save is\n // still one store call. `FieldPatch` does not declare the key yet (store gap, reported);\n // the door has carried it since the Sheet's seam started writing it.\n ...(chooses ? (look ? { display_format: look } : {}) : (shownAs ?? {})),\n label,\n required,\n dated,\n sensitivity: sensitivity as FieldSensitivity,\n context_policy: contextPolicy as ContextPolicy,\n rules,\n // FLD-2. THE SHAPE OF THE VALUE, WHICH IS A SETTING LIKE ANY OTHER. This\n // patch never carried it, so the tick beside \"Can hold more than one\"\n // was decoration on an existing column — and the store's own roll-up\n // refusal tells a person to use exactly that tick. It is sent ALONE:\n // `custom.field_update` honours a `multi`-only patch since FIX-7B-FIELD's\n // migration (before it, the door read `multi` only inside its behaviour\n // arm, answered \"saved\" and changed nothing), so there is no behaviour\n // word to send beside it and sending one would retype a column nobody\n // asked to retype.\n ...(multiApplies(type) ? { multi: isTitle ? false : multi } : {}),\n ...(unitApplies(type) ? { unit } : {}),\n // LANE 10 P4: a status's groups and a barcode's code type, sent only when they changed.\n ...(statusGroupsChanged ? { status_groups: statusGroupsSent } : {}),\n // V11 #4/#10: a rating's top star goes as `max`, the word custom.field_update now takes the way\n // custom.field_declare does; the store writes the max Rule and sets aside any score above it.\n ...(type === \"rating\" && ratingMax !== ratingMaxOf(field) ? { max: ratingMax } : {}),\n ...(type === \"barcode\" && symbology !== String(field.config?.[\"symbology\"] ?? \"\") ? { symbology: symbology === \"\" ? null : symbology } : {}),\n ...(type === \"button\" && JSON.stringify(buttonSettings) !== JSON.stringify(buttonStart) ? { button: buttonSettings } : {}),\n ...(field.type === \"relation\" && dependency !== dependencyStart ? { dependency } : {}),\n ...(type === \"autonumber\" && numberPrefix.trim() !== prefixStart\n ? { display_format: { id: \"autonumber\", options: numberPrefix.trim() === \"\" ? {} : { prefix: numberPrefix.trim() } } }\n : {}),\n // THE CHOICES, ONE ROW EACH, IN ORDER (CHOICE-COLUMN-EDIT): `{id, words}` re-words a\n // choice in place, plain words add one, a choice left out is retired. Sent only when the\n // list is not what the store already holds.\n ...(() => {\n if (!chooses || !choiceList || !choiceListStart) return {};\n const edited = choiceListPatch(choiceListStart, choiceList);\n return edited ? { options: edited } : {};\n })(),\n // REL-DISP. Which of the other record's columns this one shows. Sent for\n // every relation column, `null` included, because `null` is how the door\n // REMOVES a spec and the column goes back to the target table's own\n // reference column — a panel that only sent the key when it was set\n // could turn the override on and never off.\n ...(field.type === \"relation\" ? { display } : {}),\n // STORE-RULE-GAPS: a choice list's own setting, sent for every list so\n // turning it off is as possible as turning it on.\n ...(field.type === \"list\" ? { allow_other: allowOther } : {}),\n // CHAIR-UI-STORE item 1: a total's filter, sent only when it changed; `null` takes it off.\n ...(type === \"rollup\" && rollupFilterChanged ? { filter: (rollupFilter ?? null) as Record<string, unknown> | null } : {}),\n // K2: a re-aimed formula goes WITH its type word, the arm `field_update` reads it in.\n ...(type === \"formula\" && formulaWritten && formulaChanged && formulaText.trim() !== \"\"\n ? { type: \"formula\" as const, formula_text: formulaText.trim() }\n : {}),\n };\n // CHOICE-TAILS: when a removed choice's records have somewhere to go, the list and those\n // records are ONE save through `fieldUpdateRehomingChoices`, and the panel says what it did\n // and offers Undo before it closes.\n if (Object.keys(rehome).length > 0 && Array.isArray((patch as { options?: unknown }).options)) {\n setRehomeRefused(null);\n const done = await client.fieldUpdateRehomingChoices({ field_id: field.id, patch: patch as FieldPatch, rehome });\n if (!done.ok) {\n setRehomeRefused(done.error);\n return;\n }\n tableShapeChanged(tableId);\n for (const c of done.data.undo.cells_back) announceRecordChanged(c.record_id as Uuid);\n const n = done.data.rehomed.reduce((sum, r) => sum + r.records, 0);\n setRehome({});\n setRehomed({ said: `Saved. ${n} ${n === 1 ? \"record was\" : \"records were\"} changed with the choices.`, undo: done.data.undo });\n return;\n }\n const written = await tableMutation.update({ field_id: field.id, patch: patch as FieldPatch });\n if (written !== null) onSaved?.();\n return;\n }\n const spec: NewFieldDeclaration = {\n label,\n // A NEW COLUMN LANDS AT THE END (lane C, review 2026-09-26 C5): declared one past the last\n // column's `sort`, so every view and every client draws it last — never in the alphabetical\n // slot of its internal key.\n sort: nextFieldSort(fields.data),\n ...(isRelationFieldType(type)\n ? {\n type: \"relation\" as const,\n relation_target: relationTarget as Uuid,\n // REL-DISP. Left out entirely when the person did not override it,\n // so a plain relation's document is byte-identical to yesterday's.\n ...(display ? { display } : {}),\n // REL-2. What happens to this record when the thing it points at\n // goes. The panel asks nothing about it yet, so it names the store's\n // own default rather than leaving the key out — nothing is silently\n // decided somewhere else.\n on_target_delete: \"set_null\" as const,\n ...(type === \"relation\" && nestsSubItems && relationTarget === tableId ? { config: { sub_items: true } } : {}),\n }\n : declaredAsLook(type)\n ? // A RATING OR A TIME the store does not publish as its own word: a plain column wearing\n // its look, in the same declaration (`LOOK_KINDS`, grids review 3 item 5).\n { plain: LOOK_KINDS[type]!.plain, display_format: LOOK_KINDS[type]!.look({ ratingMax }) }\n : isPlainFieldType(type)\n ? { plain: type }\n : isParityFieldType(type)\n ? { parity_type: type }\n // ── FIX-10B-F6: EVERY OTHER KIND GOES AS ITS WORD. ────────────────────────\n // `custom._field_document_for` resolves the WORD a person picked — it is the\n // one body that knows a signature is text wearing a format, a checkbox is a\n // boolean, and a `banana` is nothing — and `parity_type` is only for the\n // fourteen it publishes as such. This branch used to be `{ parity_type: type }`\n // for everything that was not plain or a relation, so the moment the menu gained\n // a kind that is not one of the fourteen the panel would have sent it as a\n // parity type and been refused \"There is no field type called signature\". The\n // menu is the store's list now (`DECLARABLE_FIELD_KINDS`), so this is the arm\n // every future kind arrives through.\n : { type: type as Exclude<PickableFieldType, LookFieldKind> }),\n required,\n dated,\n multi: multiApplies(type) ? multi : type === \"multi_select\",\n sensitivity: sensitivity as FieldSensitivity,\n context_policy: contextPolicy as ContextPolicy,\n rules,\n ...(type === \"select\" || type === \"multi_select\" || type === \"status\" ? { options } : {}),\n // LANE 10 P4: what the panel asked of a rating, a status, a barcode and a count.\n ...(type === \"rating\" && !declaredAsLook(type) ? { max: ratingMax } : {}),\n ...(type === \"status\" ? { status_groups: statusGroupsSent } : {}),\n ...(type === \"barcode\" && symbology !== \"\" ? { symbology } : {}),\n ...(type === \"button\" ? { button: buttonSettings } : {}),\n ...(type === \"autonumber\" && numberPrefix.trim() !== \"\" ? { display_format: { id: \"autonumber\", options: { prefix: numberPrefix.trim() } } } : {}),\n ...(type === \"count\" ? { via } : {}),\n // THE COLOURS ITS CHOICES WERE GIVEN (W1-B), on the Field's look in the same declaration:\n // both declare doors build the Field through `custom._field_document_for`, which keeps a\n // `display_format` it is handed — so the grid paints them from its first draw.\n ...(() => {\n const look = listsChoices ? choiceLookForNewList(type === \"multi_select\", newChoices) : null;\n return look ? { display_format: look } : {};\n })(),\n ...((type === \"select\" || type === \"multi_select\") && allowOther ? { allow_other: true } : {}),\n ...(type === \"entity_reference\" ? { allowed_types: allowedTypes } : {}),\n ...(type === \"currency\" ? { unit } : {}),\n ...(type === \"datetime\" ? { kind: withTime ? (\"datetime\" as const) : (\"date\" as const) } : {}),\n ...(type === \"lookup\" ? { via, pick } : {}),\n ...(type === \"rollup\"\n ? { via, agg, ...(agg === \"count\" ? {} : { of }), ...(rollupFilter ? { filter: rollupFilter as unknown as Record<string, unknown> } : {}) }\n : {}),\n ...(type === \"formula\"\n ? formulaWritten\n ? { formula_text: formulaText.trim() }\n : { expr: formulaExpression(formulaOp, formulaFields, formulaSeparator) }\n : {}),\n };\n const written = onEntity\n ? await entityMutation.declare({ token: entityToken as string, spec: spec as unknown as NewEntityFieldDeclaration })\n : await tableMutation.declare({ table_id: tableId, spec });\n if (written === null) return;\n // 🚨 SUCCESS IS A READ-BACK, NOT A WRITE'S ANSWER (lane LIMITS-FIX-UI, 2026-09-21).\n //\n // Crew C, on fifty-one real national parks: \"Every 'Add field' attempt appeared to\n // succeed on screen (no error text), but a direct fields() read afterward showed\n // only the table's default Title column — none of the 5 fields actually persisted.\"\n // This panel closed on the DOOR'S ANSWER, and the grid then drew \"This table has no\n // columns yet\" over real, complete data. A screen that reports a success it has not\n // confirmed is the one thing a person cannot recover from, because they move on.\n //\n // So it asks the table for its columns and looks for the one it just made, BY ID.\n // The store's own cause was fixed by lane LIMITS-FIX the same day; this is the half\n // that means the SCREEN can never claim it again, whatever the store does next.\n const landed = onEntity ? await client.entityFields({ token: entityToken as string }) : await client.fields({ table_id: tableId });\n if (landed.ok && !landed.data.some((f) => f.id === written)) {\n setNotLanded(true);\n return;\n }\n setNotLanded(false);\n // H2 (lane DEFAULT-GRID-PARITY): an autonumber column numbers what is ALREADY here too, in\n // the order it was made — the older grid's backfill. A refusal is said, and the panel stays,\n // because a column that numbers only tomorrow's records would be a quiet half-answer.\n if (type === \"autonumber\") {\n const numbered = await client.autonumberBackfill({ field_id: written });\n if (!numbered.ok) {\n setBackfillError(numbered.error);\n return;\n }\n }\n setBackfillError(null);\n // NOTION-PROPS: the same link as a column on the other table, made through the store's own door.\n if (type === \"relation\" && showOnOther && otherTable.data && otherTable.data.id !== tableId) {\n const made = await client.relationReverseField({ field_id: written });\n if (!made.ok) {\n setReverseRefused(made.error);\n return;\n }\n tableShapeChanged(relationTarget as Uuid);\n }\n setReverseRefused(null);\n onSaved?.();\n };\n\n const remove = async () => {\n if (!field) return;\n const gone = await tableMutation.retire({ field_id: field.id });\n // Left asking while the dialog closes, so nothing in it moves as it goes (WALK3-FIX).\n if (gone) (onRemoved ?? onSaved)?.();\n else setAskingToRemove(false);\n };\n\n return (\n <div className={cn(\"flex min-w-0 flex-col gap-3 text-xs\", className)} data-records-field-editor=\"\">\n {/* One row of header: what this is, and nothing restating it. */}\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{field ? `Field · ${fieldName(field)}` : \"New field\"}</span>\n <span className=\"ml-auto text-muted-foreground\">{tableLabel}</span>\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <label className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Name</Label>\n <BasicInput\n value={label}\n autoFocus\n aria-label=\"Field name\"\n placeholder=\"Day rate\"\n onChange={(e) => setLabel(e.target.value)}\n onBlur={(e) => {\n // Leaving an empty name box is an attempt; a click on Cancel is not.\n const to = e.relatedTarget as HTMLElement | null;\n if (to?.textContent === \"Cancel\") return;\n setAttempted(true);\n }}\n {...(nameTaken ? { \"aria-invalid\": true, \"aria-describedby\": \"field-editor-name-taken\" } : {})}\n />\n {/* SAID AS IT IS TYPED (the Sheet's column-name check): the store still judges on Save. */}\n {nameTaken ? (\n <span id=\"field-editor-name-taken\" data-field-editor-name-taken=\"\" className=\"truncate text-[11px] text-destructive\" title={columnNameTakenLine(nameTaken, noun)}>\n {columnNameTakenLine(nameTaken, noun)}\n </span>\n ) : null}\n </label>\n\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">What it holds</Label>\n <Select\n value={type}\n disabled={editing}\n onValueChange={(next) => setType(next as PickableFieldType)}\n >\n <SelectTrigger size=\"sm\" aria-label=\"What this field holds\" {...(choice?.explanation ? { title: choice.explanation } : {})}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIELD_TYPE_GROUPS.filter((group) => offered.some((c) => c.group === group)).map((group) => (\n <SelectGroup key={group}>\n <SelectLabel>{group}</SelectLabel>\n {/* An existing column of a kind the menu does not offer yet still reads as its own kind (P4). */}\n {FIELD_TYPE_CATALOGUE.filter((c) => c.group === group && (c.id === type || offered.includes(c))).map((c) => (\n <SelectItem key={c.id} value={c.id}>\n {c.label}\n </SelectItem>\n ))}\n </SelectGroup>\n ))}\n </SelectContent>\n </Select>\n {/* CHANGE WHAT IT HOLDS (review 2, C3): the store's retype door, with the count before. */}\n {editing && field ? (\n <FieldRetype field={liveField ?? field} tableId={tableId} />\n ) : null}\n </div>\n </div>\n\n {/* WHAT THE PANEL ASKS FOR NEXT depends entirely on the answer above, and\n nothing else on this panel knows the difference between the sixteen. */}\n {/* REL-DISP: a relation is asked its questions when EDITING too. Until\n 2026-09-21 this branch skipped every existing column that was not a\n choice list, so there was nowhere to say which of the other record's\n columns a link should show — the one thing about an existing relation\n a person most wants to change. The target itself stays locked there\n (`lockTarget={editing}`): this panel sends no `relation_target` in a\n patch, and a picker that let a person change it would be a control\n that silently does nothing. */}\n {/* F5 (lane STORE-TAILS-2): a worked-out column that is ALREADY THERE gets no formula\n controls on this panel, and until now it got no sentence either — the panel simply\n showed nothing about the one thing that column is. It cannot get the controls in this\n lane: `custom.field_update` takes an `expr` patch (its own FLD-11 arm), but\n `FieldPatch` in `@ai-matrx/records` has no `expr` key, so sending one would need that\n package published too. A live control that cannot send is worse than none, so the\n panel SAYS so instead of standing silent over it. */}\n {type === \"formula\" && others.length > 0 ? (\n <div className=\"flex flex-col gap-2\">\n {editing ? (\n startingFormulaText.trim() === \"\" ? (\n <p className=\"text-[11px] text-muted-foreground\">{EDITING_A_WORKED_OUT_COLUMN}</p>\n ) : null\n ) : (\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"How to make this column\">\n <Button\n type=\"button\"\n size=\"sm\"\n variant={formulaWritten ? \"ghost\" : \"secondary\"}\n aria-pressed={!formulaWritten}\n onClick={() => setFormulaWritten(false)}\n >\n Pick the columns\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant={formulaWritten ? \"secondary\" : \"ghost\"}\n aria-pressed={formulaWritten}\n onClick={() => setFormulaWritten(true)}\n >\n Write a formula\n </Button>\n </div>\n )}\n {formulaWritten ? (\n <FormulaTextEditor\n tableId={tableId}\n text={formulaText}\n onText={setFormulaText}\n onChecked={setFormulaOk}\n columns={others}\n />\n ) : null}\n </div>\n ) : editing && type === \"formula\" ? (\n <p className=\"text-[11px] text-muted-foreground\">No other column to read.</p>\n ) : null}\n {/* CHAIR-ROLLUP-HONEST: a column this lookup or roll-up reads is archived — named, with Bring back. */}\n {editing && field && !onEntity && (type === \"lookup\" || type === \"rollup\") ? (\n <SourceArchivedNotice fieldId={field.id} tableId={tableId} />\n ) : null}\n {(!editing && !(type === \"formula\" && formulaWritten)) ||\n type === \"select\" ||\n type === \"multi_select\" ||\n type === \"status\" ||\n type === \"rating\" ||\n type === \"barcode\" ||\n type === \"relation\" ||\n type === \"entity_reference\" ? (\n <TypeQuestions\n type={type}\n editing={editing}\n tableId={tableId}\n relationTarget={relationTarget}\n setRelationTarget={setRelationTarget}\n display={display}\n setDisplay={setDisplay}\n unit={unit}\n setUnit={setUnit}\n withTime={withTime}\n setWithTime={setWithTime}\n via={via}\n setVia={setVia}\n pick={pick}\n setPick={setPick}\n agg={agg}\n setAgg={setAgg}\n of={of}\n setOf={setOf}\n formulaOp={formulaOp}\n setFormulaOp={setFormulaOp}\n formulaFields={formulaFields}\n setFormulaFields={setFormulaFields}\n formulaSeparator={formulaSeparator}\n setFormulaSeparator={setFormulaSeparator}\n relations={sourcesFor(type)}\n others={others}\n choiceList={\n editing && field ? (\n <ChoiceListEditor\n field={field}\n rows={choiceList}\n onRows={setChoiceList}\n onStart={setChoiceListStart}\n allowOther={allowOther}\n rehome={rehome}\n onRehome={setRehome}\n />\n ) : (\n <ChoiceListEditor isNew rows={newChoices} onRows={setNewChoices} />\n )\n }\n allowedTypes={allowedTypes}\n setAllowedTypes={setAllowedTypes}\n newer={\n type === \"rating\" ? (\n <RatingMaxQuestion\n value={ratingMax}\n onChange={(next) => {\n setRatingMax(next);\n // An existing rating's top star is its max Rule, saved with the rules.\n // An existing rating's new top star is sent as `max` with the save (above).\n }}\n />\n ) : type === \"status\" ? (\n <StatusGroupsQuestion rows={shownStatusRows} onGroup={(ref, next) => setStatusGroups({ ...statusGroups, [ref]: next })} />\n ) : type === \"barcode\" ? (\n <BarcodeSymbologyQuestion value={symbology} onChange={setSymbology} />\n ) : null\n }\n />\n ) : null}\n\n {type === \"button\" ? (\n <ButtonSettingsEditor value={buttonSettings} onChange={setButtonSettings} tableId={onEntity ? null : tableId} fields={others} />\n ) : null}\n {type === \"autonumber\" ? (\n <label className=\"flex max-w-[16rem] flex-col gap-1\">\n <Label className=\"text-xs\">Prefix</Label>\n <BasicInput className=\"h-8 text-xs\" placeholder=\"TASK-\" maxLength={16} data-records-autonumber-prefix=\"\" value={numberPrefix} onChange={(e) => setNumberPrefix(e.target.value)} />\n </label>\n ) : null}\n {editing && field?.type === \"relation\" && field.relation_target && field.relation_target === field.entity_definition_id ? (\n <label className=\"flex items-center gap-1.5 text-sm\" title=\"A timeline draws a line to each record this one waits on\">\n <Checkbox checked={dependency} aria-label=\"Waits on the linked records\" data-records-dependency=\"\" onCheckedChange={(v) => setDependency(v === true)} />\n <span>Waits on the linked records</span>\n </label>\n ) : null}\n {type === \"rollup\" ? (\n <RollupFilterQuestion\n relation={totalSources.find((f) => f.key === via)}\n agg={agg}\n editing={editing}\n value={rollupFilter}\n onChange={setRollupFilter}\n />\n ) : null}\n\n {editing && field && !(type === \"select\" || type === \"multi_select\" || type === \"status\") ? (\n <FieldFormatPicker field={field} value={showsAs} onValue={setShowsAs} />\n ) : null}\n\n <div className=\"flex flex-wrap items-center gap-4\">\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={required}\n aria-label=\"Required\"\n onCheckedChange={(v) => setRequired(v === true)}\n />\n <span title=\"Every record has to have one\">Required</span>\n </label>\n {offersMany ? (\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={multi}\n aria-label=\"Can hold more than one\"\n onCheckedChange={(v) => setMulti(v === true)}\n />\n Can hold more than one\n </label>\n ) : null}\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={dated}\n aria-label=\"Each value has its own date\"\n onCheckedChange={(v) => setDated(v === true)}\n />\n Each value has its own date\n </label>\n {!field && type === \"relation\" && otherTable.data && otherTable.data.id !== tableId ? (\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={showOnOther}\n aria-label={`Show on ${otherTable.data.name ?? \"the other table\"}`}\n onCheckedChange={(v) => setShowOnOther(v === true)}\n data-records-show-on-other=\"\"\n />\n Show on {otherTable.data.name ?? \"the other table\"}\n </label>\n ) : null}\n {!field && type === \"relation\" && relationTarget === tableId ? (\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={nestsSubItems}\n aria-label=\"Sub-items\"\n onCheckedChange={(v) => {\n setNestsSubItems(v === true);\n if (v === true) setMulti(false);\n }}\n data-records-sub-items=\"\"\n />\n <span title=\"Each record sits under the one this column names\">Sub-items</span>\n </label>\n ) : null}\n {/* Offered only because the choice editor honours it (editors.tsx). */}\n {CHOICE_EDITOR_ADDS_WHAT_IS_TYPED && (type === \"select\" || type === \"multi_select\") ? (\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={allowOther}\n aria-label=\"A value that is not one of the choices is added to them\"\n onCheckedChange={(v) => setAllowOther(v === true)}\n />\n A value that is not one of the choices is added to them\n </label>\n ) : null}\n </div>\n\n {/* SHEET PARITY: the column's default, typed in the column's own editor. */}\n {editing && field && takesADefault(liveField ?? field) ? (\n <div className=\"flex flex-col gap-1\" data-records-field-default=\"\">\n <Label htmlFor=\"records-field-default\" className=\"text-xs\">\n {DEFAULT_LABEL}\n </Label>\n <FieldControl\n id=\"records-field-default\"\n // The column itself, minus what would make a default write or refuse on its own: it is\n // never required (an empty default is \"none\"), and typed words are never added to a\n // choice list from here — Save is the one write.\n field={{ ...(liveField ?? field), required: false, config: { ...((liveField ?? field).config ?? {}), allow_other: false } }}\n value={startsWith}\n onChange={setStartsWith}\n />\n </div>\n ) : null}\n\n <Separator />\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Who can see what is in it</Label>\n <Select value={sensitivity} onValueChange={setSensitivity}>\n <SelectTrigger size=\"sm\" aria-label=\"Who can see what is in it\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {sensitivities.map((row) => (\n <SelectItem key={row.value} value={row.value}>\n {row.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Can an assistant read it</Label>\n <Select value={contextPolicy} onValueChange={setContextPolicy}>\n <SelectTrigger size=\"sm\" aria-label=\"Can an assistant read it\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {AGENT_VISIBILITY.map((row) => (\n <SelectItem key={row.value} value={row.value}>\n {row.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n <Separator />\n\n {/* FLD-3: a constraint is a RULE attached to the Field, never a behaviour. */}\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">What counts as a good value</span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"ml-auto\"\n onClick={() => setRules([...rules, { kind: \"min\", value: 0 }])}\n >\n Add a check\n </Button>\n </div>\n {/* FLD-3 / B1: the store's `unique` rule, as one tick rather than a row with a value box. */}\n {canBeUnique(type, multi) || rules.some((r) => r.kind === \"unique\") ? (\n <label className=\"flex items-center gap-1.5\" data-records-field-unique=\"\">\n <Checkbox\n checked={rules.some((r) => r.kind === \"unique\")}\n aria-label={UNIQUE_LABEL}\n onCheckedChange={(v) => setRules(withUnique(rules, v === true))}\n />\n {UNIQUE_LABEL}\n </label>\n ) : null}\n {rules.length === 0 ? (\n <p className=\"text-muted-foreground\">\n No checks.\n </p>\n ) : null}\n {rules.map((rule, index) => rule.kind === \"unique\" ? null : (\n <div key={`${rule.kind}-${index}`} className=\"flex items-center gap-1\">\n <Select\n value={rule.kind}\n onValueChange={(kind) =>\n setRules(rules.map((r, i) => (i === index ? { ...r, kind: kind as FieldRule[\"kind\"] } : r)))\n }\n >\n <SelectTrigger size=\"sm\" className=\"w-52\" aria-label={`Check ${index + 1}`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {RULE_KINDS.map((row) => (\n <SelectItem key={row.kind} value={row.kind}>\n {row.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {/* STORE-RULE-GAPS: a length has a shortest beside its longest\n (the older grid's minLength). A blank box sends nothing. */}\n {rule.kind === \"length\" ? (\n <BasicInput\n className=\"h-8 w-24\"\n inputMode=\"numeric\"\n placeholder=\"fewest\"\n value={rule.min === undefined ? \"\" : String(rule.min)}\n aria-label={`Check ${index + 1} fewest characters`}\n onChange={(e) =>\n setRules(rules.map((r, i) => (i === index ? withNumber(r, \"min\", e.target.value) : r)))\n }\n />\n ) : null}\n <BasicInput\n className=\"h-8\"\n {...(rule.kind === \"length\" ? { inputMode: \"numeric\" as const, placeholder: \"most\" } : {})}\n value={String(rule.value ?? \"\")}\n aria-label={rule.kind === \"length\" ? `Check ${index + 1} most characters` : `Check ${index + 1} value`}\n onChange={(e) => setRules(rules.map((r, i) => (i === index ? { ...r, value: e.target.value } : r)))}\n />\n {/* STORE-RULE-GAPS: how a person writes it (the older grid's\n patternHint). A refused value is told \"Enter it like …\". */}\n {rule.kind === \"pattern\" ? (\n <BasicInput\n className=\"h-8\"\n placeholder=\"for example 949-555-0142\"\n value={rule.example ?? \"\"}\n aria-label={`Check ${index + 1} example`}\n onChange={(e) =>\n setRules(rules.map((r, i) => (i === index ? withText(r, \"example\", e.target.value) : r)))\n }\n />\n ) : null}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={`Remove check ${index + 1}`}\n onClick={() => setRules(rules.filter((_, i) => i !== index))}\n >\n ×\n </Button>\n </div>\n ))}\n </div>\n\n {/* V13 #4: a check that tightens, or a lower top star, sets aside what no longer fits — counted\n here before Save, the way a retype is (`FieldRulePreview`). */}\n {editing && field && !onEntity && rulesChanged(savedRules, editedRules) ? (\n <FieldRulePreview field={field} tableId={tableId} rules={editedRules} />\n ) : null}\n\n {mutation.error ? <RefusalNotice error={mutation.error} /> : null}\n\n {/* WHAT IS STILL MISSING, where the person is about to press. Not a\n disabled button with nothing beside it, and not a refusal from the\n store a second after the press: the sentence and the control are one\n thing, and the sentence names what to do. */}\n {/* 🚨 NOT A REFUSAL YET, SO NOT RED (lane REFUSAL-SWEEP, 2026-09-23). Nothing\n was pressed and nothing was refused: this is the reason Save is waiting,\n read BEFORE the press. Drawn as an alarm it told somebody half-way through\n naming a column that they had already failed. It is the Save button's own\n description, so a screen reader reads it on the button. */}\n {/* WALK3-FIX (2026-10-07): the sentence now sits IN the footer row, beside Save, so it never\n adds a line to the dialog (typing a name shifted the card 0.0094), and it waits for an\n attempt — a Save press or leaving the name box — so a fresh dialog opens without\n \"Give the column a name.\" before anything was typed. A formula's own check still speaks\n as it is written. */}\n {/* The store took the column and the table does not have it. Never a silent\n \"saved\" over a table that did not change — see `save`. */}\n {notLanded ? (\n <RefusalNotice\n error={refusalOf(\n \"internal\",\n onEntity\n ? \"The store accepted this field and these records do not have it yet. Nothing was lost, and this panel is staying open.\"\n : COLUMN_DID_NOT_LAND_SENTENCE,\n COLUMN_DID_NOT_LAND_REMEDY,\n )}\n />\n ) : null}\n {rehomeRefused ? <RefusalNotice error={rehomeRefused} /> : null}\n {/* CHOICE-TAILS: what the save did to the records of removed choices, with its Undo. */}\n {rehomed ? (\n <div data-records-choice-rehomed=\"\" className=\"flex flex-wrap items-center gap-2 text-[11px]\">\n <span>{rehomed.said}</span>\n {rehomed.undo ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => {\n const undo = rehomed.undo;\n if (!undo || !field) return;\n void client\n .fieldUpdateRehomingChoices({ field_id: field.id, patch: { options: undo.options }, cells_back: undo.cells_back })\n .then((back) => {\n if (!back.ok) {\n setRehomeRefused(back.error);\n return;\n }\n tableShapeChanged(tableId);\n for (const c of undo.cells_back) announceRecordChanged(c.record_id as Uuid);\n setChoiceList(null);\n setChoiceListStart(null);\n setRehomed({ said: \"Undone. The choices and the records that held them are back as they were.\", undo: null });\n });\n }}\n >\n Undo\n </Button>\n ) : null}\n <Button type=\"button\" size=\"sm\" className=\"h-6 px-2 text-xs\" onClick={() => onSaved?.()}>\n Done\n </Button>\n </div>\n ) : null}\n {/* NOTION-PROPS: the link is made here; the other table's column was not. */}\n {reverseRefused ? (\n <div data-records-reverse-field-refused=\"\" className=\"flex flex-col gap-1\">\n <p className=\"text-[11px]\">The link is made. Its column on the other table was not:</p>\n <RefusalNotice error={reverseRefused} />\n </div>\n ) : null}\n {/* H2: the column is made, but the records already here were not numbered. */}\n {backfillError ? (\n <div data-records-autonumber-backfill-refused=\"\" className=\"flex flex-col gap-1\">\n <p className=\"text-[11px]\">The column is made. The records already in the table were not numbered:</p>\n <RefusalNotice error={backfillError} />\n </div>\n ) : null}\n\n <div className=\"flex min-w-0 flex-nowrap items-center gap-2\" data-field-editor-footer=\"\">\n <Button\n size=\"sm\"\n // A formula the store cannot read is said as it is written, and Save waits for it.\n disabled={mutation.saving || Boolean(formulaMissing)}\n {...(missingShown ? { \"aria-describedby\": \"field-editor-missing\" } : {})}\n onClick={() => {\n if (missing) {\n setAttempted(true);\n return;\n }\n void save();\n }}\n >\n {mutation.saving ? \"Saving…\" : field ? EDIT_FIELD_SAVE_LABEL : onEntity ? ADD_STANDARD_FIELD_SAVE_LABEL : ADD_FIELD_SAVE_LABEL}\n </Button>\n {onCancel ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={onCancel}>\n Cancel\n </Button>\n ) : null}\n <span\n id=\"field-editor-missing\"\n data-field-editor-missing={missingShown ? \"\" : undefined}\n title={missingShown ?? undefined}\n className=\"min-w-0 flex-1 truncate text-[11px] text-muted-foreground\"\n >\n {missingShown}\n </span>\n {field ? (\n /* WALK3-FIX (2026-10-07): the confirm appears IN PLACE. Both states share one grid cell,\n the idle one drawn invisibly under the asking one and the other way round, so the\n footer is always as wide and as tall as its larger state: opening the confirm moved\n the dialog card 0.2278 and closing it 0.1303. The consequence is the tooltip of\n \"Remove it\" (interface-text: the slot holds a label, never a paragraph). */\n <div className=\"ml-auto grid shrink-0 items-center\" data-field-editor-remove={askingToRemove ? \"asking\" : \"idle\"}>\n <div className={cn(\"col-start-1 row-start-1 flex items-center justify-end gap-2\", askingToRemove && \"invisible\")} aria-hidden={askingToRemove || undefined}>\n <Button size=\"sm\" variant=\"outline\" tabIndex={askingToRemove ? -1 : undefined} onClick={() => setAskingToRemove(true)}>\n Remove this field\n </Button>\n </div>\n <div className={cn(\"col-start-1 row-start-1 flex items-center justify-end gap-2\", !askingToRemove && \"invisible\")} aria-hidden={!askingToRemove || undefined}>\n <span className=\"whitespace-nowrap text-destructive\" data-field-editor-remove-ask=\"\">\n Archive this field?\n </span>\n <Button\n size=\"sm\"\n variant=\"destructive\"\n tabIndex={askingToRemove ? undefined : -1}\n disabled={mutation.saving}\n title={removeConsequence}\n aria-description={removeConsequence}\n onClick={() => void remove()}\n >\n Remove it\n </Button>\n <Button size=\"sm\" variant=\"ghost\" tabIndex={askingToRemove ? undefined : -1} onClick={() => setAskingToRemove(false)}>\n Keep it\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * WHAT THE PANEL STILL NEEDS BEFORE THE STORE WOULD TAKE THIS, in plain words.\n *\n * It answers exactly the questions this panel asked, so every sentence names a\n * control the person is looking at. It is NOT a second copy of the store's\n * rules and it is not allowed to become one: the store decides, and every one\n * of these is something the panel can see is unanswered without asking it.\n *\n * Exported so the suite can assert the sentences without driving the whole\n * panel, and so the red twin can assert that removing it puts the contract row\n * id back in front of a person.\n */\n/**\n * WHAT A LOOKUP OR A ROLLUP CAN READ THROUGH, by kind: a link, a person, a file — or null when the\n * column is not link-like (the store resolves `via` through every relation it can follow to a\n * record; a platform reference is `{token, id}` and is not one of them).\n */\nexport function sourceKindOf(field: Field): \"link\" | \"person\" | \"file\" | null {\n if (isBackLinkSource(field)) return \"link\";\n const kind = editorKindFor(field);\n if (kind === \"relation\") return \"link\";\n if (kind === \"member\") return \"person\";\n if (kind === \"attachment\") return \"file\";\n return null;\n}\n\nexport function whatIsMissing(state: {\n type: PickableFieldType;\n label: string;\n options: string[];\n via: string;\n pick: string;\n agg: NonNullable<NewFieldDeclaration[\"agg\"]>;\n of: string;\n relations: Field[];\n formulaFields: string[];\n /** Only a link asks for one, so a caller about any other kind leaves it out. */\n relationTarget?: string;\n /** Only an entity-reference column asks for these (SC-R). */\n allowedTypes?: readonly string[];\n /** What the thing being made is called where it is made: a table's \"column\", a record page's \"field\". */\n noun?: \"column\" | \"field\";\n}): string | null {\n const noun = state.noun ?? \"column\";\n const { type, label, via, pick, agg, of, relations, formulaFields } = state;\n const relationTarget = state.relationTarget ?? \"\";\n if (label.trim() === \"\") return `Give the ${noun} a name.`;\n\n if (type === \"entity_reference\") return whatIsMissingForEntityReference(state.allowedTypes ?? []);\n\n // A LINK WITH NOWHERE TO POINT. The store refuses it — \"relation_target names\n // the Table whose records this column may point at\" — which is a caller's\n // sentence; this is the panel's, and it names the control above it.\n if (type === \"relation\") {\n if (relationTarget.trim() === \"\") return `Choose the table this ${noun} points at.`;\n return null;\n }\n\n // A choice column may start with no choices (lane CHOICE-COLUMN-EDIT b): the store makes it an\n // empty list, and its first choice is added later, from its settings or from a cell.\n if (type === \"select\" || type === \"multi_select\") {\n return null;\n }\n\n if (type === \"lookup\" || type === \"rollup\") {\n if (relations.length === 0) {\n return type === \"rollup\"\n ? \"A total is worked out across the records a link, Person or File column holds, and this table has none yet. Add one that can hold more than one, then come back.\"\n : \"A borrowed value is read from the record a link, Person or File column holds, and this table has none yet. Add one, then come back.\";\n }\n const chosen = relations.find((relation) => relation.key === via);\n if (!chosen) {\n return type === \"rollup\"\n ? \"Choose the column whose records this one adds up.\"\n : \"Choose the column whose record this one reads from.\";\n }\n // THE ONE THE VERDICT HIT. The column a person means is usually there and\n // simply holds one thing; saying which column and what to do about it beats\n // hiding it from the list and beats \"config.via names a relation Field\".\n if (type === \"rollup\" && !chosen.multi) {\n return `${fieldName(chosen)} points at one record at a time, so there is nothing to total. Tick \"Can hold more than one\" on ${fieldName(chosen)}, or use Borrowed value to read its one value.`;\n }\n if (type === \"lookup\" && pick.trim() === \"\") {\n return `Say which value to read from the record ${fieldName(chosen)} points at.`;\n }\n if (type === \"rollup\" && agg !== \"count\" && of.trim() === \"\") {\n return \"Say which value of those records to work out.\";\n }\n return null;\n }\n\n // ── FIX-10B-F5, 2026-09-22: THE FORMULA, WHICH THIS FUNCTION USED TO WAVE THROUGH. ──\n //\n // It used to return null here, reasoning that \"the store already accepts it (it writes\n // `{op, args:[{const:\"\"}]}`)… if it should be refused, it is the store's rule to make.\"\n // VERIFIER-10 is what that costs. On Rincon Plumbing Co's \"Truck 1 dispatch backlog\" an\n // admin added \"Ticket label\" as a worked-out column and pressed Create field; the column\n // appeared in the grid and **every cell read `—`, on all 100 rows**, before a write, after\n // a write to a source column, and after a reload. The field the panel wrote, read back off\n // the live store: `\"expr\": {\"op\": \"concat\", \"args\": [{\"const\": \"\"}]}` — a formula that\n // reads NO column. `custom.rule_eval` evaluates it exactly as written, answers the empty\n // string every time, and the grid draws an empty string as `—`. The evaluator was never\n // broken: the same door over the same record, with the two field ids in the expr, answers\n // `RPC-T1-7000 — 100 Ventura Ave, Ventura`.\n //\n // AND IT IS NOT THE STORE'S RULE TO MAKE, which is why it never got made. A formula column\n // whose expression is trivial is LEGITIMATE at the store: a Rule with `target_field_id` can\n // be the thing that works it out (`scripts/campaign-tests/w1_rule_apply.sql` declares\n // exactly that pair, deliberately, and the Rules that fill them come afterwards). The store\n // cannot tell that column apart from this one. THIS SCREEN CAN, and only this screen can:\n // it is the one that asked the person which columns and was answered with none. So the\n // refusal lives where the knowledge is, the button says what is still needed, and the\n // placeholder expression is never sent. Nothing about the store's behaviour moves, so there\n // is no second truth.\n if (type === \"formula\") {\n if (formulaFields.length === 0) return \"Pick the columns this one works out its answer from.\";\n return null;\n }\n\n return null;\n}\n\n/**\n * Whether \"can hold more than one\" is a question for this type at all.\n *\n * A link a person aimed themselves is exactly the column the roll-up panel\n * sends them to tick this on, so leaving it off the list here would have left\n * that remedy sentence pointing at a control that is not drawn.\n */\nfunction multiApplies(type: PickableFieldType): boolean {\n return (\n type === \"member\" || type === \"attachment\" || type === \"text\" || type === \"relation\" || type === \"entity_reference\"\n );\n}\n\nfunction unitApplies(type: PickableFieldType): boolean {\n return type === \"currency\";\n}\n\n/**\n * Which kind an existing Field already is, in the words this panel offers — `pickableTypeOf`,\n * the same reader the Settings list uses, so the panel and the list can never disagree (a\n * signature opened here and saved must stay a signature; a Record number must not reopen as a\n * formula and be saved as one).\n */\nfunction startingType(field: Field | undefined): PickableFieldType {\n if (!field) return \"text\";\n return pickableTypeOf(field) ?? \"text\";\n}\n\n/**\n * REC-15 / REC-17: a Rule expression is an object of nodes, and it points at a\n * Field BY ITS ID, never by its name — a name changes and the rule would stop\n * resolving. The panel therefore collects columns, not text.\n */\nfunction formulaExpression(op: string, fieldIds: string[], separator: string): Record<string, unknown> {\n const args = fieldIds.filter((id) => id !== \"\").map((id) => ({ field: id }));\n // F5: only a JOIN has anything between its parts. Sending `separator` on `add` would be a\n // key the evaluator ignores, which is a setting that silently does nothing.\n const joined = op === \"concat\" && separator !== \"\" ? { separator } : {};\n if (args.length === 0) return { op, ...joined, args: [{ const: \"\" }] };\n return { op, ...joined, args };\n}\n\n/** The expression a formula Field is already carrying, in the shape this panel writes. */\nfunction formulaExprOf(field: Field | undefined): Record<string, unknown> | null {\n const expr = (field?.config as Record<string, unknown> | undefined)?.[\"expr\"];\n return expr !== null && typeof expr === \"object\" ? (expr as Record<string, unknown>) : null;\n}\n\nfunction formulaOpOf(field: Field | undefined): string {\n const op = formulaExprOf(field)?.[\"op\"];\n return typeof op === \"string\" && op !== \"\" ? op : \"concat\";\n}\n\n/** REC-17: the args hold field IDS, so they map straight back onto the picked columns. */\nfunction formulaFieldIdsOf(field: Field | undefined): string[] {\n const args = formulaExprOf(field)?.[\"args\"];\n if (!Array.isArray(args)) return [];\n return args\n .map((a) => (a !== null && typeof a === \"object\" ? (a as Record<string, unknown>)[\"field\"] : undefined))\n .filter((id): id is string => typeof id === \"string\" && id !== \"\");\n}\n\n/**\n * What a person asked to go between the parts. A formula written before this control\n * existed has no `separator` key at all and keeps answering exactly as it always did —\n * so the default below applies to a NEW column and never rewrites an old one.\n */\nfunction formulaSeparatorOf(field: Field | undefined): string {\n const expr = formulaExprOf(field);\n if (expr === null) return FORMULA_DEFAULT_SEPARATOR;\n const sep = expr[\"separator\"];\n return typeof sep === \"string\" ? sep : \"\";\n}\n\nfunction TypeQuestions(props: {\n type: PickableFieldType;\n editing: boolean;\n tableId: Uuid;\n relationTarget: string;\n display: RelationDisplay | null;\n setDisplay: (next: RelationDisplay | null) => void;\n setRelationTarget: (value: string) => void;\n unit: string;\n setUnit: (value: string) => void;\n withTime: boolean;\n setWithTime: (value: boolean) => void;\n via: string;\n setVia: (value: string) => void;\n pick: string;\n setPick: (value: string) => void;\n agg: NonNullable<NewFieldDeclaration[\"agg\"]>;\n setAgg: (value: NonNullable<NewFieldDeclaration[\"agg\"]>) => void;\n of: string;\n setOf: (value: string) => void;\n formulaOp: string;\n setFormulaOp: (value: string) => void;\n formulaFields: string[];\n setFormulaFields: (value: string[]) => void;\n formulaSeparator: string;\n setFormulaSeparator: (value: string) => void;\n relations: Field[];\n others: Field[];\n /** An EXISTING choice column's per-choice list, drawn in place of the one-per-line box. */\n choiceList?: ReactNode;\n allowedTypes: string[];\n setAllowedTypes: (next: string[]) => void;\n /** LANE 10 P4: the question a rating, a status or a barcode asks. */\n newer?: ReactNode;\n}) {\n const { type } = props;\n\n if (type === \"entity_reference\") {\n // SC-R: which kinds of platform thing it points at. On an existing column the store keeps its\n // kinds and this panel sends no change, so the list is shown locked, never as a dead control.\n return <EntityReferenceKindPicker value={props.allowedTypes} onChange={props.setAllowedTypes} locked={props.editing} />;\n }\n\n if (type === \"relation\") {\n // THE ONE BUILDER. Which table, which of its columns, in which order, joined\n // by what — asked here exactly as it is asked from the grid's column\n // settings, a condition, a form and a portal, because it is one component.\n // On an EXISTING column the target is locked: `custom.field_update` is sent\n // no `relation_target` from this panel, so a picker that let a person change\n // it would be a control that silently does nothing.\n return (\n <ReferenceBuilder\n tableId={props.tableId}\n lockTarget={props.editing}\n value={{ targetTableId: props.relationTarget as Uuid | \"\", display: props.display }}\n onChange={(next) => {\n props.setRelationTarget(String(next.targetTableId));\n props.setDisplay(next.display);\n }}\n />\n );\n }\n\n // LANE 10 P4: a rating's stars and a barcode's code type; a status's choices and their groups.\n if (type === \"rating\" || type === \"barcode\") return <>{props.newer}</>;\n if (type === \"status\") {\n return (\n <div className=\"flex flex-col gap-3\">\n {props.choiceList}\n {props.newer}\n </div>\n );\n }\n\n if (type === \"select\" || type === \"multi_select\") {\n // THE ONE CHOICE EDITOR — a row per choice, each with its colour, for a new column and an\n // existing one alike (`ChoiceListEditor.tsx`).\n return <>{props.choiceList}</>;\n }\n\n if (type === \"currency\") {\n return (\n <label className=\"flex max-w-[16rem] flex-col gap-1\">\n <Label className=\"text-xs\">The currency</Label>\n <BasicInput\n value={props.unit}\n aria-label=\"The currency\"\n placeholder=\"$\"\n onChange={(e) => props.setUnit(e.target.value)}\n />\n </label>\n );\n }\n\n if (type === \"datetime\") {\n return (\n <label className=\"flex items-center gap-1.5\">\n <Checkbox\n checked={props.withTime}\n aria-label=\"Include a time of day\"\n onCheckedChange={(v) => props.setWithTime(v === true)}\n />\n Include a time of day, not just the day\n </label>\n );\n }\n\n if (type === \"lookup\" || type === \"rollup\" || type === \"count\") {\n // EVERY relation column this table has — including the ones that hold ONE\n // record. A rollup needs one that holds several, and the store says so; but\n // a person looking for \"Crew lead\" and not finding it in the list learns\n // nothing, and the sentence under the button tells them exactly what to do\n // about the one they picked. Hiding the answer is not the same as giving it.\n const usable = props.relations;\n if (usable.length === 0) {\n // NEVER A DEAD CONTROL. The reason, and the thing to do about it.\n return (\n <p className=\"text-[11px] text-muted-foreground\">\n No link, Person or File column yet.\n </p>\n );\n }\n return (\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">{type !== \"lookup\" ? \"Across the records in\" : \"Read it from\"}</Label>\n <Select value={props.via} onValueChange={props.setVia}>\n <SelectTrigger size=\"sm\" aria-label={type !== \"lookup\" ? \"Across the records in\" : \"Read it from\"}>\n <SelectValue placeholder=\"Choose a column\" />\n </SelectTrigger>\n <SelectContent>\n {usable.map((f) => (\n <SelectItem key={f.id} value={f.key}>\n {fieldName(f)}\n {isBackLinkSource(f) ? BACK_LINK_SOURCE_SUFFIX : \"\"}\n {sourceKindOf(f) === \"person\" ? \" — a person\" : sourceKindOf(f) === \"file\" ? \" — a file\" : \"\"}\n {type !== \"lookup\" && !f.multi ? \" — holds one\" : \"\"}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {type === \"lookup\" ? (\n <ValueOnTheOtherSide\n label=\"The value to read\"\n help=\"The column on the other record whose value is borrowed.\"\n relation={usable.find((f) => f.key === props.via)}\n value={props.pick}\n onChange={props.setPick}\n />\n ) : type === \"count\" ? null : (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">What to work out</Label>\n <Select value={props.agg} onValueChange={(v) => props.setAgg(v as never)}>\n <SelectTrigger size=\"sm\" aria-label=\"What to work out\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {ROLLUP_OPERATIONS.map((row) => (\n <SelectItem key={row.value} value={row.value}>\n {row.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {props.agg !== \"count\" ? (\n <ValueOnTheOtherSide\n label=\"Of which value\"\n help=\"The column on those records whose values are worked out.\"\n relation={usable.find((f) => f.key === props.via)}\n value={props.of}\n onChange={props.setOf}\n compact\n />\n ) : null}\n </div>\n )}\n </div>\n );\n }\n\n if (type === \"formula\") {\n if (props.others.length === 0) {\n return (\n <p className=\"text-[11px] text-muted-foreground\">\n No other columns yet.\n </p>\n );\n }\n return (\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">What to do</Label>\n <Select value={props.formulaOp} onValueChange={props.setFormulaOp}>\n <SelectTrigger size=\"sm\" className=\"max-w-[18rem]\" aria-label=\"What to do\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FORMULA_OPERATIONS.map((row) => (\n <SelectItem key={row.value} value={row.value}>\n {row.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Which columns</Label>\n <div className=\"flex flex-wrap gap-1\">\n {props.others.map((f) => {\n const picked = props.formulaFields.includes(f.id);\n return (\n <Button\n key={f.id}\n type=\"button\"\n size=\"sm\"\n variant={picked ? \"default\" : \"outline\"}\n onClick={() =>\n props.setFormulaFields(\n picked\n ? props.formulaFields.filter((id) => id !== f.id)\n : [...props.formulaFields, f.id],\n )\n }\n >\n {fieldName(f)}\n </Button>\n );\n })}\n </div>\n </div>\n {/* F5 (VERIFIER-11): only a join has anything between its parts, so only a join asks. */}\n {props.formulaOp === \"concat\" ? (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">{FORMULA_SEPARATOR_LABEL}</Label>\n <BasicInput\n value={props.formulaSeparator}\n aria-label={FORMULA_SEPARATOR_LABEL}\n placeholder=\"—\"\n className=\"max-w-[10rem]\"\n onChange={(e) => props.setFormulaSeparator(e.target.value)}\n />\n </div>\n ) : null}\n </div>\n );\n }\n\n return null;\n}\n\n/** What a back-link reads as in the source list: the linking table's records, pointing here. */\nexport const BACK_LINK_SOURCE_SUFFIX = \" — links here\";\nconst BACK_LINK = Symbol.for(\"@ai-matrx/records-ui/back-link\");\n\n/**\n * A REVERSE COLUMN AS A TOTAL'S SOURCE (CHAIR-UI-STORE item 2). Virtual (REL-9: never a Field), so it\n * is drawn in the source list as the relation it mirrors from this end — many records of the linking\n * table — keyed exactly as `custom.reverse_columns` keys it, which is the `via` the store reads.\n */\nexport function backLinkAsSource(column: ReverseColumn): Field {\n return {\n id: `linked:${column.key}`,\n key: column.key,\n label: column.label,\n type: \"relation\",\n multi: true,\n relation_target: column.source_table_id,\n config: {},\n [BACK_LINK]: column,\n } as unknown as Field;\n}\n\nexport function isBackLinkSource(field: Field): boolean {\n return (field as unknown as Record<symbol, unknown>)[BACK_LINK] !== undefined;\n}\n\n/** The totals and lookups on the far table that read through this link column's back-link. */\nexport function readingThroughLink(link: Field, farFields: readonly Field[]): Field[] {\n const key = link.inverse_key ?? `linked_${link.id}`;\n return farFields.filter((f) => {\n const kind = editorKindFor(f);\n return (kind === \"rollup\" || kind === \"lookup\") && (f.config as Record<string, unknown> | undefined)?.[\"via\"] === key;\n });\n}\n\n/** The lead of a total's filter row, in the words of what it works out. */\nexport function rollupFilterLead(agg: string): string {\n return agg === \"count\" ? \"Only count records where\" : \"Only use records where\";\n}\n\n/**\n * \"ONLY COUNT RECORDS WHERE…\" (CHAIR-UI-STORE item 1). A total's `config.filter`, built in THE one\n * condition builder the grid's saved views use (`ConditionGroup`, `ViewFilter.tsx`), over the columns\n * of the table its source points at. It writes the store's Rule shape by far-side field id, which\n * `custom.field_declare` / `custom.field_update` validate and `custom.rollup_value` compiles with\n * `custom.record_filter_sql` — the same grammar, never a second one. A filter written elsewhere in a\n * shape the builder cannot draw is read out and can be cleared, never silently overwritten.\n */\nfunction RollupFilterQuestion({\n relation,\n agg,\n editing,\n value,\n onChange,\n}: {\n relation: Field | undefined;\n agg: string;\n editing: boolean;\n value: RuleExpression | null;\n onChange: (next: RuleExpression | null) => void;\n}) {\n const far = (relation?.relation_target ?? null) as Uuid | null;\n const farFields = useFields(far);\n const conditionFields = useMemo<ConditionField[]>(\n () =>\n (farFields.data ?? [])\n .filter((f) => f.type !== \"formula\")\n .map((f) => ({ id: f.id, key: f.key, label: fieldName(f), field: f })),\n [farFields.data],\n );\n // A new total's source changed: the old conditions name another table's columns.\n const lastFar = useRef(far);\n useEffect(() => {\n if (lastFar.current !== null && far !== lastFar.current && !editing) onChange(null);\n lastFar.current = far;\n }, [far, editing, onChange]);\n if (!relation || !far) return null;\n return (\n <div className=\"flex flex-col gap-1\" data-records-rollup-filter=\"\">\n {!conditionIsDrawable(value) ? (\n <div className=\"flex flex-wrap items-center gap-2 text-[11px]\">\n <span className=\"text-muted-foreground\">\n {rollupFilterLead(agg)} {conditionInWords(value, conditionFields)}.\n </span>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-2 text-xs\" onClick={() => onChange(null)}>\n Clear\n </Button>\n </div>\n ) : (\n <ConditionGroup\n lead={rollupFilterLead(agg)}\n emptyLabel={`every record in ${fieldName(relation)}`}\n expr={value}\n fields={conditionFields}\n onChange={onChange}\n />\n )}\n </div>\n );\n}\n\n/**\n * WHICH VALUE, ON THE OTHER SIDE — offered by NAME, never typed as a key.\n *\n * A borrowed value and a total both read one column of the records the chosen\n * relation points at, and this panel used to ask for that column as free text\n * with the placeholder `name`. So the one question on the panel that a person\n * could not answer without knowing an internal key was the last question on the\n * two column types the sixth-pass verdict could not create — and a typo in it\n * is a column that silently borrows nothing.\n *\n * The relation says which Table it points at, so the columns of that Table are\n * simply offered. When it points at nothing yet, this says so and offers\n * nothing, which is the honest half of the same rule.\n *\n * AND A TABLE THE STORE KEEPS ITSELF STILL HAS COLUMNS. `custom.applicable_fields`\n * answers the Fields a table DECLARES, and the kernels declare none: a Person\n * column points at the person kernel, which has 441 records and zero Field rows.\n * So the picker offered nothing for every Person and every File relation — and\n * the only two column types a person cannot build without it are exactly the\n * two the sixth-pass verdict could not build. Measured 2026-09-20.\n *\n * The store reads the far side with `custom.record_values(…) -> pick`\n * (`custom.lookup_value`), so what a pick may name is a KEY THOSE RECORDS\n * CARRY. When the target declares no Fields, this reads one of its records\n * through the ordinary read door and offers the keys it actually has — the same\n * fact the store will use, asked the same way. Nothing is typed, and nothing is\n * guessed.\n */\nfunction ValueOnTheOtherSide({\n label,\n help,\n relation,\n value,\n onChange,\n compact,\n}: {\n label: string;\n help: string;\n relation: Field | undefined;\n value: string;\n onChange: (value: string) => void;\n compact?: boolean | undefined;\n}) {\n const target = (relation?.relation_target ?? null) as Uuid | null;\n const columns = useFields(target);\n const declared = (columns.data ?? []).filter((f) => f.type !== \"formula\");\n // Only asked when the target declares nothing — the ordinary case costs no\n // extra call, and this one is a single row.\n const sample = useRecords(declared.length === 0 && !columns.loading ? target : null, { pageSize: 1 });\n const carried = sample.data?.rows[0]?.document ?? null;\n const offered: { key: string; name: string }[] =\n declared.length > 0\n ? declared.map((f) => ({ key: f.key, name: fieldName(f) }))\n : Object.keys(carried ?? {}).map((key) => ({ key, name: humanizeIdentifier(key) }));\n const stillAsking = columns.loading || (declared.length === 0 && sample.loading);\n\n const body = !relation ? (\n <p className=\"text-[11px] text-muted-foreground\">Choose the column above first.</p>\n ) : stillAsking ? (\n <p className=\"text-[11px] text-muted-foreground\">Reading that table's columns…</p>\n ) : offered.length === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">\n No columns to read yet.\n </p>\n ) : (\n <Select value={value} onValueChange={onChange}>\n <SelectTrigger size=\"sm\" aria-label={label}>\n <SelectValue placeholder=\"Choose a column\" />\n </SelectTrigger>\n <SelectContent>\n {offered.map((column) => (\n <SelectItem key={column.key} value={column.key}>\n {column.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n\n if (compact) return <div className=\"mt-1 flex flex-col gap-1\">{body}</div>;\n return (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\" title={help}>{label}</Label>\n {body}\n </div>\n );\n}\n\n/** A rule with one number set, or taken off when the box is blank (STORE-RULE-GAPS). */\nfunction withNumber(rule: FieldRule, key: \"min\", typed: string): FieldRule {\n const { [key]: _gone, ...rest } = rule;\n const trimmed = typed.trim();\n if (trimmed === \"\") return rest;\n const n = Number(trimmed);\n return Number.isFinite(n) ? { ...rest, [key]: n } : { ...rest, [key]: trimmed as unknown as number };\n}\n\n/** A rule with one word set, or taken off when the box is blank (STORE-RULE-GAPS). */\nfunction withText(rule: FieldRule, key: \"example\", typed: string): FieldRule {\n const { [key]: _gone, ...rest } = rule;\n return typed.trim() === \"\" ? rest : { ...rest, [key]: typed };\n}\n\n/** The kinds an existing entity-reference column already points at (`config.allowed_types`). */\nfunction entityReferenceKindsOf(field: Field | null | undefined): string[] {\n const raw = (field?.config ?? {})[\"allowed_types\"];\n return Array.isArray(raw) ? raw.filter((t): t is string => typeof t === \"string\") : [];\n}\n","\"use client\";\n\n// src/ReferenceBuilder.tsx — @ai-matrx/records-ui · REL-DISP\n//\n// THE ONE PLACE A REFERENCE TO ANOTHER TABLE IS BUILT.\n//\n// The owner's ruling, 2026-09-21: *a column that offers choices from ANOTHER\n// table is a relation; the stored value is always the id; what is DISPLAYED is\n// resolved by one primitive.* This is the UI half — one component, so the\n// question \"which table, and which of its columns do I read?\" is asked once and\n// answered the same way wherever it is asked: declaring a column in the field\n// editor, changing one from the grid's column settings, referencing a relation\n// in a condition, a form, or a portal.\n//\n// WHAT IT ASKS, IN THE ORDER A PERSON THINKS OF IT\n// 1. which table its records come from;\n// 2. what a record of that table is called TODAY — its own reference column,\n// shown rather than hidden, because the honest default is a fact the person\n// should see before they decide to override it;\n// 3. only if they want it, WHICH columns to show instead, in order, and what\n// goes between them — the \"first name\" + \" \" + \"last name\" the store could\n// not express at all before REL-DISP;\n// 4. a preview built from that table's REAL first rows, so the answer is read\n// rather than imagined.\n//\n// WHY THIS EXISTS RATHER THAN A FOURTH COPY. Before this component, three\n// separate implementations of \"read tableList, find title_field, call rowName\"\n// lived in labels.tsx, RelationPicker.tsx and PortalsPanel.tsx, and the only\n// target-table picker was `TableToPointAt`, private inside FieldEditor.tsx. Four\n// places to fix, four places to forget, and not one of them could ever have\n// shown two columns joined.\n//\n// THE STORE IS THE AUTHORITY AND THIS IS A PREVIEW. `previewWords` below mirrors\n// the display arm of `custom._words_for` so the panel can show an answer for a\n// column that does not exist yet — a declaration has no field id to ask about.\n// It is deliberately NOT the resolver: once a column exists, its words come from\n// `client.relationWords` / `client.relationWordsMany`, which ask the read-access\n// ladder before they read a name. Nothing renders a real cell from this function.\n\nimport { useMemo, useState } from \"react\";\nimport type { Field, RecordsError, RelationDisplay, Uuid } from \"@ai-matrx/records\";\nimport { useFields, useRecords, useRecordsClient } from \"@ai-matrx/records/react\";\nimport { DOORS, doorReady } from \"@ai-matrx/records/core\";\nimport { ensureTable, tokenFor, type NewFieldSpec } from \"./createTable\";\nimport { RefusalNotice } from \"./Refusal\";\nimport { ShowListsToggle, tablePickerEntries, usePickerTables } from \"./tablePicking\";\nimport {\n Button,\n Checkbox,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n BasicInput,\n cn,\n} from \"@ai-matrx/design-system\";\nimport { looksLikeId, tableName } from \"./names\";\n\n/** What a person has chosen: the table, and optionally which of its columns to show. */\nexport interface ReferenceChoice {\n /** The Table whose records this column offers. `\"\"` until one is picked. */\n targetTableId: Uuid | \"\";\n /** Which of that Table's columns to show. `null` = the Table's own reference column. */\n display: RelationDisplay | null;\n}\n\nexport interface ReferenceBuilderProps {\n /** The Table the column being built lives on, so \"this table\" can be marked. */\n tableId: Uuid;\n value: ReferenceChoice;\n onChange: (next: ReferenceChoice) => void;\n /**\n * A Person or File column points at a kernel Table the person does not choose.\n * The target picker is then not shown — but which columns to display still is,\n * because that half is theirs either way.\n */\n lockTarget?: boolean | undefined;\n className?: string | undefined;\n}\n\nconst DEFAULT_SEPARATOR = \" \";\n\n/** The Select's own value for \"New table…\" — never a table id, so it can never be saved as one. */\nconst NEW_TABLE = \"__records_ui_new_table__\";\n\n/**\n * THE PRIMARY COLUMN A TABLE MADE FROM THE LINK PICKER IS BORN WITH (T4.3, lane 10 sublane LT).\n * Airtable's new table opens with \"Name\" as its primary field; a table a person makes in order to\n * point at it (\"Referring Physicians\") is a list of named things, so its records are titled by a\n * Name and the link's chips read as those names from the first record on.\n */\nconst LINK_TARGET_FIELDS: NewFieldSpec[] = [\n { key: \"name\", label: \"Name\", type: \"text\", sort: 10, required: false },\n];\n\n/**\n * The client mirror of `custom._words_for`'s display arm, for the PREVIEW only.\n * Same order, same blank-dropping, same refusal to print an id — a preview that\n * disagreed with the store about what a chip says would be worse than none.\n */\nexport function previewWords(\n document: Record<string, unknown> | undefined,\n display: RelationDisplay | null,\n titleField: string | null,\n): string {\n const data = document ?? {};\n const read = (key: string): string => {\n const raw = data[key];\n if (typeof raw === \"number\") return String(raw);\n if (typeof raw !== \"string\") return \"\";\n const trimmed = raw.trim();\n // An id is never a name. The store resolves one hop here; a preview cannot\n // (it holds only this table's rows) and says so rather than printing a uuid.\n if (looksLikeId(trimmed)) return \"…\";\n return trimmed;\n };\n\n if (display && display.columns.length > 0) {\n const parts = display.columns.map(read).filter((part) => part !== \"\");\n if (parts.length > 0) return parts.join(display.separator ?? DEFAULT_SEPARATOR);\n // Falls through exactly as the store does: the named columns hold nothing on\n // THIS record, so the table's own answer is shown rather than an empty chip.\n }\n for (const key of [titleField, \"title\", \"name\", \"label\", \"full_name\", \"company\", \"subject\"]) {\n if (!key) continue;\n const value = read(key);\n if (value !== \"\" && value !== \"…\") return value;\n }\n // The store's last resort, mirrored: the first words the record holds in key\n // order, skipping its own machinery and anything uuid-shaped.\n for (const key of Object.keys(data).sort()) {\n if (key.startsWith(\"_\") || key === \"id\" || key === \"table_id\") continue;\n const value = read(key);\n if (value !== \"\" && value !== \"…\") return value;\n }\n return \"an untitled record\";\n}\n\n/**\n * THE COLUMNS OF THE TABLE ON THE OTHER SIDE.\n *\n * A Table the STORE keeps itself still has columns: `custom.applicable_fields`\n * answers what a table DECLARES, and the kernels declare none — a Person column\n * points at the person kernel, which has records and zero Field rows. So when\n * the target declares nothing, one of its records is read through the ordinary\n * door and the keys it actually carries are offered. Same fact, asked the way\n * the store will ask it.\n */\nfunction useTargetColumns(target: Uuid | null): { keys: string[]; loading: boolean } {\n const declared = useFields(target);\n const usable = (declared.data ?? []).filter((f: Field) => f.type !== \"formula\");\n const needSample = usable.length === 0 && !declared.loading && target !== null;\n const sample = useRecords(needSample ? target : null, { pageSize: 1 });\n return useMemo(() => {\n if (usable.length > 0) return { keys: usable.map((f) => f.key), loading: false };\n const carried = sample.data?.rows[0]?.document ?? null;\n if (!carried) return { keys: [], loading: declared.loading || sample.loading };\n return {\n keys: Object.keys(carried).filter((k) => !k.startsWith(\"_\")),\n loading: false,\n };\n }, [usable, sample.data, declared.loading, sample.loading]);\n}\n\nexport function ReferenceBuilder({\n tableId,\n value,\n onChange,\n lockTarget,\n className,\n}: ReferenceBuilderProps) {\n const tables = usePickerTables();\n const client = useRecordsClient();\n // \"NEW TABLE…\" (T4.3). `null` = the name box is closed; a string = what she has typed so far.\n const [naming, setNaming] = useState<string | null>(null);\n const [making, setMaking] = useState(false);\n const [refused, setRefused] = useState<RecordsError | null>(null);\n // The table just made, offered at once — before the re-read of the organization's tables lands.\n const [born, setBorn] = useState<{ id: Uuid; name: string } | null>(null);\n const target = (value.targetTableId || null) as Uuid | null;\n const columns = useTargetColumns(target);\n const preview = useRecords(target, { pageSize: 3 });\n\n const targetTable = (tables.data ?? []).find((t) => t.id === target) ?? null;\n const titleField = targetTable?.title_field ?? null;\n\n // \"Show more than one column\" is OPEN when a spec already exists — a person\n // editing a column that joins two names should see that, not a closed tick.\n const [overriding, setOverriding] = useState(value.display !== null);\n\n // TABLES ONLY, unless \"Show lists\" — the choice lists every choice column keeps were 64 entries\n // here, \"Status choices\" five times (`tablePicking.ts`, the one rule every table picker uses).\n const [showLists, setShowLists] = useState(false);\n const picking = useMemo(\n () =>\n tablePickerEntries(\n [\n ...(tables.data ?? []).map((t) => ({ ...t, name: tableName(t) })),\n ...(born && !(tables.data ?? []).some((t) => t.id === born.id) ? [born] : []),\n ],\n { showLists, keep: value.targetTableId || null },\n ),\n [tables.data, showLists, value.targetTableId, born],\n );\n const offered = picking.entries;\n\n /**\n * MAKE THE TABLE, LINK THE COLUMN TO IT, STAY HERE. Through the store's own doors, in the active\n * organization (the client's — where every write goes):\n * · `tableFind` by the slug the name makes — a table of that address she can see is the one she\n * means, and it is picked as it stands (`ensureTable` would otherwise ADD a Name column to it);\n * · otherwise `ensureTable` (`custom.table_ensure`, one transaction) makes it with a Name column.\n * A refusal keeps the name box open with what she typed, and says the store's own sentence.\n */\n const makeTable = async () => {\n const name = (naming ?? \"\").trim();\n if (!name || making) return;\n setMaking(true);\n setRefused(null);\n const slug = tokenFor(name);\n const found = await client.tableFind({ slug });\n if (!found.ok) {\n setMaking(false);\n setRefused(found.error);\n return;\n }\n const existing =\n found.data && !(found.data as { kept_for?: string | null }).kept_for ? found.data : null;\n let id: Uuid;\n let bornName = name;\n if (existing) {\n id = existing.id as Uuid;\n bornName = tableName(existing);\n } else {\n const made = await ensureTable(client, {\n name,\n slug,\n titleField: \"name\",\n fields: LINK_TARGET_FIELDS,\n });\n if (!made.ok) {\n setMaking(false);\n setRefused(made.error);\n return;\n }\n id = made.data;\n }\n setMaking(false);\n setNaming(null);\n setBorn({ id, name: bornName });\n tables.reload();\n onChange({ targetTableId: id, display: null });\n };\n\n /** \"New table…\" is offered only where the store has the two doors it calls (absent before the chair's apply). */\n const mayMakeTable = doorReady(client.config, DOORS.tableFind) && doorReady(client.config, DOORS.tableEnsure);\n const newTableButton = !mayMakeTable ? null : (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n className=\"self-start\"\n onClick={() => {\n setRefused(null);\n setNaming(\"\");\n }}\n >\n New table…\n </Button>\n );\n\n const display = value.display;\n const chosen = display?.columns ?? [];\n const separator = display?.separator ?? DEFAULT_SEPARATOR;\n\n const setDisplay = (next: RelationDisplay | null) => onChange({ ...value, display: next });\n\n const toggleColumn = (key: string) => {\n const next = chosen.includes(key) ? chosen.filter((k) => k !== key) : [...chosen, key];\n setDisplay(next.length === 0 ? null : { columns: next, separator });\n };\n\n const move = (key: string, by: -1 | 1) => {\n const at = chosen.indexOf(key);\n const to = at + by;\n if (at < 0 || to < 0 || to >= chosen.length) return;\n const next = chosen.slice();\n next.splice(to, 0, next.splice(at, 1)[0]!);\n setDisplay({ columns: next, separator });\n };\n\n return (\n <div className={cn(\"flex max-w-[26rem] flex-col gap-3\", className)}>\n {/* ── 1. WHICH TABLE ─────────────────────────────────────────────── */}\n {!lockTarget && (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label className=\"text-xs\">The table it points at</Label>\n <ShowListsToggle count={picking.listCount} on={showLists} onChange={setShowLists} />\n </div>\n {naming !== null ? (\n <div className=\"flex flex-col gap-1\" data-new-link-table=\"\">\n <div className=\"flex items-center gap-1\">\n <BasicInput\n autoFocus\n value={naming}\n placeholder=\"Table name\"\n aria-label=\"New table name\"\n disabled={making}\n onChange={(e) => setNaming(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n void makeTable();\n }\n if (e.key === \"Escape\") {\n e.stopPropagation();\n setNaming(null);\n setRefused(null);\n }\n }}\n className=\"h-7 text-xs\"\n />\n <Button\n type=\"button\"\n size=\"sm\"\n disabled={making || naming.trim() === \"\"}\n onClick={() => void makeTable()}\n >\n {making ? \"Creating…\" : \"Create\"}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={making}\n onClick={() => {\n setNaming(null);\n setRefused(null);\n }}\n >\n Cancel\n </Button>\n </div>\n {refused ? <RefusalNotice error={refused} /> : null}\n </div>\n ) : tables.loading && offered.length === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">Reading your tables…</p>\n ) : offered.length === 0 ? (\n <div className=\"flex items-center gap-2\">\n <p className=\"text-[11px] text-muted-foreground\">No tables yet.</p>\n {newTableButton}\n </div>\n ) : (\n <Select\n value={value.targetTableId}\n onValueChange={(next) => {\n if (next === NEW_TABLE) {\n setRefused(null);\n setNaming(\"\");\n return;\n }\n // Changing the table invalidates the columns: the store refuses a\n // spec naming a column the new target does not have, and a panel\n // that carried the old one would walk a person into that refusal.\n onChange({ targetTableId: next as Uuid, display: null });\n }}\n >\n <SelectTrigger size=\"sm\" aria-label=\"The table this column points at\">\n <SelectValue placeholder=\"Choose a table\" />\n </SelectTrigger>\n <SelectContent>\n {offered.map((t) => (\n <SelectItem key={t.id} value={t.id}>\n {t.label}\n {t.id === tableId ? \" — this table\" : \"\"}\n </SelectItem>\n ))}\n {mayMakeTable ? <SelectItem value={NEW_TABLE}>New table…</SelectItem> : null}\n </SelectContent>\n </Select>\n )}\n </div>\n )}\n\n {/* ── 2. WHAT ONE OF ITS RECORDS IS CALLED TODAY ──────────────────── */}\n {target && (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-xs\">Shown as</Label>\n <span className=\"text-[11px] text-muted-foreground\">\n {titleField\n ? `${titleField} — what ${targetTable ? tableName(targetTable) : \"that table\"} is titled by`\n : \"whatever each record is named by\"}\n </span>\n </div>\n\n <label className=\"flex items-center gap-2 text-[11px] text-muted-foreground\">\n <Checkbox\n checked={overriding}\n onCheckedChange={(next) => {\n const on = next === true;\n setOverriding(on);\n if (!on) setDisplay(null);\n }}\n aria-label=\"Show more than one column\"\n />\n Show different columns, or more than one\n </label>\n </div>\n )}\n\n {/* ── 3. WHICH COLUMNS, IN ORDER, AND WHAT JOINS THEM ─────────────── */}\n {target && overriding && (\n <div className=\"flex flex-col gap-2 rounded-md border border-border p-2\">\n {columns.loading ? (\n <p className=\"text-[11px] text-muted-foreground\">Reading that table's columns…</p>\n ) : columns.keys.length === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">\n That table has no columns to show yet. Give it one, then come back — until then this\n column shows whatever each record is named by.\n </p>\n ) : (\n <>\n <div className=\"flex flex-wrap gap-1\">\n {columns.keys.map((key) => {\n const on = chosen.includes(key);\n return (\n <Button\n key={key}\n type=\"button\"\n size=\"sm\"\n variant={on ? \"default\" : \"outline\"}\n onClick={() => toggleColumn(key)}\n aria-pressed={on}\n >\n {key}\n {on && chosen.length > 1 ? ` ${chosen.indexOf(key) + 1}` : \"\"}\n </Button>\n );\n })}\n </div>\n\n {chosen.length > 1 && (\n <div className=\"flex flex-wrap items-center gap-1\">\n <span className=\"text-[11px] text-muted-foreground\">Order</span>\n {chosen.map((key, at) => (\n <span key={key} className=\"flex items-center gap-0.5\">\n <span className=\"text-[11px]\">{key}</span>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={at === 0}\n onClick={() => move(key, -1)}\n aria-label={`Move ${key} earlier`}\n >\n ←\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n disabled={at === chosen.length - 1}\n onClick={() => move(key, 1)}\n aria-label={`Move ${key} later`}\n >\n →\n </Button>\n </span>\n ))}\n </div>\n )}\n\n {chosen.length > 1 && (\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-xs whitespace-nowrap\">Joined by</Label>\n <BasicInput\n value={separator}\n onChange={(e) => setDisplay({ columns: chosen, separator: e.target.value })}\n aria-label=\"What goes between the columns\"\n className=\"h-7 w-28 text-xs\"\n />\n <span className=\"text-[11px] text-muted-foreground\">a space by default</span>\n </div>\n )}\n </>\n )}\n </div>\n )}\n\n {/* ── 4. READ IT, RATHER THAN IMAGINE IT ──────────────────────────── */}\n {target && (\n <div className=\"flex flex-col gap-0.5\">\n <Label className=\"text-xs\">It will read</Label>\n {preview.loading ? (\n <p className=\"text-[11px] text-muted-foreground\">Reading a few of its records…</p>\n ) : (preview.data?.rows?.length ?? 0) === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">\n That table has no records yet, so there is nothing to show here — this column will\n still work, and the first record added is the first thing it offers.\n </p>\n ) : (\n <ul className=\"flex flex-col gap-0.5\">\n {(preview.data?.rows ?? []).map((row) => (\n <li key={row.id} className=\"truncate text-[11px] text-foreground\">\n {previewWords(\n row.document as Record<string, unknown> | undefined,\n display,\n titleField,\n )}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n );\n}\n","// src/createTable.ts — @ai-matrx/records-ui\n//\n// The one birth of a person-made Table now lives in @ai-matrx/records/core (headless, so the\n// extension and server-side births use it too — lane GRID-PRIMITIVES, 2026-09-24). This module\n// keeps records-ui's own import path and names.\n\nexport {\n declareTable,\n ensureTable,\n addFields,\n fieldDeclarationFor,\n tokenFor,\n DEFAULT_FIELDS,\n} from \"@ai-matrx/records/core\";\nexport type { NewTableSpec, NewFieldSpec, DeclareResult, EnsureResult } from \"@ai-matrx/records/core\";\n","\"use client\";\n\n// src/tablePicking.tsx — @ai-matrx/records-ui · lane 10 VIEWS-AND-FIELDS W1-A\n//\n// WHICH TABLES A \"CHOOSE A TABLE\" CONTROL OFFERS — ONE RULE FOR EVERY PICKER.\n//\n// Every choice column makes a backing List (`kept_for = 'choices'`, named \"<column> choices\").\n// The link-target picker listed all of them beside the organization's tables: 64 entries on a\n// clinic's account, \"Status choices\" five times, no way to tell them apart. Four other pickers had\n// each grown their own inline filter for the same question (`!platform_owned` here, a lane check\n// there, `work_kind` somewhere else), and the one that had none flooded.\n//\n// THE RULE:\n// · by default a picker offers TABLES — never a value set or anything else the app keeps for\n// itself (the choice lists, checklist steps, booking slots, the app's own bookkeeping);\n// · \"Show lists\" adds the value sets, each named by its column and its owning table\n// (\"Status — Patient Visits\"), so no two visible entries share a name;\n// · the table already chosen is always offered, whatever it is, so a saved choice never vanishes.\n//\n// Which table is a value set, and which table owns it, are the store's facts\n// (`custom.table_facts`: `kept_for`, `used_in_table_id`; `custom.data_home_tables`: `kind`).\n// Nothing here guesses from a name except trimming the store's own \" choices\" suffix for the label.\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { withTablePlacement, type Table, type TablePlacementFact } from \"@ai-matrx/records\";\nimport { useRecordsClient, useTables } from \"@ai-matrx/records/react\";\nimport { Checkbox, cn } from \"@ai-matrx/design-system\";\n\n/** The facts a picker needs about one table, whichever list it came from. */\nexport interface PickerTable {\n id: string;\n name: string;\n platform_owned?: boolean | null | undefined;\n /** The Table document's own key for the same fact (`tableList()` spreads the document onto the Table). */\n kept_by_the_app?: boolean | null | undefined;\n /** `custom.table_facts`: which feature keeps it (`choices` for a value set). */\n kept_for?: string | null | undefined;\n /** `custom.data_home_tables`: the store's one word for what it is (`list` for a value set). */\n kind?: string | null | undefined;\n /** The table a value set belongs to (`custom.table_facts.used_in_table_id`). */\n used_in_table_id?: string | null | undefined;\n /** A checklist's steps, a booking page's slots, a workflow's states. */\n work_kind?: unknown;\n slug?: string | null | undefined;\n /** When the table was made — what tells two lists apart once their column is gone. */\n created_at?: string | null | undefined;\n}\n\n/** The slug prefix of the tables this package keeps for its own bookkeeping (saved views, forms …). */\nconst PLATFORM_TABLE_PREFIX = \"records_ui_\";\n\n/** The store's flag (`platform_owned`) or the Table document's own key (`kept_by_the_app`) — either says the app keeps it. */\nfunction keptByPlatform(table: PickerTable): boolean {\n return table.platform_owned === true || table.kept_by_the_app === true;\n}\n\n/** A value set: the List a choice column keeps its choices in. */\nexport function isValueSet(table: PickerTable): boolean {\n if (table.kept_for === \"choices\") return true;\n return table.kept_for == null && table.kind === \"list\" && keptByPlatform(table);\n}\n\n/** Anything the app keeps for itself rather than a table a person keeps. */\nexport function isKeptTable(table: PickerTable): boolean {\n return (\n keptByPlatform(table) ||\n isValueSet(table) ||\n Boolean(table.work_kind) ||\n (table.slug ?? \"\").startsWith(PLATFORM_TABLE_PREFIX)\n );\n}\n\nexport interface TablePickerEntry<T extends PickerTable> {\n table: T;\n id: string;\n /** Unique among the entries returned. */\n label: string;\n /** A value set (shown only with \"Show lists\", or because it is the chosen one). */\n isList: boolean;\n}\n\nexport interface TablePickerEntries<T extends PickerTable> {\n entries: TablePickerEntry<T>[];\n /** How many value sets \"Show lists\" would add — 0 means the control is not worth drawing. */\n listCount: number;\n}\n\nconst CHOICES_SUFFIX = / choices$/i;\n\n/**\n * THE ONE RULE. Tables first (by name), then — with `showLists` — the value sets, each named\n * \"<column> — <owning table>\". Any names still equal get \" (2)\", \" (3)\" so no two entries match.\n */\nexport function tablePickerEntries<T extends PickerTable>(\n tables: readonly T[],\n options: { showLists?: boolean; keep?: string | null | undefined } = {},\n): TablePickerEntries<T> {\n const byId = new Map(tables.map((t) => [t.id, t]));\n const lists = tables.filter(isValueSet);\n const listLabel = (t: T): string => {\n const column = t.name.replace(CHOICES_SUFFIX, \"\");\n // A LIST WHOSE COLUMN IS GONE: `custom.table_facts` names the list itself (or nothing) as where\n // it is used. Said so, and told apart by the day it was made — never by a counter.\n if (!t.used_in_table_id || t.used_in_table_id === t.id) {\n const made = madeOn(t.created_at);\n return made ? `${column} — no column · ${made}` : `${column} — no column`;\n }\n const owner = byId.get(t.used_in_table_id);\n // Owned by a table this person cannot see: its own name, as the store gave it.\n if (!owner) return t.name;\n return `${column} — ${owner.name}`;\n };\n const plain = tables\n .filter((t) => !isKeptTable(t) || (t.id === options.keep && !isValueSet(t)))\n .map((t) => ({ table: t, id: t.id, label: t.name, isList: false }))\n .sort((a, b) => a.label.localeCompare(b.label));\n const shownLists = lists\n .filter((t) => options.showLists || t.id === options.keep)\n .map((t) => ({ table: t, id: t.id, label: listLabel(t), isList: true }))\n .sort((a, b) => a.label.localeCompare(b.label));\n const entries = [...plain, ...shownLists];\n const seen = new Map<string, number>();\n for (const entry of entries) {\n const key = entry.label.toLowerCase();\n const n = (seen.get(key) ?? 0) + 1;\n seen.set(key, n);\n if (n > 1) entry.label = `${entry.label} (${n})`;\n }\n return { entries, listCount: lists.length };\n}\n\n/** \"Sep 3, 2026\" in the reader's own locale, or null when the store gave no date. */\nfunction madeOn(stamp: string | null | undefined): string | null {\n if (!stamp) return null;\n const at = new Date(stamp);\n if (Number.isNaN(at.getTime())) return null;\n return new Intl.DateTimeFormat(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" }).format(at);\n}\n\n/**\n * The organization's tables with the store's placement facts folded on (`kept_for`,\n * `used_in_table_id`), for a picker that reads `tableList()`. A store with no facts door, or one\n * that did not answer, leaves each table as `tableList()` gave it — its own `platform_owned`.\n */\nexport function usePickerTables(): { loading: boolean; data: Array<Table & PickerTable>; reload: () => void } {\n const client = useRecordsClient();\n const tables = useTables();\n const [facts, setFacts] = useState<TablePlacementFact[] | null | \"reading\">(\"reading\");\n // A table made FROM a picker (\"New table…\" in the link-target picker) is read again, list and\n // facts both, so the picker offers what it just made.\n const [nonce, setNonce] = useState(0);\n const reloadTables = tables.reload;\n const reload = useCallback(() => {\n reloadTables();\n setNonce((n) => n + 1);\n }, [reloadTables]);\n useEffect(() => {\n let alive = true;\n void client.tableFacts().then((answered) => {\n if (alive) setFacts(answered.ok ? ((answered.data as unknown as TablePlacementFact[] | null) ?? null) : null);\n });\n return () => {\n alive = false;\n };\n }, [client, nonce]);\n const data = useMemo(\n () => withTablePlacement(tables.data ?? [], facts === \"reading\" ? null : facts) as Array<Table & PickerTable>,\n [tables.data, facts],\n );\n return { loading: tables.loading || facts === \"reading\", data, reload };\n}\n\n/** The \"Show lists\" control beside a table picker. Drawn only when there are lists to show. */\nexport function ShowListsToggle({\n count,\n on,\n onChange,\n className,\n}: {\n count: number;\n on: boolean;\n onChange: (on: boolean) => void;\n className?: string | undefined;\n}) {\n if (count === 0) return null;\n return (\n <label className={cn(\"flex items-center gap-1.5 text-[11px] text-muted-foreground\", className)}>\n <Checkbox checked={on} onCheckedChange={(next) => onChange(next === true)} aria-label=\"Show lists\" />\n Show lists ({count})\n </label>\n );\n}\n","\"use client\";\n\n// src/FormulaTextEditor.tsx — @ai-matrx/records-ui · lane DEFAULT-GRID-PARITY (TABLE-PARITY K2)\n//\n// A FORMULA, WRITTEN THE WAY A PERSON WRITES ONE, AND CHECKED BY THE STORE AS THEY TYPE.\n//\n// The field panel could only build a worked-out column from a fixed list of operations over\n// picked columns. The store has spoken the older grid's whole formula language since\n// GRID-PRIMITIVES G3 (`custom.formula_parse`, 530 of 530 answers equal to the older\n// evaluator) — `{Visit fee} - {Deposit taken}`, `IF({Status} = \"No-show\", 0, {Fee})` — and\n// nothing on this panel could say it.\n//\n// THE STORE IS THE CHECKER. Every pause in typing asks `formula_parse`, which answers either\n// the columns it reads and the kind of answer it gives, or the mistake and where it is. This\n// screen never parses a formula itself: a second parser here would be a second answer to\n// \"is this formula right\", and the two would drift within a month. Airtable's formula field is\n// the reference — the reference check and the function list are right under the box.\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { useRecordsClient, type Field, type Uuid } from \"@ai-matrx/records/react\";\nimport type { FormulaPreview } from \"@ai-matrx/records\";\nimport { FORMULA_FUNCTIONS as KIT_FORMULA_FUNCTIONS } from \"@ai-matrx/kit/formula\";\nimport { BasicTextarea, Button, Label, cn } from \"@ai-matrx/design-system\";\n\nimport type { RecordsError } from \"@ai-matrx/records\";\n\nimport { useRecordsUi } from \"./host\";\nimport { RefusalLine } from \"./Refusal\";\nimport { refusalSentence } from \"./plainWords\";\nimport { fieldName } from \"./names\";\n\n/**\n * The `fx.*` nodes a person never types by name — the same list `custom._fxp_level` refuses as a\n * function name: the operators (`fx.ne` is `!=`, `fx.mod` is `%`) and the three system kinds\n * (an autonumber, created or modified column is a column kind, not a function).\n */\nconst NOT_TYPED_BY_NAME = new Set([\n \"fx.add\", \"fx.sub\", \"fx.mul\", \"fx.div\", \"fx.mod\", \"fx.neg\",\n \"fx.eq\", \"fx.ne\", \"fx.lt\", \"fx.lte\", \"fx.gt\", \"fx.gte\",\n \"fx.autonumber\", \"fx.created_time\", \"fx.modified_time\",\n]);\n\n/** The functions a vocabulary offers, as a person types them (`fx.regex_match` → REGEX_MATCH). */\nexport function formulaFunctionNames(kinds: readonly { node: string }[]): string[] {\n return [...new Set(kinds.map((row) => row.node))]\n .filter((node) => node.startsWith(\"fx.\") && !NOT_TYPED_BY_NAME.has(node))\n .map((node) => node.slice(3).toUpperCase())\n .sort();\n}\n\n/**\n * The functions the store's evaluator answers: kit's one formula language (architecture D6). Its list\n * is pinned to the store's generated vocabulary by `a-formula-lists-only-functions-a-person-can-type`.\n */\nconst FUNCTION_NAMES: string[] = KIT_FORMULA_FUNCTIONS.map((fn) => fn.name).sort();\n\nconst RESULT_WORD: Record<string, string> = {\n number: \"a number\",\n text: \"text\",\n boolean: \"a yes or no\",\n date: \"a date\",\n unknown: \"an answer whose kind depends on the row\",\n};\n\n/** The sampled answer as one line: the value, \"empty\", or why it could not be worked out. */\nexport function sampleWords(preview: FormulaPreview): string {\n if (preview.ok && preview.error) return preview.error;\n const v = preview.value;\n if (v === null || v === undefined || v === \"\") return \"empty\";\n if (typeof v === \"boolean\") return v ? \"Yes\" : \"No\";\n if (typeof v === \"number\" || typeof v === \"string\") return String(v);\n return JSON.stringify(v);\n}\n\nexport function FormulaTextEditor({\n tableId,\n text,\n onText,\n onChecked,\n columns,\n sampleRecordId,\n className,\n}: {\n tableId: Uuid;\n text: string;\n onText: (next: string) => void;\n /** The store's verdict on the text as it stands: true, false, or null while it is asked. */\n onChecked: (ok: boolean | null) => void;\n /** The other columns of this table, offered to insert by name. */\n columns: readonly Field[];\n /**\n * NOTION-PROPS — THE LIVE SAMPLE: the record whose answer is shown as the formula is typed. Left\n * out, the table's first row is sampled; `null` samples nothing.\n */\n sampleRecordId?: Uuid | null | undefined;\n className?: string | undefined;\n}) {\n const client = useRecordsClient();\n const host = useRecordsUi();\n const [parsed, setParsed] = useState<FormulaPreview | null>(null);\n // The row sampled when the host names none: the table's first, read once.\n const [firstRow, setFirstRow] = useState<Uuid | null>(null);\n useEffect(() => {\n if (sampleRecordId !== undefined) return;\n let live = true;\n void client.list({ table_id: tableId, limit: 1 }).then((read) => {\n if (live && read.ok) setFirstRow((read.data.rows[0]?.id as Uuid | undefined) ?? null);\n });\n return () => {\n live = false;\n };\n }, [client, tableId, sampleRecordId]);\n const sampled = sampleRecordId !== undefined ? sampleRecordId : firstRow;\n const [error, setError] = useState<RecordsError | null>(null);\n const box = useRef<HTMLTextAreaElement | null>(null);\n // The parent's setter, held so the question (the text, the table) alone drives the ask.\n const report = useRef(onChecked);\n report.current = onChecked;\n\n useEffect(() => {\n const asked = text.trim();\n if (asked === \"\") {\n setParsed(null);\n setError(null);\n report.current(null);\n return;\n }\n report.current(null);\n let cancelled = false;\n const timer = setTimeout(() => {\n // One call parses AND works the answer out on the sampled row. The sample is extra: when that\n // door cannot answer (absent, or the row is not this reader's), the parse is asked on its own.\n void client\n .formulaPreview({ table_id: tableId, record_id: sampled, text: asked })\n .then((previewed) => (previewed.ok ? previewed : client.formulaParse({ table_id: tableId, text: asked })))\n .then((answered) => {\n if (cancelled) return;\n if (!answered.ok) {\n setError(answered.error);\n setParsed(null);\n report.current(false);\n return;\n }\n setError(null);\n setParsed(answered.data);\n report.current(answered.data.ok);\n });\n }, 300);\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [client, tableId, text, sampled]);\n\n const insert = (piece: string) => {\n const el = box.current;\n const at = el?.selectionStart ?? text.length;\n const to = el?.selectionEnd ?? at;\n onText(`${text.slice(0, at)}${piece}${text.slice(to)}`);\n requestAnimationFrame(() => {\n el?.focus();\n const caret = at + piece.length - (piece.endsWith(\"()\") ? 1 : 0);\n el?.setSelectionRange(caret, caret);\n });\n };\n\n const where = useMemo(() => {\n if (!parsed || parsed.ok) return null;\n const at = Math.max(0, Math.min(parsed.position ?? 0, parsed.text.length));\n return { before: parsed.text.slice(0, at), after: parsed.text.slice(at) };\n }, [parsed]);\n\n return (\n <div data-records-formula-editor=\"\" className={cn(\"flex flex-col gap-1.5\", className)}>\n <div className=\"flex items-center gap-1\">\n <Label className=\"text-xs\">The formula</Label>\n {host.formulaHelp ? (\n <span data-records-formula-help=\"\" className=\"ml-auto\">\n {host.formulaHelp({\n tableId,\n text,\n columns,\n mistake: parsed && !parsed.ok ? parsed.error : error ? refusalSentence(error) : null,\n functions: FUNCTION_NAMES,\n onFormula: onText,\n })}\n </span>\n ) : null}\n </div>\n <BasicTextarea\n ref={box}\n value={text}\n rows={2}\n aria-label=\"The formula\"\n placeholder=\"{Visit fee} - {Deposit taken}\"\n className=\"font-mono text-xs\"\n onChange={(e) => onText(e.target.value)}\n />\n {parsed?.ok ? (\n <p data-records-formula-ok=\"\" className=\"text-[11px] text-muted-foreground\">\n Reads {parsed.references.length === 0 ? \"no column\" : parsed.references.map((r) => r.name).join(\", \")} ·\n gives {RESULT_WORD[parsed.result_type] ?? \"an answer\"}.\n </p>\n ) : null}\n {parsed?.ok && parsed.record_id ? (\n <p data-records-formula-sample=\"\" className=\"truncate text-[11px]\" title={sampleWords(parsed)}>\n <span className=\"text-muted-foreground\">{sampleRecordId ? \"This record\" : \"First row\"}: </span>\n <span className={cn(\"font-mono\", parsed.error ? \"text-muted-foreground\" : \"text-foreground\")}>{sampleWords(parsed)}</span>\n </p>\n ) : null}\n {parsed && !parsed.ok ? (\n // NOT A REFUSAL, SO NOT RED: nothing was pressed. It is the store's reading of the\n // text as it stands, drawn the way the panel draws what Save is still waiting for.\n <div data-records-formula-mistake=\"\" role=\"status\" className=\"text-[11px] text-foreground\">\n <p>{parsed.error}</p>\n {where ? (\n <p className=\"mt-0.5 font-mono text-foreground\">\n {where.before}\n <span className=\"bg-amber-500/30 px-0.5\">▏</span>\n {where.after}\n </p>\n ) : null}\n </div>\n ) : null}\n {error ? <RefusalLine error={error} /> : null}\n <div className=\"flex flex-wrap items-center gap-1\">\n <span className=\"text-[11px] text-muted-foreground\">Columns:</span>\n {columns.map((f) => (\n <Button key={f.id} type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-6 px-1.5 text-[11px]\" onClick={() => insert(`{${fieldName(f)}}`)}>\n {fieldName(f)}\n </Button>\n ))}\n </div>\n {FUNCTION_NAMES.length > 0 ? (\n <details className=\"text-[11px] text-muted-foreground\">\n <summary className=\"cursor-pointer\">Functions the store works out ({FUNCTION_NAMES.length})</summary>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {FUNCTION_NAMES.map((name) => (\n <Button key={name} type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-1.5 font-mono text-[11px]\" onClick={() => insert(`${name}()`)}>\n {name}\n </Button>\n ))}\n </div>\n </details>\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/host.tsx — @ai-matrx/records-ui\n//\n// THE ONE BINDING POINT. A host mounts `<RecordsUiProvider>` once, inside\n// `<RecordsProvider>` from @ai-matrx/records, and every component in this\n// package reads what it needs from here. There is no module-level state: two\n// organizations in two tabs must never share one.\n//\n// WHAT A HOST BINDS, AND WHAT HAPPENS WHEN IT DOES NOT\n// ----------------------------------------------------\n// `rights` USED TO BE the only answer to \"may this person administer this\n// table?\" — a PORT, whose default was `false` with a reason and whose only\n// other honest setting was `storeDecidesRights`: yes to everything, let the door\n// refuse afterwards. The sixth-pass verdict measured what that second answer\n// costs a person: a colleague at viewer got a live cell editor, typed, pressed\n// Enter, and was refused only then.\n//\n// THE STORE ANSWERS THIS NOW, through the door this lane added:\n// `custom.my_levels` says what level the CALLER holds on the subjects they\n// name, one call for a whole page. `rights` stays a PORT for a host whose\n// authority is genuinely its own, but nothing is guessed when it is unbound:\n// the store's own answer is the default, and `rights.why(...)` says, for each\n// thing a person may not do, what level it would take and who can give it.\n//\n// IT IS NOT FREE, AND THE OBVIOUS FREE VERSION IS WRONG. `custom.read_records`\n// answers `level` on every row and `tableList` is a read — but of the Table\n// KERNEL, so that level is the caller's level on the kernel (viewer, for\n// everybody) and not on the table the row describes. Carrying it was measured\n// wrong within the hour: a table's own owner came back \"viewer\". A table is a\n// record, and its level is asked for like any other record's.\n//\n// ABSENT OR HONEST, NEVER DEAD — and never offered-then-refused, which is the\n// same lie with a longer fuse.\n\nimport { createContext, useContext, useMemo, type ReactNode } from \"react\";\nimport type { AggregateFilter, Field, PermissionLevel, RecordDocument, RecordRead, Table, Uuid } from \"@ai-matrx/records\";\nimport { useMyLevel, useMyLevels } from \"@ai-matrx/records/react\";\nimport type { ReversibleAnnouncement } from \"@ai-matrx/kit/reversible\";\nimport type { TableSettingsAgent } from \"./settingsAgent\";\n\nimport { NOT_ANSWERED_YET, whatYouMayDo, whatYouMayDoWithTable, type WhatYouMayDo } from \"./rights\";\nimport type { RecordChatContext } from \"./RecordChat\";\nimport type { EnrichAsk, EnrichOutcome } from \"./Enrich\";\nimport type { GridContextSnapshot } from \"./gridAgentContext\";\n\n/**\n * What a person may do to one table. The four words and the ladder are the\n * store's (`rights.ts`), not ours.\n *\n * `admin`, `comment` and `write` are kept with the names they have always had,\n * because every screen in this package and in the host apps reads them; they\n * are now the store's ANSWER rather than a host's guess.\n */\nexport interface TableRights extends WhatYouMayDo {\n /** SCR-2: holders of `admin` on the table see the \"+\" and the settings panel. */\n admin: boolean;\n /**\n * Why this answer, in one sentence. Kept for callers that show a single\n * reason; `why(what)` is the per-control sentence and is what the screens use.\n */\n reason: string;\n}\n\nfunction tableRights(may: WhatYouMayDo, overallReason?: string): TableRights {\n return {\n ...may,\n admin: may.structure,\n reason: overallReason ?? (may.structure ? \"\" : may.why(\"structure\")),\n };\n}\n\n/**\n * Kept so a host that imported it still compiles. It is no longer any screen's\n * default: the store answers this question now, and a package that said \"I\n * assume nothing\" while holding the answer would be hiding controls from the\n * people who hold them.\n */\nexport const NO_RIGHTS: TableRights = tableRights(NOT_ANSWERED_YET);\n\n/**\n * THE ONE WAY TO BUILD A `TableRights` BY HAND — for a host with its own\n * authority, and for a suite that wants to mount one seat's screen. It takes\n * the LEVEL, never six booleans, so nobody can hand a screen a combination the\n * ladder cannot produce (write without read, share without edit).\n */\nexport function tableRightsAt(level: PermissionLevel | null): TableRights {\n return tableRights(whatYouMayDo(level, true));\n}\n\n/**\n * The authored-text slots `renderText` is asked to draw. `cell`: a long-text cell of the merged\n * grid and the whole-text dialog's preview — the host may return block content there (the grid\n * clips it to the row); the form slots take phrasing content only.\n */\nexport type RenderTextSlot = \"form-intro\" | \"form-help\" | \"form-thank-you\" | \"cell\";\n\nexport type { GridContextSnapshot } from \"./gridAgentContext\";\n\n/** One reference a chip names (`renderReference`). `record` is a relation's value, read side only. */\n/** What a record page hands the host's rich editor (`editRichText`). */\nexport interface RichTextEditProps {\n /** The stored Markdown. A later value is the store's echo or a colleague's change. */\n value: string;\n /** Every change the person makes, as the whole Markdown text. Saving is the package's. */\n onChange: (text: string) => void;\n readOnly: boolean;\n placeholder: string;\n}\n\nexport interface ReferenceChipRef {\n token: string;\n id: Uuid;\n label: string | null;\n /** For `token: \"record\"`, the Table the relation points into. */\n tableId?: Uuid | undefined;\n /**\n * The record it names sits in Archived items. An archive keeps every reference to what it\n * archived (chair ruling B3-21), so the chip still names it and draws the archived state.\n */\n archived?: boolean | undefined;\n /** The record's (or its table's) icon — an emoji or short glyph — when the host knows one. */\n icon?: string | null | undefined;\n}\n\nexport interface RecordsUiHost {\n /**\n * Draws an icon kept as a NAME (\"Briefcase\" — how the store keeps an icon a person picked from the\n * icon list). A relation cell in an embedded table wears its record's icon; an emoji is drawn as\n * text and a name only through this port. Unbound (or `null` back), the page glyph stands in.\n */\n renderIcon?: ((name: string) => ReactNode) | undefined;\n /**\n * TEMPORARY (one-grid merge, steps 5-8). Which table grid draws: `classic` — the default Grid\n * as it shipped in 0.86; `merged` — the same grid with the older /data grid's control layer on\n * it (the column header menu, the right-click Cell / Row / Column / Table sections, column\n * settings, column order and hidden columns kept on the view). Left out: `classic`. Removed at\n * merge step 9, when `merged` is the only grid.\n */\n grid?: \"classic\" | \"merged\";\n /**\n * OPTIONAL. CLEAN A PASTED PIECE OF HTML INTO PLAIN TEXT (merge tranche 6m, inventory A7).\n *\n * A cell pasted from a web page or an email carries its tags, entities and inline styles. The\n * platform has ONE cleaner (the host's content-cleanup), so this is a port rather than a second\n * one here. The merged grid offers \"Clean HTML\" in a text cell's right-click Cell section and in\n * the whole-text editor; the cleaned text is written through the grid's own one-cell write (one\n * undo step). Unbound, the item is ABSENT, never dead.\n */\n cleanText?: (text: string) => string;\n /**\n * OPTIONAL. WHERE THE PERSON IS IN THE GRID, told as it changes (merge tranche 6l, inventory H1).\n *\n * An agent in the host's side chat is asked about \"this cell\", \"these rows\", \"the table\". Only\n * the grid knows the table, its columns, the cell the cursor is on, the selected block, the\n * ticked rows, the rows on screen and the search. The merged grid calls this after any of them\n * changes (identical snapshots are not repeated); the host builds its agent scope from it. The\n * snapshot carries the store's own `Field` records and the masked documents exactly as drawn.\n * Unbound, nothing is built.\n */\n onGridContext?: (snapshot: GridContextSnapshot) => void;\n /**\n * OPTIONAL. THE PLATFORM'S ONE ICON PICKER (merge tranche 6j, inventory G2). A row action's\n * button may carry an icon from the canonical icon set; that set and its picker are the host's\n * (this package carries no icon library). Unbound, the row-action editor draws no icon control\n * and keeps whatever icon an action already carries.\n */\n iconPicker?: (props: { value: string; label: string; onChange: (name: string) => void }) => ReactNode;\n /**\n * OPTIONAL. HELP WRITING A FORMULA (Sheet retirement). The formula box hands the host what it\n * holds — the text, the table's other columns and the store's reading of what is wrong — and the\n * host draws its own help control beside the box (matrx-frontend runs its formula-writing job).\n * Whatever formula the help arrives at goes back through `onFormula` into the box, unsaved, for\n * the person to keep or change. Unbound, nothing is drawn.\n */\n formulaHelp?: (ask: FormulaHelpAsk) => ReactNode;\n /**\n * OPTIONAL. AN AGENT OVER A TABLE'S SETTINGS (Sheet retirement). While the settings panel is open\n * it wraps itself in what this returns, handing the host a `TableSettingsAgent`: what the panel\n * can see (the description as edited, the row actions and the one being edited, what stops it\n * saving) and three staging calls (a whole row action, one step's formula, the description).\n * Staging never saves; the person presses Save. Unbound, the panel draws bare.\n */\n settingsAgent?: (args: { tableId: Uuid; agent: TableSettingsAgent; children: ReactNode }) => ReactNode;\n /** Answer the rights question for one table. Synchronous: a screen renders now. */\n rights?: (table: Table) => TableRights;\n /** Where a record's own page lives, when the host has one. A peek is used when it does not. */\n hrefForRecord?: (args: { table: Table; recordId: Uuid }) => string | undefined;\n /**\n * OPTIONAL. WHERE A FILE OPENS. A value too big for one cell is kept as a file and the cell\n * holds its first words (`@ai-matrx/records/core` `wholeValueOf`); this is the host's page for\n * that file. Unbound, the cell shows the words and says the whole text is kept as a file this\n * screen cannot open — never a dead link.\n */\n hrefForFile?: (args: { fileId: Uuid }) => string | undefined;\n /**\n * OPTIONAL. READ A FILE'S WHOLE TEXT, so an export writes a big value's whole content rather\n * than its first words. Unbound, the exported cell carries the words and one sentence naming\n * the file (`wholeValueNotRead`) — never the words passed off as the value.\n */\n readFileText?: (args: { fileId: Uuid }) => Promise<string>;\n /**\n * OPTIONAL. A FILE DRAWN AS A PICTURE — the gallery card's cover when the view's picture column\n * is a File column (lane DATA-V2-VIEWS-1). The host owns how a file becomes pixels (its media\n * lane, its auth), so this is a port: it returns the element that fills the cover box. Unbound,\n * the cover says in words that this screen cannot draw files, never a broken image.\n */\n fileImage?: (args: { fileId: Uuid; alt: string }) => ReactNode;\n /**\n * OPTIONAL. HOW AUTHORED TEXT READS. A form's intro, a question's help and the thank-you body\n * are written by a person and may carry markdown and math (`**bold**`, `\\\\(x^2\\\\)`, links).\n * This package does not parse markdown — the host owns its renderer — so this is a port: the\n * host returns phrasing content (valid inside a `<p>`). `where` names the slot. Unbound, the\n * text shows exactly as written.\n */\n renderText?: (text: string, where: RenderTextSlot) => ReactNode;\n /**\n * OPTIONAL. ONE REFERENCE, DRAWN AS A CHIP THAT OPENS WHAT IT NAMES (lane REFERENCE-CARRY).\n *\n * Every reference this package shows — a relation to a record (`token: \"record\"`, with the\n * Table it points into), an entity reference to a platform thing (`note`, `agent`, `workflow`…)\n * — is drawn through this port, so a person can always reach the thing (the host owns routes,\n * peeks and new tabs). `label` is the store's words, or null when they were withheld from this\n * reader. Unbound, the chip names the thing and opens nothing.\n */\n renderReference?: (ref: ReferenceChipRef) => ReactNode;\n /**\n * OPTIONAL. A VALUE THAT NAMES ITS OWN SHAPE, DRAWN THROUGH THE HOST'S KIND SYSTEM (lane\n * REFERENCE-CARRY). A cell holding `__kind` JSON — or a Matrx directive stored before the Kind\n * Directives merge (```matrx {\"matrx_version\":1,…}```) — is handed over whole (`kindValues.ts`);\n * the host decodes it with its one decoder and returns a compact rendering for `where` (a cell,\n * a panel row) that opens the real view. Unbound, the cell names the kind and shows the raw text\n * on hover — never the fence at eye level.\n */\n renderKind?: (args: { value: Record<string, unknown>; kind: string; where: \"cell\" | \"panel\"; title: string }) => ReactNode;\n /** The host's own link element, so routing stays the host's business. */\n Link?: (props: { href: string; children: ReactNode; className?: string }) => ReactNode;\n /** Toasts. Absent means the screen shows the sentence inline instead — never silence. */\n notify?: {\n /** `action`: one button on the toast (an Undo). A host without actions draws the sentence alone. */\n success: (message: string, action?: { label: string; run: () => void }) => void;\n error: (message: string) => void;\n /**\n * OPTIONAL. THE REVERSIBLE ACTION (`@ai-matrx/kit/reversible`): something this package did\n * that can be undone — a table archived — handed to the host's one announcer, which acts it\n * out at the person's level (taught the first time, a long Undo toast the next few, an ordinary\n * one after) and answers ⌘Z. The package says WHAT happened and HOW to undo it; where the\n * thing went (`foundAt`) is the host's routes. Unbound, the package falls back to `success`\n * with an Undo button.\n */\n reversible?: (announcement: ReversibleAnnouncement) => void;\n };\n /** Density for every table this package renders. */\n density?: \"condensed\" | \"normal\" | \"spacious\";\n /**\n * OPTIONAL. WHETHER A WITHHELD CONTROL SAYS WHAT LEVEL IT TAKES (\"You are Viewer here, and it takes\n * Editor to … Ask somebody who is Admin on it to move you up.\"). Default `true`. A host whose\n * person has no level to be moved up to — a template preview, a public look at a table — sets\n * `false`: the control stays absent exactly as before, without the sentence. It changes words\n * only, never what is offered.\n */\n sayLevelNeeded?: boolean;\n /**\n * OPTIONAL. Where a file a person attached actually goes. A File is a record\n * in the kernel File Table (REC-31), but the BYTES are the host's file\n * service, not this package's business — so this is a port.\n *\n * Unbound, an attachment question does NOT draw a file chooser that quietly\n * loses the file: it says, in one sentence, that no file store is bound and\n * names this port. Absent or honest, never dead.\n */\n upload?: (file: File) => Promise<{ ok: true; fileId: Uuid } | { ok: false; reason: string }>;\n /**\n * OPTIONAL. THE HOST'S OWN FILE WINDOW (one-grid merge, inventory: the older grid's\n * AttachmentInput). An attachment cell adds files the person already holds through the host's\n * file picker — Airtable's \"Attach\" over your own files — rather than a second browser this\n * package would invent. `multiple`: the column holds several files; `accept`: the native\n * `accept` list, when the column restricts types. Resolves the host's file ids (the store turns\n * each into its kernel File record at the write door), or `null` when the person cancelled.\n *\n * Unbound, the editor offers `upload` alone; with neither bound it says no file store is bound\n * (`NO_UPLOAD_REASON`) — never a dead button.\n */\n pickFiles?: (ask: { multiple: boolean; accept?: string }) => Promise<Uuid[] | null>;\n /**\n * Where this app serves its PUBLIC pages from, when that is not the origin\n * the screen is running on. A form's link is built here, so an owner copying\n * it from an admin host, a preview deployment or a desktop shell gets the\n * address a stranger can actually open — never `http://localhost:3000/f/…`\n * pasted into an email. Unbound, the browser's own origin is used.\n */\n publicOrigin?: string;\n /**\n * OPTIONAL. The organization's saved views as `platform.saved_view` holds\n * them — which is what a subscription points at (DOOR-18). The record store\n * has NO door onto that table, because it is the platform's and not the\n * store's, so this is a port rather than a read this package invents.\n *\n * Unbound, `NotifyRuleEditor` shows the subscriptions that exist and says, in\n * one sentence, that it cannot offer a view to subscribe to. It never renders\n * an empty picker that looks like \"you have no views\".\n */\n savedViews?: () => Promise<Array<{ id: Uuid; name: string }>>;\n /**\n * OPTIONAL. WHO IS IN THIS ORGANIZATION (FLD-11 `member`).\n *\n * A person field must offer PEOPLE. Who the people are is the platform's\n * answer — organization membership lives in `iam`, not in the record store —\n * and the store has no door onto it, so this is a port rather than a read\n * this package invents. `PersonPicker` resolves whoever is picked to their\n * record in the kernel Person Table, which is what the Field actually stores.\n *\n * Unbound, a person question is ABSENT with `NO_MEMBERS_REASON`. It never\n * falls back to listing the kernel Person Table's contents: that Table also\n * holds the Homes this package writes, and offering \"Comments Home\" as a\n * person is exactly what this port exists to stop.\n */\n members?: () => Promise<OrganizationMember[]>;\n /**\n * OPTIONAL. THE HOST'S OWN CHAT SURFACE (SCR-26).\n *\n * This package ships no chat UI, on purpose: AI Matrx has exactly one, it\n * lives in matrx-frontend (`AgentConversationColumn`), and it reads that app's\n * Redux store — so a second one here would drift within a month and a package\n * that imported the first would stop being a package. `RecordChat` therefore\n * builds the CONTEXT (the record, through the read door, with the masked\n * fields named) and hands it to this port.\n *\n * Unbound, the panel is ABSENT with that reason, never a composer that goes\n * nowhere.\n */\n chat?: (context: RecordChatContext) => ReactNode;\n /**\n * OPTIONAL. MORE SECTIONS ON AN OPEN RECORD — drawn in the record rail after its history,\n * one host-owned block about THIS record (e.g. \"What ran on this record\": the Workflow runs\n * stamped with it). Unbound, nothing is drawn.\n */\n recordSections?: (target: { tableId: Uuid; recordId: Uuid }) => ReactNode;\n /**\n * OPTIONAL. THE PLATFORM'S ONE RICH EDITOR, for a record page's body (lane TABLE-EXPERIENCE,\n * v7 item 1: a record is a page). The host draws its own editor — matrx-frontend's notes editor —\n * reporting every change through `onChange`; this package owns the saving. Unbound, the body is\n * drawn read-only and is edited through the record's form.\n */\n editRichText?: (props: RichTextEditProps) => ReactNode;\n /**\n * OPTIONAL. THE HOST DRAWS A RECORD PAGE'S WHOLE BODY (the \"Spaces\" page layer's block editor).\n * When bound and it returns non-null, the record page draws that in place of the package's own\n * body (the formatted-text column editor and its \"Write on this page\" offer); the host owns\n * saving. Returning `null` (or leaving it unbound) draws today's body unchanged.\n */\n renderRecordBody?: (args: {\n tableId: string;\n recordId: string;\n record: RecordRead;\n readOnly: boolean;\n /** Today's body as an element — return it (or null) where the host has no body of its own. */\n fallback: ReactNode;\n }) => ReactNode | null;\n /**\n * OPTIONAL. \"LINK A RECORD…\" — the HOST opens its one record picker pointed at this record and\n * writes the link through its own reference door; this package draws only the menu entry (a\n * card's ⋯ and right-click, the grid row's right-click). Unbound, the entry says it is not\n * available here.\n */\n linkRecord?: (target: { tableId: Uuid; recordId: Uuid; name: string }) => void;\n /**\n * OPTIONAL. \"TALK TO THIS RECORD\" — the HOST opens its own one chat surface\n * (AGT-N-9, PRODUCTS row 11).\n *\n * `chat` is the port that RENDERS a chat inside a panel this package draws.\n * This one is the other direction: a menu entry in the grid, the cell menu or\n * the record header says \"the person wants to talk about this record\", and the\n * host opens the chat where the host puts chats — full height, the platform's\n * own pattern — and binds the conversation to the record through\n * `conversationScopeBind`. Drawing a chat next to a grid row from inside this\n * package would be the parallel layer the canvas ruling forbids.\n *\n * ABSENT, NEVER DEAD: where neither this nor `chat` is bound, the entries do\n * not render at all.\n */\n talkToRecord?: (target: { tableId: Uuid; recordId: Uuid; title: string }) => void;\n /**\n * OPTIONAL. A TABLE'S AGENT BUTTON, PRESSED (TABLE-PARITY M3, lane DEFAULT-GRID-PARITY).\n *\n * A row action of kind `agent` (\"Ask Dr. Whitfield\") hands the row to an agent with the\n * action's own `prompt`. Only the host can start that conversation — this package ships no\n * chat — so the grid hands the row, the action's name and its prompt here, and the host\n * opens its one chat surface bound to the record with that prompt as the opening ask. It is\n * a separate port from `talkToRecord` because that one carries no prompt: a host that bound\n * only `talkToRecord` would open an empty chat and silently drop what the button was for.\n *\n * ABSENT, NEVER DEAD: unbound, agent buttons are not drawn.\n *\n * NO SECOND READ (lane GRID-TAILS, 2026-09-24). The grid already holds the table, its\n * columns, the row as this reader may see it and this reader's level on the row, so it hands\n * them over: a host needs no `tableList`, `fields`, `recordRead` or `myLevels` to start the\n * job, and the agent is handed exactly what the person was looking at.\n */\n runAgentAction?: (target: {\n tableId: Uuid;\n recordId: Uuid;\n title: string;\n action: string;\n prompt: string;\n /** The table's name, as the grid shows it. */\n tableName: string;\n /** The table's columns, as the grid drew them. */\n fields: readonly Field[];\n /** The row, masked for this reader exactly as the grid shows it. */\n document: RecordDocument;\n /** This reader's level on the row (`custom.read_records_matching`'s answer). */\n level: PermissionLevel | null;\n }) => void;\n /**\n * OPTIONAL. THE SERVER'S `records` TOOL (SCR-27).\n *\n * An AI fill must be written with actor `agent` on behalf of the person, and\n * only the server can honestly say that — a browser stamping itself `agent`\n * is a browser claiming to be one. So `EnrichPanel` asks here, and the host\n * calls the server's own `records` tool (`action: \"record_write\"`), which\n * stamps `_actor` and `_on_behalf_of` itself.\n *\n * Unbound, no Fill control is drawn at all and the reason names this port.\n */\n enrich?: (ask: EnrichAsk) => Promise<EnrichOutcome>;\n /**\n * OPTIONAL. WHERE AN OFFLINE CAPTURE WAITS (SCR-30).\n *\n * `CaptureSheet` mints the id for a capture BEFORE it tries to send it, so a\n * phone with no signal has already decided what the write will be called.\n * Where that queue physically lives is the host's business — IndexedDB in a\n * browser, a file in a desktop app — so it is a port. Unbound, the sheet\n * keeps its queue in memory for the life of the page AND SAYS SO, because a\n * queue that silently died with the tab is the failure this exists to avoid.\n */\n captureQueue?: CaptureQueuePort;\n /**\n * OPTIONAL. THE HOST'S OWN SHARE DIALOG (SCR-N-5).\n *\n * This package ships no share dialog, ON PURPOSE, and for the same reason it\n * ships no chat: AI Matrx has exactly ONE sharing surface — matrx-frontend's\n * `features/sharing` ShareModal, with its people picker, its level picker, its\n * grant list and its \"who can see this, and why\" panel — and a second one here\n * would be a parallel sharing UI within a month. Sharing is the access model's\n * front door, and two front doors is how a platform ends up with two answers\n * to \"who can see this\".\n *\n * So `ShareControl` draws the BUTTON (which belongs on the record and table\n * screens, beside everything else a person does to a thing) and hands the\n * subject to this port, which returns the host's own dialog.\n *\n * Unbound, the button is ABSENT and `NO_SHARE_REASON` says which port to bind.\n * Never a Share button that opens nothing.\n */\n share?: (subject: ShareSubject) => ReactNode;\n /**\n * APPLETS ON A PAGE (v7 APPS-ON-DATA item 3). The host's applet system: which applets this person\n * may place (`list`), and the applet itself drawn in place (`render`). Unbound, a page offers no\n * Applet block and an applet block already on the page says it opens inside the app.\n */\n applets?: {\n list: () => Promise<ReadonlyArray<{ id: string; name: string }>>;\n render: (appId: string) => ReactNode;\n };\n /**\n * OPTIONAL. OPEN THE RECORDS BEHIND A NUMBER (SCR-16).\n *\n * Every number on a dashboard is a count of real records, and the whole\n * product row is that a person can get from the number to them: click the\n * \"Awaiting parts\" column and the grid opens on the twenty-eight jobs it\n * counted, with the block's own filter still on. That is one navigation, and\n * WHERE the grid lives is the host's routing — so it is a port, like\n * `hrefForRecord`, rather than a route string this package invents.\n *\n * Unbound, the marks are NOT clickable and the canvas says so in one\n * sentence naming this port. A chart whose bars looked pressable and did\n * nothing is the dead control this package does not ship.\n */\n openRecords?: (ask: OpenRecordsAsk) => void;\n /**\n * OPTIONAL. WHERE A PAGE OPENS (v6 lane 11, wave D). A Page is a dashboard record whose\n * `presentation.kind` is `\"page\"` (`pages.ts`); the host owns its route, so this hands back the\n * address of an existing page, or of the screen that makes a new one on a Table. Unbound, the\n * Dashboards area lists no pages and offers no \"New page\" — absent, never dead.\n */\n pageHref?: (target: { pageId: Uuid } | { newOnTable: Uuid }) => string;\n /**\n * OPTIONAL. ASK THE AGENT TO CHANGE THIS DASHBOARD (SCR-16).\n *\n * \"break it down by owner\" is how a dashboard is actually built — the agent\n * calls `dashboard_propose` on the server's `records` tool with this\n * dashboard's id and re-states it. Only the server can do that honestly (a\n * browser stamping itself `agent` is a browser claiming to be one), which is\n * the same reason `enrich` is a port, so this is one too.\n *\n * Unbound, the box is drawn DISABLED with one sentence naming this port —\n * never a composer that goes nowhere and never silence.\n */\n onReask?: (question: string, context: ReaskContext) => Promise<void>;\n /**\n * OPTIONAL. ASK AN AGENT FOR A WHOLE FORM, BOOKING PAGE, PORTAL OR DIGEST.\n *\n * This is the FASTER of the two ways every builder offers (`BuildOrAsk`), and\n * it is a port for the same reason `onReask` is: the server's `records` tool\n * is what calls `form_propose`, `booking_propose`, `portal_propose` and\n * `subscription_propose`, and a browser stamping itself `agent` would be a\n * browser claiming to be one.\n *\n * `suggestion` is the sentence this package would put in the person's mouth —\n * a host normally opens its composer with it already typed, so the person\n * edits rather than starts.\n *\n * Unbound, the \"Ask an agent\" button is ABSENT — not greyed — and every\n * builder's empty state says so in one sentence naming this port, with the\n * hand-built way still right there. The product walk of 2026-09-21 found the\n * opposite arrangement (the agent named and no builder at all), which left a\n * person who did not know what to say with nothing to press.\n */\n onAskForOne?: (ask: AgentBuildAsk) => void;\n}\n\n/** What the formula box hands the host's help (`formulaHelp`). */\nexport interface FormulaHelpAsk {\n tableId: Uuid;\n /** The formula as it stands in the box (may be empty). */\n text: string;\n /** The table's other columns, the ones the formula may read as {Name}. */\n columns: readonly Field[];\n /** The store's reading of what is wrong with the text, when it does not parse. */\n mistake: string | null;\n /** The functions the store works out, as a person types them. */\n functions: readonly string[];\n /** Put a formula into the box (unsaved). */\n onFormula: (text: string) => void;\n}\n\n/** What a person is asking an agent to make, and where they were standing. */\nexport interface AgentBuildAsk {\n /**\n * `column`: a layout needs a column the table lacks (`ViewNeeds`, lane DATA-V2-VIEWS-1) — the\n * agent adds it through the store's field door, held for approval like every agent schema change.\n */\n kind: \"form\" | \"booking\" | \"portal\" | \"digest\" | \"column\";\n tableId: Uuid;\n /** The sentence this package would say. A host opens its composer with it. */\n suggestion: string;\n}\n\n/**\n * WHAT A CLICK ON A NUMBER ASKS FOR. The filter is already merged: the block's\n * own filter (which `custom.dashboard_run` echoes back with the canvas bar\n * folded under it) with the clicked group's key and value over the top. A host\n * that dropped a key would open the grid on more records than the number\n * counted, which is the one way this control can lie.\n */\nexport interface OpenRecordsAsk {\n tableId: Uuid;\n filter: Record<string, AggregateFilter>;\n /** What the person clicked, in words: \"Jobs by stage this month · Awaiting parts\". */\n label: string;\n}\n\n/** Which dashboard a re-ask is about, so the agent re-states it rather than making a second one. */\nexport interface ReaskContext {\n tableId: Uuid;\n /** Null while the canvas has no dashboard yet — the answer is the first one. */\n dashboardId: Uuid | null;\n dashboardName: string | null;\n}\n\n/**\n * What a host's share dialog is being opened ON. A Table is a record in this\n * store (a `custom.record` row whose table is the Table kernel), so ONE subject\n * shape covers both screens and `kind` is what the sentences say, not what the\n * store looks up.\n */\nexport interface ShareSubject {\n kind: \"record\" | \"table\";\n /** The store is keyed (organization_id, id); this package never guesses one. */\n organizationId: Uuid;\n subjectId: Uuid;\n /** What to call it on screen. Never empty — the id's first eight characters at worst. */\n name: string;\n /** Close the dialog. The control owns the open/closed state, the host owns the dialog. */\n onClose: () => void;\n}\n\n/** One member of the organization, in the words a person reads. */\nexport interface OrganizationMember {\n /** The platform's user id. This is what a Person record carries as `user_id`. */\n userId: string;\n /** Their display name, when the platform has one. */\n name?: string | null;\n email?: string | null;\n avatarUrl?: string | null;\n}\n\n/** The durable half of offline capture: read the queue, write it, that is all. */\nexport interface CaptureQueuePort {\n load: () => Promise<PendingCapture[]>;\n save: (pending: PendingCapture[]) => Promise<void>;\n}\n\n/** One capture waiting to be written, with the id the CLIENT minted for it. */\nexport interface PendingCapture {\n /**\n * The client key. Minted offline, before the first attempt, and never\n * re-minted on retry — that is exactly what lets the store's replay ledger\n * tell a retry from a second capture.\n */\n clientKey: string;\n tableId: Uuid;\n payload: Record<string, unknown>;\n capturedAt: string;\n device: string;\n /** How many times sending has been tried, and what the store last said. */\n attempts: number;\n lastRefusal?: string | null;\n}\n\n/**\n * The sentence the notify editor shows when no saved-view port is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `savedViews` on\n * `<RecordsUiProvider>` with the host's own list of `platform.saved_view` rows —\n * the record store has no door onto them — and the picker appears.\n */\nexport const NO_SAVED_VIEWS_REASON =\n \"There are no saved views here yet, so there is nothing to be told about. Save a view of this \" +\n \"table first and it will be offered here.\";\n\n/**\n * The sentence a person question shows when no membership port is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `members` on\n * `<RecordsUiProvider>` with the host's own roster. Who is in an organization is\n * the platform's answer, not the record store's, so this package will not guess.\n */\nexport const NO_MEMBERS_REASON =\n \"This app cannot offer the people in your organization on this screen yet, so there is nobody to \" +\n \"pick. Type the person's name into a text field for now, and tell us — it is on our list, not \" +\n \"yours.\";\n\n/**\n * The sentence shown when no share dialog is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `share` on\n * `<RecordsUiProvider>` with the app's own sharing dialog. AI Matrx has exactly\n * one, and this package deliberately does not ship a second.\n */\nexport const NO_SHARE_REASON =\n \"Sharing is not available on this screen, so there is no Share button here rather than one that \" +\n \"opens nothing. Share this table from the tables list instead.\";\n\n/**\n * The sentence a canvas shows when nothing is bound to open the records behind a number.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `openRecords` on\n * `<RecordsUiProvider>`. Where this app puts its grid is the host's routing, not\n * this package's, so it will not guess an address.\n */\nexport const NO_OPEN_RECORDS_REASON =\n \"These numbers do not click through yet. Every one of them is a count of real records — open the \" +\n \"records view and group it by the same field to see them. It is on our list, not yours.\";\n\n/**\n * The sentence the re-ask box shows when no agent is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `onReask` on\n * `<RecordsUiProvider>`; it drives `dashboard_propose` on the server's `records`\n * tool with this dashboard's id. Only the server can honestly speak as an agent.\n */\nexport const NO_REASK_REASON =\n \"Changing this dashboard by describing it is not switched on here yet, so this box is off rather \" +\n \"than one that goes nowhere. Add and remove the blocks by hand above. It is on our list, not \" +\n \"yours.\";\n\n/**\n * The sentence an attachment question shows when no file store is bound.\n *\n * FOR WHOEVER MAINTAINS THIS APP (never on the screen): bind `upload` on\n * `<RecordsUiProvider>` with the host's file service and the chooser appears.\n */\nexport const NO_UPLOAD_REASON =\n \"This screen cannot take a file yet, so there is no chooser here rather than one that loses what \" +\n \"you pick. Put a link to the file in a text field for now. It is on our list, not yours.\";\n\nconst HostContext = createContext<RecordsUiHost | null>(null);\n\nexport function RecordsUiProvider({ value, children }: { value: RecordsUiHost; children: ReactNode }) {\n const bound = useMemo(() => value, [value]);\n return <HostContext.Provider value={bound}>{children}</HostContext.Provider>;\n}\n\nexport function useRecordsUi(): RecordsUiHost {\n return useContext(HostContext) ?? {};\n}\n\n/**\n * WHAT THIS PERSON MAY DO TO THIS TABLE — asked, once per table.\n *\n * A host that binds `rights` still wins: a portal, an embed or an app with its\n * own authority is entitled to a narrower answer than the store's. An unbound\n * host no longer gets a guess in either direction — while the door is\n * answering, `known` is false and NOTHING is offered and nothing is claimed.\n */\n/** The same answer, with its level sentences silenced when the host says so (`sayLevelNeeded`). */\nfunction quiet<T extends WhatYouMayDo>(may: T, say: boolean | undefined): T {\n if (say !== false) return may;\n return { ...may, why: () => \"\", ...(\"reason\" in may ? { reason: \"\" } : {}) };\n}\n\nexport function useTableRights(table: Table | null | undefined): TableRights {\n const host = useRecordsUi();\n const asked = useTableRightsAsked(table, host);\n return useMemo(() => quiet(asked, host.sayLevelNeeded), [asked, host.sayLevelNeeded]);\n}\n\nfunction useTableRightsAsked(table: Table | null | undefined, host: RecordsUiHost): TableRights {\n const bound = Boolean(host.rights);\n // A table is a record in this store, so its level is the same question.\n const asked = useMyLevel(bound || !table ? null : table.id);\n return useMemo(() => {\n if (!table) return NO_RIGHTS;\n if (host.rights) return host.rights(table);\n if (asked.loading) return tableRights(NOT_ANSWERED_YET);\n // A refusal is an ANSWER: the door said no, so this person holds nothing.\n const level = asked.error ? null : asked.data;\n return tableRights(whatYouMayDoWithTable(table, level, true));\n }, [host, table, bound, asked.loading, asked.error, asked.data]);\n}\n\n/**\n * WHAT THIS PERSON MAY DO TO ONE RECORD — which is a different question from\n * the table's, and the sixth-pass verdict is the proof: a record shared with a\n * colleague at Editor inside a table she holds at Viewer. The grid used to\n * label that row \"viewer\" while the store let her write to it.\n */\nexport function useRecordRights(recordId: Uuid | null): WhatYouMayDo {\n const asked = useMyLevel(recordId);\n const say = useRecordsUi().sayLevelNeeded;\n return useMemo(() => {\n if (!recordId) return NOT_ANSWERED_YET;\n if (asked.loading) return NOT_ANSWERED_YET;\n // A refusal is an ANSWER: the door said no, so this person holds nothing.\n if (asked.error) return quiet(whatYouMayDo(null, true), say);\n return quiet(whatYouMayDo(asked.data, true), say);\n }, [recordId, asked.loading, asked.error, asked.data, say]);\n}\n\n/**\n * The same question for a whole page of records, in ONE call — the door takes a\n * list precisely so a grid never makes one call per row.\n *\n * `enabled` is how a grid avoids asking at all in the ordinary case: when the\n * table level already admits editing, every row it returned is editable and\n * there is nothing a per-record answer could add.\n */\nexport function useRowRights(\n rowIds: Uuid[],\n enabled: boolean,\n): (rowId: Uuid) => WhatYouMayDo | null {\n const asked = useMyLevels(enabled ? rowIds : []);\n const say = useRecordsUi().sayLevelNeeded;\n return useMemo(() => {\n if (!enabled) return () => null;\n if (asked.loading) return () => NOT_ANSWERED_YET;\n if (asked.error) return () => quiet(whatYouMayDo(null, true), say);\n const held = asked.data ?? {};\n return (rowId: Uuid) => quiet(whatYouMayDo((held[rowId] ?? null) as PermissionLevel | null, true), say);\n }, [enabled, asked.loading, asked.error, asked.data, say]);\n}\n","// src/rights.ts — @ai-matrx/records-ui\n//\n// THE ONE PLACE A LEVEL BECOMES A SCREEN.\n//\n// WHAT A PERSON HIT (independent verdict, sixth pass, 19-20 September). A\n// colleague who had been shared a table at viewer opened it, double-clicked a\n// cell, got a live editor, typed a value and pressed Enter — and only THEN was\n// told she may not write. \"The permission is right; the screen told her she\n// could.\" Measured against Airtable, Notion and Linear the verdict called it\n// out by name: \"None of these three products lets you start an action it\n// already knows it will reject.\"\n//\n// WHY THE SCREEN COULD NOT KNOW. The rights question was a PORT with two honest\n// answers and no third: `NO_RIGHTS` (every administering control absent, which\n// is useless for a host whose authority IS the store's) and\n// `storeDecidesRights` — `{admin: true, comment: true, write: true}` for every\n// non-kernel table, for everybody. That second one is the defect, written down:\n// it is the screen ASSUMING the answer and letting the door say no afterwards.\n//\n// WHAT REPLACES IT. The store already answers this, and the client now carries\n// it: `custom.read_records` returns the reader's level on the TABLE on every\n// row (so `Table.your_level` costs nothing), and `custom.my_levels` — the door\n// this lane added — answers the caller's level on any subject they name, one\n// call for a whole page. This file is the only place in the package that turns\n// one of those four words into what a screen may DRAW.\n//\n// THE LADDER IS THE STORE'S, NOT OURS: viewer < commenter < editor < admin, and\n// which rung each door requires is read from the doors themselves —\n// `custom.record_update` asserts `editor` on the record, `custom.field_declare`\n// asserts `admin` on the TABLE (\"the SHAPE of this table, which is an admin's\n// right and not an editor's\"), `custom.io_comment_write` admits a commenter.\n// Nothing here invents a rule; it mirrors the four assertions those doors make\n// and is wrong the moment they change, which is what the suite is for.\n//\n// ABSENT OR HONEST, NEVER DEAD. Every `false` here carries the sentence that\n// says why and what to do about it, so a control can be left out AND explained.\n// A screen that hid a control with nothing to say is the silent half of the\n// same defect.\n\nimport { atLeast, type PermissionLevel, type Table } from \"@ai-matrx/records\";\n\n/** The six things a person does to a record or a table, as the screens offer them. */\nexport type Capability = \"read\" | \"comment\" | \"write\" | \"organise\" | \"remove\" | \"share\" | \"structure\";\n\nexport interface WhatYouMayDo {\n /** The word the store answered, or null when it answered nothing. */\n level: PermissionLevel | null;\n /**\n * Whether the store has ANSWERED yet. `false` is a third state and not a\n * refusal: a screen that drew \"you may not\" while the answer was in flight\n * would blink every control off on every reload, which is its own lie.\n */\n known: boolean;\n read: boolean;\n comment: boolean;\n write: boolean;\n /** Duplicate, merge, restore, make a layout the default: the doors that ask `editor`, above content. */\n organise: boolean;\n remove: boolean;\n share: boolean;\n structure: boolean;\n /** Why this person may not do that, in one sentence naming the way in. */\n why: (what: Capability) => string;\n}\n\n/** What each rung of the ladder is called where a person reads it. */\nexport const LEVEL_WORD: Record<PermissionLevel, string> = {\n viewer: \"Viewer\",\n commenter: \"Commenter\",\n edit_content: \"Content editor\",\n editor: \"Editor\",\n admin: \"Admin\",\n};\n\n/**\n * WHICH RUNG EACH DOOR ASKS FOR. Read off the doors themselves, in one place,\n * so a screen never re-decides it and the suite has one thing to check.\n */\nconst NEEDS: Record<Capability, PermissionLevel> = {\n read: \"viewer\",\n // custom.io_comment_write\n comment: \"commenter\",\n // custom.record_update / custom.record_write — `edit_content` changes rows and page content;\n // columns, views and settings (structure) stay with admin below, and sharing with admin.\n write: \"edit_content\",\n // custom.view_designate / view_declare / migrate_merge / record_restore — all ask `editor`: more than\n // changing content (`edit_content`), less than changing columns (`admin`).\n organise: \"editor\",\n // custom.record_delete\n remove: \"editor\",\n // custom.share_grant — passing your access on is an administrator's right\n share: \"admin\",\n // custom.field_declare / field_update / field_retire / table settings\n structure: \"admin\",\n};\n\n/** The rung a capability asks for — so a short \"Needs Admin access\" never re-decides the ladder. */\nexport function levelNeededFor(what: Capability): PermissionLevel {\n return NEEDS[what];\n}\n\nconst NOT_YET =\n \"Still asking the store what you may do here. Nothing is offered until it has answered.\";\n\nconst NOTHING_AT_ALL =\n \"You have not been given this. Ask somebody who administers it to share it with you.\";\n\n/** The sentence for one refusal: what the level is, what it would have to be. */\nfunction sentenceFor(what: Capability, level: PermissionLevel | null): string {\n if (level === null) return NOTHING_AT_ALL;\n const need = LEVEL_WORD[NEEDS[what]];\n const have = LEVEL_WORD[level];\n const doing: Record<Capability, string> = {\n read: \"open this\",\n comment: \"leave a comment\",\n write: \"change anything here\",\n organise: \"organise this\",\n remove: \"delete this\",\n share: \"pass this on to somebody else\",\n structure: \"change the columns of this table\",\n };\n return `You are ${have} here, and it takes ${need} to ${doing[what]}. Ask somebody who is Admin on it to move you up.`;\n}\n\n/**\n * WHAT ONE LEVEL LETS A PERSON DO. `level` null and `known` true means the\n * store said \"nothing\" — a real answer. `known` false means it has not said.\n */\nexport function whatYouMayDo(level: PermissionLevel | null, known = true): WhatYouMayDo {\n const may = (what: Capability) => known && atLeast(level, NEEDS[what]);\n return {\n level: known ? level : null,\n known,\n read: may(\"read\"),\n comment: may(\"comment\"),\n write: may(\"write\"),\n organise: may(\"organise\"),\n remove: may(\"remove\"),\n share: may(\"share\"),\n structure: may(\"structure\"),\n why: (what) => (known ? sentenceFor(what, level) : NOT_YET),\n };\n}\n\n/** Nothing offered, because nothing is known yet. */\nexport const NOT_ANSWERED_YET: WhatYouMayDo = whatYouMayDo(null, false);\n\n/**\n * REC-27. The nine Tables the platform ships are not administered from a\n * person's screen whatever level they hold on them — so the structure controls\n * are absent for a kernel Table and say why, and everything else follows the\n * level as usual.\n */\nexport const KERNEL_REASON =\n \"This is one of the tables the platform ships, so its columns are not changed from a screen. \" +\n \"Make your own table to change columns.\";\n\nexport function whatYouMayDoWithTable(\n table: Table | null | undefined,\n level: PermissionLevel | null,\n known: boolean,\n): WhatYouMayDo {\n const base = whatYouMayDo(level, known);\n if (!table?.is_kernel) return base;\n return {\n ...base,\n structure: false,\n why: (what) => (what === \"structure\" ? KERNEL_REASON : base.why(what)),\n };\n}\n","\"use client\";\n\n// src/EntityReferenceKindPicker.tsx — @ai-matrx/records-ui · lane SC-R (P12)\n//\n// WHAT A COLUMN THAT POINTS AT A PLATFORM THING MAY POINT AT.\n//\n// An `entity_reference` column holds `{token, id}` values naming a note, a web site, an agent, a\n// workbook, a conversation — anything in `platform.entity_types` that is not a record-store Table\n// (a File and a Person stay `attachment` / `member`). The store keeps the allowed kinds in\n// `config.allowed_types` and refuses a value of any other kind by name. This is the question the\n// field editor asks for it: WHICH kinds. The list is the store's own\n// (`custom.entity_reference_kinds`, through `useEntityReferenceKinds`), grouped by its category,\n// searchable because there are over a hundred, and the chosen kinds sit above it as removable\n// chips so a person always sees what the column will take.\n//\n// No new primitive: `BasicInput`, `Checkbox`, `Badge` and `Button` from the design system, and the\n// package's own `RefusalNotice` when the kinds cannot be read — a list that silently came back\n// empty would be a screen that lies about what the store takes.\n\nimport { useMemo, useState } from \"react\";\nimport type { EntityReferenceKind } from \"@ai-matrx/records\";\nimport { useEntityReferenceKinds } from \"@ai-matrx/records/react\";\nimport { Badge, BasicInput, Checkbox, Label, Skeleton, cn } from \"@ai-matrx/design-system\";\nimport { RefusalNotice } from \"./Refusal\";\n\n/** What the panel says while the chosen list is empty. */\nexport const ENTITY_REFERENCE_KINDS_MISSING = \"Choose at least one kind of thing this column points at.\";\n\n/**\n * The declaration an entity-reference column is sent as — the words `custom.field_declare`\n * reads (`type: \"entity_reference\"`, `allowed_types`, `multi`). One place builds it, so the field\n * editor, a table template and an agent never disagree on the shape.\n */\nexport function entityReferenceSpec(input: {\n label: string;\n allowedTypes: readonly string[];\n multi?: boolean;\n required?: boolean;\n}): { label: string; type: \"entity_reference\"; allowed_types: string[]; multi: boolean; required: boolean } {\n const seen = new Set<string>();\n const allowed: string[] = [];\n for (const raw of input.allowedTypes) {\n const token = raw.trim().toLowerCase();\n if (!token || seen.has(token)) continue;\n seen.add(token);\n allowed.push(token);\n }\n return {\n label: input.label,\n type: \"entity_reference\",\n allowed_types: allowed,\n multi: input.multi ?? false,\n required: input.required ?? false,\n };\n}\n\n/** The sentence the panel shows before it lets a person save, or `null` when nothing is missing. */\nexport function whatIsMissingForEntityReference(allowedTypes: readonly string[]): string | null {\n return allowedTypes.some((t) => t.trim() !== \"\") ? null : ENTITY_REFERENCE_KINDS_MISSING;\n}\n\nexport interface EntityReferenceKindPickerProps {\n /** The chosen entity tokens (`config.allowed_types`). */\n value: readonly string[];\n onChange: (next: string[]) => void;\n /**\n * An existing column: the store keeps its kinds and this panel sends no change to them,\n * so the list is shown read-only rather than as a control that silently does nothing.\n */\n locked?: boolean;\n className?: string;\n}\n\nfunction matches(kind: EntityReferenceKind, q: string): boolean {\n if (q === \"\") return true;\n return (\n kind.label.toLowerCase().includes(q) ||\n kind.token.toLowerCase().includes(q) ||\n kind.category.toLowerCase().includes(q)\n );\n}\n\nexport function EntityReferenceKindPicker({ value, onChange, locked = false, className }: EntityReferenceKindPickerProps) {\n const { data, loading, error } = useEntityReferenceKinds();\n const [query, setQuery] = useState(\"\");\n const chosen = useMemo(() => new Set(value), [value]);\n const labelOf = useMemo(() => {\n const m = new Map<string, string>();\n for (const k of data ?? []) m.set(k.token, k.label);\n return m;\n }, [data]);\n\n const groups = useMemo(() => {\n const q = query.trim().toLowerCase();\n const byCategory = new Map<string, EntityReferenceKind[]>();\n for (const k of data ?? []) {\n if (!matches(k, q)) continue;\n const list = byCategory.get(k.category) ?? [];\n list.push(k);\n byCategory.set(k.category, list);\n }\n return [...byCategory.entries()].sort(([a], [b]) => a.localeCompare(b));\n }, [data, query]);\n\n const toggle = (token: string, on: boolean) => {\n if (locked) return;\n if (on) onChange(chosen.has(token) ? [...value] : [...value, token]);\n else onChange(value.filter((t) => t !== token));\n };\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)}>\n <Label className=\"text-xs\">What it points at</Label>\n {value.length > 0 ? (\n <div className=\"flex flex-wrap gap-1\" aria-label=\"Chosen kinds\">\n {value.map((token) => (\n <Badge key={token} variant=\"secondary\" className=\"gap-1 text-[11px]\">\n {labelOf.get(token) ?? token}\n {locked ? null : (\n <button\n type=\"button\"\n className=\"ml-0.5 rounded-sm px-0.5 opacity-70 hover:opacity-100\"\n aria-label={`Remove ${labelOf.get(token) ?? token}`}\n onClick={() => toggle(token, false)}\n >\n ×\n </button>\n )}\n </Badge>\n ))}\n </div>\n ) : null}\n {locked ? (\n <p className=\"text-[11px] text-muted-foreground\">\n The kinds an existing column points at are kept as they are; add a new column to point at others.\n </p>\n ) : error ? (\n <RefusalNotice error={error} />\n ) : loading ? (\n <Skeleton className=\"h-24 w-full\" />\n ) : (\n <>\n <BasicInput\n aria-label=\"Find a kind of thing\"\n placeholder=\"Find a kind — note, web site, agent…\"\n className=\"text-xs\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n />\n <div className=\"max-h-56 overflow-y-auto rounded-md border border-border p-2\" role=\"group\" aria-label=\"Kinds of thing\">\n {groups.length === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">No kind of thing matches “{query.trim()}”.</p>\n ) : (\n groups.map(([category, kinds]) => (\n <div key={category} className=\"mb-2 last:mb-0\">\n <p className=\"mb-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground\">{category}</p>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-2\">\n {kinds.map((k) => (\n <label key={k.token} className=\"flex items-center gap-1.5 text-xs\">\n <Checkbox\n checked={chosen.has(k.token)}\n aria-label={k.label}\n onCheckedChange={(v) => toggle(k.token, v === true)}\n />\n {k.label}\n </label>\n ))}\n </div>\n </div>\n ))\n )}\n </div>\n {value.length === 0 ? (\n <p className=\"text-[11px] text-muted-foreground\">{ENTITY_REFERENCE_KINDS_MISSING}</p>\n ) : null}\n </>\n )}\n </div>\n );\n}\n","\"use client\";\n\n// SourceArchivedNotice.tsx — @ai-matrx/records-ui\n//\n// CHAIR-ROLLUP-HONEST (Law 4). Column settings for a lookup or roll-up asks the store whether a\n// column it reads is archived (`custom.field_source_archived`): the link it reads through, the\n// linking column of a back-link on another table, or the far column it totals. When one is, the\n// panel names it and offers ONE click to bring it back through the existing door\n// (`custom.field_restore`), after which every screen on both tables re-reads and the values return.\n// Nothing is drawn while every source is live.\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Button } from \"@ai-matrx/design-system\";\nimport type { RecordsError, SourceArchived, Uuid } from \"@ai-matrx/records\";\nimport { tableShapeChanged, useRecordsClient } from \"@ai-matrx/records/react\";\nimport { RefusalNotice } from \"./Refusal\";\nimport { SOURCE_ARCHIVED_WORDS, sourceArchivedSentence } from \"./values\";\n\n/** The restore button's words: \"Bring back Patient\". */\nexport function bringBackLabel(state: SourceArchived): string {\n return state.label ? `Bring back ${state.label}` : \"Bring it back\";\n}\n\nexport function SourceArchivedNotice({ fieldId, tableId }: { fieldId: Uuid; tableId: Uuid }) {\n const client = useRecordsClient();\n const [state, setState] = useState<SourceArchived | null>(null);\n const [busy, setBusy] = useState(false);\n const [refused, setRefused] = useState<RecordsError | null>(null);\n\n const read = useCallback(async () => {\n const answer = await client.fieldSourceArchived({ field_id: fieldId });\n if (answer.ok) setState(answer.data);\n else setRefused(answer.error);\n }, [client, fieldId]);\n\n useEffect(() => {\n void read();\n }, [read]);\n\n if (refused && !state) return <RefusalNotice error={refused} />;\n if (!state) return null;\n\n const restore = async () => {\n if (!state.field_id) return;\n setBusy(true);\n setRefused(null);\n const done = await client.fieldRestore({ field_id: state.field_id });\n setBusy(false);\n if (!done.ok) {\n setRefused(done.error);\n return;\n }\n if (state.table_id) tableShapeChanged(state.table_id);\n tableShapeChanged(tableId);\n await read();\n };\n\n return (\n <div\n className=\"flex flex-wrap items-center gap-2 rounded-md border border-border px-3 py-2\"\n data-testid=\"source-archived-notice\"\n data-field-id={state.field_id ?? \"\"}\n >\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <span className=\"text-sm\">{SOURCE_ARCHIVED_WORDS}</span>\n <span className=\"truncate text-xs text-muted-foreground\">{sourceArchivedSentence(state)}</span>\n </div>\n {state.field_id ? (\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" disabled={busy} onClick={() => void restore()}>\n {bringBackLabel(state)}\n </Button>\n ) : null}\n {refused ? <RefusalNotice error={refused} className=\"basis-full\" /> : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/values.tsx — @ai-matrx/records-ui\n//\n// HOW A VALUE IS SHOWN, one function, used by the grid cell, the peek, the\n// custom-fields section and the form's read state alike. Per SCR it is never\n// per-feature: every surface that shows a Value in this platform shows it the\n// same way, because the way is a property of the Field, not of the screen.\n//\n// VAL-2: a blank is never unexplained. When the record's envelope says why a\n// value is missing, the reason is what is shown — \"never asked\" and \"refused\"\n// are different facts and a person acts on them differently.\n\nimport { PersonChip } from \"./personChip\";\nimport { SWATCH_CLASS, formatColumnValue } from \"@ai-matrx/design-system/data-table\";\nimport { formatFieldValue, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { Field, HiddenFieldNotice, RecordDocument, ValueEnvelope } from \"@ai-matrx/records\";\nimport { WITHHELD_WORD, WithheldValue, withheldNoticeOf, withheldSentence } from \"./withheld\";\nimport { rowName } from \"./names\";\nimport { Badge, cn } from \"@ai-matrx/design-system\";\nimport { editorKindFor } from \"./parity\";\nimport { dateFormatFor, dateText, isDateField, systemStampOf } from \"./dates\";\nimport { useEmbeddedLook, type EmbeddedLook } from \"./embeddedLook\";\nimport { isId, useLabelWait, useRecordLabels, type LabelLookup } from \"./labels\";\nimport { ABSENCE_WORD_LABEL } from \"./enumLabels\";\nimport { entityReferenceText } from \"./EntityReferenceControl\";\nimport { wholeValueOf } from \"@ai-matrx/records/core\";\nimport { WholeValueCell } from \"./WholeValue\";\nimport { choiceChipLookOf } from \"./choiceLooks\";\nimport { formatPhone } from \"@ai-matrx/design-system/field-formats\";\nimport { FormattedValue, linkChipText } from \"./formattedValue\";\nimport { formatForField, shownAsOf } from \"./presentation\";\nimport { useRecordsUi } from \"./host\";\nimport { AttachmentChips } from \"./gridAttachments\";\nimport { KindValueCell, ReferenceChip, ReferenceChips, referencesOf } from \"./ReferenceChips\";\nimport { ClampedChips } from \"./ClampedChips\";\nimport { kindValueOf, kindValueWords } from \"./kindValues\";\nimport { formulaHasNothingToWorkOn, formulaSourceArchived } from \"./formulaNames\";\nimport { SignatureValue, isSignatureField, signatureWords } from \"./signature\";\nimport { autonumberPrefixOf, autonumberWords, isButtonField, newerKindWords, sourceArchivedOf, type SourceArchived } from \"@ai-matrx/records\";\nimport { ButtonValue } from \"./buttonCell\";\nimport { newerKindValue, statusMarkOf } from \"./newerKindValues\";\nimport { KeptAsideValue, WorkedOutError, keptAsideFor, workedOutErrorFor } from \"./cellMarks\";\n\n/** A status choice's group mark (lane 10 P4), before its words on the chip. */\nfunction statusMark(field: Field, item: unknown, document?: RecordDocument) {\n const mark = statusMarkOf(field, item, document as Record<string, unknown> | undefined);\n return mark ? (\n <span aria-label={mark.words} title={mark.words} className=\"mr-1\" data-records-status-group={mark.group}>\n {mark.mark}\n </span>\n ) : null;\n}\n\n/** The envelope for one key, when the document carries one. */\nexport function envelopeFor(document: RecordDocument | undefined, key: string): ValueEnvelope | undefined {\n const block = document?._values as Record<string, ValueEnvelope> | undefined;\n return block?.[key];\n}\n/** The identifier a relation cell held before it moved, when its target no longer existed. */\nexport function unresolvedFor(document: RecordDocument | undefined, key: string): string | undefined {\n const sources = document?._sources as Record<string, { unresolved?: Record<string, unknown> }> | undefined;\n if (!sources || typeof sources !== \"object\") return undefined;\n for (const source of Object.values(sources)) {\n const held = source?.unresolved?.[key];\n if (typeof held === \"string\" && held) return held;\n if (Array.isArray(held) && held.length) return held.map(String).join(\", \");\n }\n return undefined;\n}\n\n/** A worked-out column that actually carries something to work out. */\nfunction hasFormula(field: Field): boolean {\n const config = (field.config ?? {}) as Record<string, unknown>;\n return Boolean(config.expr) || Boolean(String(config.formula_text ?? \"\").trim());\n}\n\n/**\n * WHY A WORKED-OUT COLUMN IS EMPTY, by its own kind and THIS record (lane VIEWS-AND-FIELDS W1-B\n * item 6) — the census of every column the store works out:\n * · a lookup reads from the record its link holds: no link → \"Pick a linked record\"; a link\n * whose value is empty → \"Empty on the linked record\";\n * · a rollup or a count works over the records its link holds: none → \"No linked records yet\";\n * some, with nothing worked out → a count reads its own 0, a total \"—\" (\"Nothing to add up\");\n * · a formula with no formula yet says so in words; with one, and the store's stamps, plain \"—\".\n * With no record to look at, a lookup or rollup is a plain \"—\" (never a guessed reason).\n * `words` replaces the dash; `sentence` is drawn in its place in italics; `why` is the tooltip.\n * `null`: not a worked-out column.\n */\nexport function computedEmptyOf(\n field: Field,\n document?: Record<string, unknown> | null,\n): { kind: \"lookup\" | \"rollup\" | \"count\" | \"formula\" | \"stamp\"; why?: string; sentence?: string; words?: string } | null {\n const kind = editorKindFor(field);\n const config = (field.config ?? {}) as Record<string, unknown>;\n if (kind === \"lookup\" || kind === \"rollup\") {\n const via = typeof config[\"via\"] === \"string\" ? config[\"via\"] : null;\n const held = document && via ? document[via] : undefined;\n const known = Boolean(document && via);\n const linked = !(held === null || held === undefined || held === \"\" || (Array.isArray(held) && held.length === 0));\n const count = kind === \"rollup\" && config[\"agg\"] === \"count\";\n const which = kind === \"lookup\" ? \"lookup\" : count ? \"count\" : \"rollup\";\n if (!known) return { kind: which };\n if (kind === \"lookup\") return { kind: which, why: linked ? \"Empty on the linked record\" : \"Pick a linked record\" };\n if (!linked) return { kind: which, why: \"No linked records yet\" };\n return count ? { kind: which, words: \"0\" } : { kind: which, why: \"Nothing to add up\" };\n }\n if (kind !== \"formula\" && field.type !== \"formula\") return null;\n if (typeof config[\"system\"] === \"string\") return { kind: \"stamp\" };\n if (!hasFormula(field)) return { kind: \"formula\", sentence: \"Worked out once its formula is in place\" };\n return { kind: \"formula\" };\n}\n\n/** The cell words for a lookup or roll-up whose source is archived (CHAIR-ROLLUP-HONEST). */\nexport const SOURCE_ARCHIVED_WORDS = \"Source archived\";\n\n/** What it is that was archived, for a tooltip: \"Patient on Appointments is archived\". */\nexport function sourceArchivedSentence(state: SourceArchived): string {\n if (!state.label) return \"A column it reads is archived\";\n return state.table ? `${state.label} on ${state.table} is archived` : `${state.label} is archived`;\n}\n\n/**\n * A LOOKUP OR ROLL-UP WHOSE SOURCE IS ARCHIVED (CHAIR-ROLLUP-HONEST, Law 4): the store answers a\n * typed state in the value's place (`sourceArchivedOf`), never a 0. The cell says so in two words\n * and names the archived column on hover; Column settings carries \"Bring back\".\n */\nexport function SourceArchivedValue({ state }: { state: SourceArchived }) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={sourceArchivedSentence(state)} data-records-source-archived={state.field_id ?? \"\"}>\n {SOURCE_ARCHIVED_WORDS}\n </span>\n );\n}\n\n// THE one map — see `enumLabels.ts`.\nexport const ABSENCE_WORDS: Record<string, string> = ABSENCE_WORD_LABEL;\n\nexport function renderValue(field: Field, value: unknown, document?: RecordDocument, labels?: LabelLookup, stillWaitingFor?: string | null, look?: EmbeddedLook | null) {\n const archivedSource = sourceArchivedOf(value);\n if (archivedSource) return <SourceArchivedValue state={archivedSource} />;\n const envelope = envelopeFor(document, field.key);\n if (envelope?.absent) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={`VAL-2: ${envelope.absent}`}>\n {ABSENCE_WORDS[String(envelope.absent)] ?? String(envelope.absent)}\n </span>\n );\n }\n if (value === null || value === undefined || value === \"\") {\n // VAL-2 AGAIN, FOR TWO BLANKS A DASH WOULD LIE ABOUT (VERIFIER-16, 2026-09-23).\n // A relation cell that pointed at a record which no longer exists moved EMPTY — the store\n // refuses a relation to nothing — and the id it held is kept on the record's own\n // provenance entry (`_sources.<ptr>.unresolved.<key>`). A dash there says \"nobody filled\n // this in\", which is false: somebody did, and what they chose is gone.\n const gone = unresolvedFor(document, field.key);\n if (gone) {\n return (\n <span className=\"text-xs italic text-muted-foreground\" title={`It pointed at ${gone}`}>\n The record this pointed at no longer exists\n </span>\n );\n }\n // A FORMULA OVER A COLUMN WHOSE SOURCE IS ARCHIVED says so, never a blank (v7 item 7).\n const archivedInput = formulaSourceArchived(field, document as Record<string, unknown> | undefined);\n if (archivedInput) return <SourceArchivedValue state={archivedInput} />;\n // A WORKED-OUT COLUMN'S EMPTY STATE IS ITS OWN KIND'S (`computedEmptyOf`): a lookup is empty\n // because no linked record is picked, never because \"its formula\" is missing.\n const computed = computedEmptyOf(field, document as Record<string, unknown> | undefined);\n if (computed?.sentence) return <span className=\"text-xs italic text-muted-foreground\">{computed.sentence}</span>;\n if (computed?.words) return <span data-records-empty-why={computed.kind}>{computed.words}</span>;\n if (computed?.why) {\n return (\n <span className=\"text-muted-foreground\" title={computed.why} data-records-empty-why={computed.kind}>\n —\n </span>\n );\n }\n // EMBEDDED (`embeddedLook.ts`): a plain empty cell is blank, as Notion's is.\n if (look?.blankEmpty) return null;\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n // A SIGNATURE IS SEEN AS ITS DRAWING (or the signer's name a sealed document wrote), never as\n // the image's data text (`signature.tsx`).\n if (isSignatureField(field)) return <SignatureValue value={value} fieldKey={field.key} document={document} />;\n\n if (isButtonField(field)) return <ButtonValue field={field} />;\n // THE NEWER KINDS (lane 10 P4) draw in their own shape (`newerKindValues.tsx`).\n const newer = newerKindValue(field, value);\n if (newer !== undefined) return newer;\n\n // A VALUE TOO BIG FOR ONE CELL: the words it keeps, and the way to the whole text (`WholeValue.tsx`).\n const whole = typeof value === \"string\" ? wholeValueOf(document, field.key) : null;\n if (whole) return <WholeValueCell words={value as string} pointer={whole} />;\n\n const kind = editorKindFor(field);\n // A REFERENCE IS A CHIP THAT OPENS WHAT IT NAMES (lane REFERENCE-CARRY): a relation's records and\n // an entity reference's platform things alike (`ReferenceChips.tsx`).\n if (kind === \"relation\" || kind === \"entity_reference\") {\n return <ReferenceChips refs={referencesOf(field, value, kind, labels)} waiting={stillWaitingFor} />;\n }\n // A VALUE THAT NAMES ITS OWN SHAPE — `__kind` JSON, or a Matrx directive stored before the Kind\n // Directives merge (```matrx {\"matrx_version\":1,…}```) — is drawn by the kind system, never as\n // the raw fence (Arman, Department table, 2026-09-28).\n // A PERSON IS A PERSON CHIP, never the link chip (`personChip.tsx`, night walk 2026-10-06).\n if (kind === \"member\") {\n const ids = (Array.isArray(value) ? value : [value]).filter((v) => v !== null && v !== undefined && v !== \"\");\n return (\n <span className=\"flex min-w-0 flex-wrap gap-1\" data-records-person-chips=\"\">\n {ids.map((id, i) => (\n <PersonChip key={`${String(id)}-${i}`} name={scalarText(field, id, labels, stillWaitingFor)} />\n ))}\n </span>\n );\n }\n const kv = kind === \"attachment\" ? null : kindValueOf(value);\n if (kv) return <KindValueCell kv={kv} where=\"cell\" title={field.label} />;\n // A CHOICE WEARS THE COLOUR ITS COLUMN KEEPS FOR IT (`choiceLooks.ts`) — never a colour hashed\n // from its word — as a chip whose words can be read in both themes (`CHOICE_CHIP_CLASS`, lane C,\n // review 2026-09-26: white words on pale fills measured ~1.1:1). A choice the column keeps no\n // colour for is a NEUTRAL chip, never bare text.\n const chosen = kind === \"select\" || kind === \"multi_select\";\n const chipOf = (item: unknown): { className: string; tinted: boolean; dot: string } => {\n const chipLook = choiceChipLookOf(field, item, scalarText(field, item, labels));\n return { className: chipLook.className, tinted: chipLook.color !== null, dot: SWATCH_CLASS[chipLook.color ?? \"gray\"] };\n };\n if (chosen) {\n const items = Array.isArray(value) ? value : [value];\n return (\n <span className=\"flex flex-wrap gap-1\" data-records-choice-chips=\"\">\n {items.map((item, i) => {\n const chip = chipOf(item);\n return (\n <Badge\n key={`${String(item)}-${i}`}\n variant=\"outline\"\n className={cn(\"text-[11px]\", chip.className)}\n data-records-choice-chip=\"\"\n {...(chip.tinted ? { \"data-records-choice-tint\": \"\" } : {})}\n >\n {look?.choiceDot ? <span aria-hidden=\"true\" data-matrx-pill-ink=\"\" data-records-choice-dot=\"\" className={cn(\"mr-1.5 inline-block size-1.5 shrink-0 rounded-full\", chip.dot)} /> : null}\n {statusMark(field, item, Array.isArray(value) ? undefined : document)}\n {scalarText(field, item, labels, Array.isArray(value) ? undefined : stillWaitingFor)}\n </Badge>\n );\n })}\n </span>\n );\n }\n // A FILE READS AS ITS NAME AND OPENS WHERE THE HOST KEEPS IT (`gridAttachments.tsx`).\n if (kind === \"attachment\") return <AttachmentChips value={value} />;\n if (Array.isArray(value)) {\n return (\n <span className=\"flex flex-wrap gap-1\">\n {value.map((item, i) => (\n <Badge key={`${String(item)}-${i}`} variant=\"secondary\" className=\"text-[11px]\">\n {scalarText(field, item, labels)}\n </Badge>\n ))}\n </span>\n );\n }\n if (kind === \"url\" && typeof value === \"string\") {\n // A LINK IS A CHIP NAMING WHERE IT GOES (lane C, review 2026-09-26 F1–F7: \"A URL column shows\n // raw image URLs\"): the site and the file, the whole address on hover. Airtable's link chip.\n const href = value.includes(\"://\") ? value : `https://${value}`;\n return (\n <a\n className=\"inline-flex min-w-0 max-w-full items-center gap-1 rounded-md border border-border bg-muted/60 px-1.5 py-0.5 text-[11px] text-foreground hover:bg-accent\"\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n title={value}\n data-records-link-chip=\"\"\n onClick={(event) => event.stopPropagation()}\n >\n <span aria-hidden=\"true\" className=\"text-muted-foreground\">↗</span>\n <span className=\"truncate\">{linkChipText(value)}</span>\n </a>\n );\n }\n if (kind === \"phone\" && typeof value === \"string\" && value.trim() !== \"\") {\n return (\n <a\n className=\"truncate tabular-nums text-primary underline-offset-2 hover:underline\"\n href={`tel:${value.replace(/[^\\d+]/g, \"\")}`}\n title={value}\n data-records-phone=\"\"\n onClick={(event) => event.stopPropagation()}\n >\n {formatPhone(value)}\n </a>\n );\n }\n if (kind === \"email\" && typeof value === \"string\") {\n return (\n <a className=\"truncate text-primary underline-offset-2 hover:underline\" href={`mailto:${value}`}>\n {value}\n </a>\n );\n }\n if (typeof value === \"boolean\") {\n // LIMITS-FIX 2026-09-21: a tick box reads as a tick wherever it is only READ — a peek,\n // a portal, a form's answered state. The grid draws the real control instead, because\n // there a person expects to change it. (An UNANSWERED tick box never reaches here: it\n // has no value and left through the blank branch above, which is the third state.)\n return (\n <span className={kind === \"checkbox\" ? \"text-sm\" : \"\"} title={value ? \"Yes\" : \"No\"}>\n {value ? \"✓\" : \"—\"}\n </span>\n );\n }\n return <span className={cn(\"truncate\", kind === \"number\" || kind === \"currency\" || kind === \"percent\" ? \"tabular-nums\" : \"\")}>{scalarText(field, value, labels, stillWaitingFor)}</span>;\n}\n\n/**\n * The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1\n * says both change the MEANING — and with an id resolved to the NAME of the\n * record it points at.\n *\n * `labels` is the resolver from `RecordLabelProvider`. Without it, an id is\n * drawn as \"Loading…\" and never as itself: a 36-character identifier in a cell\n * reads like a value, and the 19 September verdict found it in choice cells,\n * relation cells and as every Kanban column heading.\n */\nexport function scalarText(\n field: Field,\n value: unknown,\n labels?: LabelLookup,\n /**\n * WHAT THIS COLUMN IS WAITING FOR, once it has been looking long enough to owe\n * a sentence (`useLabelWait`). \"Loading…\" is honest for a moment and a lie with\n * a spinner on it after that: VERIFIER-8 MEDIUM-1 watched a whole relation\n * column say it for 10-13 seconds while the rest of the grid sat readable\n * behind it, and nothing on screen said what it was waiting for.\n */\n stillWaitingFor?: string | null,\n): string {\n if (value === null || value === undefined) return \"—\";\n if (sourceArchivedOf(value)) return SOURCE_ARCHIVED_WORDS;\n // A drawn signature reads as \"Signed\" wherever only words fit (a card title, a sentence).\n if (isSignatureField(field)) return signatureWords(value) ?? \"—\";\n // NOTION-PROPS-3: a record number reads with its prefix (TASK-42) wherever only words fit.\n if (autonumberPrefixOf(field)) return autonumberWords(field, value) ?? String(value);\n // The newer kinds' own words (lane 10 P4): an address on one line, h:mm, who by name, 3 / 5.\n const newerWords = newerKindWords(field, value);\n if (newerWords !== null) return newerWords;\n const kind = editorKindFor(field);\n // SC-R: a reference to a platform thing reads as the thing's own words (withheld ones said so).\n if (kind === \"entity_reference\") return entityReferenceText(value);\n // A many-relation reads as its records' names, never \"2 of them\" (lane REFERENCE-CARRY) — and a\n // SEVERAL-CHOICE value reads as its choices' words the same way (BREAKER-2 B2-19: a board grouped\n // by Body Areas titled one column \"1 of them\").\n if ((kind === \"relation\" || field.type === \"list\") && Array.isArray(value)) {\n return value.map((item) => scalarText(field, item, labels, stillWaitingFor)).join(\", \");\n }\n // A kind value in words: its items' own names, else what it is (`kindValues.ts`).\n const kv = kindValueOf(value);\n if (kv) return kindValueWords(kv);\n if (isId(value) && (field.type === \"list\" || field.type === \"relation\")) {\n return labels?.(field, String(value)) ?? stillWaitingFor ?? \"Loading…\";\n }\n // A CHOICE HELD BY ITS KEY reads as its option's words (DATA-V2-BASICS-2): the key never\n // reaches a person. Until the options are read the column's own \"Shows as\" answers below.\n if (field.type === \"list\" && typeof value === \"string\" && labels) {\n const words = labels(field, value);\n if (words) return words;\n }\n // A column's own \"Shows as\" (tranche 6e) words a card and a sentence the way the grid shows it.\n const shownAs = shownAsOf(field);\n if (shownAs) {\n const said = formatFieldValue(value, shownAs);\n if (said.ok && !said.empty) return said.text;\n }\n if (typeof value === \"number\") {\n if (kind === \"percent\") return `${value}%`;\n // The symbol goes in FRONT of an amount of money and a unit goes AFTER a\n // quantity: `$3` and `3 units`. Before this, `editorKindFor` called any\n // range field with a unit longer than one character a currency, so three\n // things measured in units rendered as \"units3\".\n if (kind === \"currency\") return field.unit ? `${field.unit}${value.toLocaleString()}` : value.toLocaleString();\n return field.unit ? `${value.toLocaleString()} ${field.unit}` : value.toLocaleString();\n }\n // A DATE IS READ BY THE ONE HELPER (`dates.ts`), the same registry the grid prints with:\n // a bare `2026-04-01` is April 1st in every zone, never UTC midnight moved to March 31st.\n // The store's own Created / Last changed stamps come through here too.\n if (kind === \"datetime\" || systemStampOf(field) === \"created_time\" || systemStampOf(field) === \"modified_time\") {\n const said = dateText(field, value);\n if (said !== null) return said;\n }\n // NEVER A JSON DUMP IN A CELL. A value with a shape a column cannot draw is\n // described; the raw document is available on the record panel, which is\n // where a person goes to look at it.\n if (Array.isArray(value)) return value.length === 0 ? \"\" : `${value.length} of them`;\n if (typeof value === \"object\") return \"…\";\n return String(value);\n}\n\n/** The provenance badge a value carries when the store interned a source for it (SCR-27). */\nexport function ProvenanceBadge({ document, fieldKey }: { document: RecordDocument | undefined; fieldKey: string }) {\n const envelope = envelopeFor(document, fieldKey);\n if (!envelope?.src) return null;\n // A value kept as a file: the cell already says so and opens it (WholeValue.tsx); its pointer's\n // raw fields are not a provenance a person reads.\n if (wholeValueOf(document, fieldKey)) return null;\n const sources = document?._sources as Record<string, Record<string, unknown>> | undefined;\n const source = sources?.[envelope.src];\n const label = source ? Object.values(source).map(String).join(\" · \") : envelope.src;\n return (\n <Badge variant=\"outline\" className=\"text-[10px] font-normal\" title={`Written by ${envelope.actor ?? \"?\"}${envelope.at ? ` at ${envelope.at}` : \"\"}`}>\n {label}\n </Badge>\n );\n}\n\n/**\n * THE VALUE, AS A COMPONENT, so a cell can resolve the ids it holds.\n *\n * `renderValue` is a plain function called from inside a column's `cell`\n * callback and from a dozen other places; a function cannot ask the resolver\n * for a name, because asking is a hook. Every read-only surface therefore draws\n * through this instead, and the one that needs the raw function (a plain-text\n * export, a chat line) keeps calling `renderValue` with no resolver and says\n * \"Loading…\" rather than printing an id.\n */\nexport function RecordValue({\n field,\n value,\n document,\n format,\n withheld,\n inCell,\n recordId,\n}: {\n field: Field;\n value: unknown;\n document?: RecordDocument | undefined;\n /**\n * WHOSE VALUE THIS IS. A drawn signature a form sent is kept as a File the value's source names,\n * and the read doors give the value without its source — so the signature reader asks for it by\n * the record (`signature.tsx`). Every other kind ignores it.\n */\n recordId?: string | null | undefined;\n /**\n * The column's DECLARED format (`presentation.ts`), when it has one.\n *\n * A cell renderer beats `MatrxColumnDef.format` — the table hands the cell to\n * the consumer and steps back — so a store column that declared `currency`\n * and then drew itself here would have shown a raw `1250.5` while its own\n * header was right-aligned for money. The primitive's formatter is asked for\n * the text instead of a second one being written beside it, so the read view\n * and the table can never disagree about what a number means. THE FALLBACK\n * LAW rides along: a value that does not fit is amber with the reason, never\n * blank.\n */\n format?: FieldFormatConfig | undefined;\n /**\n * THE STORE'S REASON, when it withheld this value from the reader (`ReadRow.hidden[key]`).\n * A withheld value reads \"Withheld\" with the store's sentence on hover — never \"—\", which\n * means the cell is empty (`withheld.tsx`).\n */\n withheld?: HiddenFieldNotice | null | undefined;\n /**\n * Drawn in a GRID CELL. In the merged grid a long-text cell reads through the host's text\n * renderer (`RecordsUiHost.renderText`, slot `cell` — markdown, formatted), clipped to the row;\n * unbound, the words as written.\n */\n inCell?: boolean | undefined;\n}) {\n const ui = useRecordsUi();\n const labels = useRecordLabels(ONE_FIELD_ARRAY_CACHE(field));\n // A CELL THAT IS STILL RESOLVING SAYS WHAT IT IS WAITING FOR — after one\n // second, not immediately: the word \"Loading…\" is honest for the moment it\n // takes, and a lie with a spinner on it after that.\n const stillWaitingFor = useLabelWait(field);\n const embeddedLook = useEmbeddedLook();\n // NOTION-PROPS-3: A BUTTON holds no value — it is drawn as itself and pressed (`buttonCell.tsx`).\n if (isButtonField(field)) return <ButtonValue field={field} recordId={recordId} inCell={inCell} />;\n if (withheld && (value === null || value === undefined)) return <WithheldValue field={field} notice={withheld} />;\n // A WORKED-OUT COLUMN THE STORE COULD NOT WORK OUT says so, with the store's sentence (`cellMarks.tsx`).\n if (value === null || value === undefined) {\n const failed = workedOutErrorFor(document, field.key);\n if (failed) return <WorkedOutError field={field} sentence={failed} floated={Boolean(inCell)} />;\n }\n // A VALUE KEPT ASIDE when its column changed stays where it was in a grid cell, amber, saying why.\n if (inCell) {\n const kept = keptAsideFor(document, field.key);\n if (kept) return <KeptAsideValue field={field} entry={kept} shown={scalarText(field, kept.value)} />;\n }\n const archivedSource = sourceArchivedOf(value);\n if (archivedSource) return <SourceArchivedValue state={archivedSource} />;\n // A WORKED-OUT COLUMN WITH NOTHING TO WORK ON IS EMPTY (review 2, A12): a new row's\n // `{Quote} * 1.08` is blank, never \"$0.00\" (`formulaNames.ts`).\n if (formulaHasNothingToWorkOn(field, document as Record<string, unknown> | undefined)) return embeddedLook?.blankEmpty ? null : <span className=\"text-muted-foreground\">—</span>;\n // THE NEWER KINDS (lane 10 P4) draw in their own shape in every layout (`newerKindValues.tsx`).\n if (value !== null && value !== undefined && value !== \"\" && !envelopeFor(document, field.key)?.absent) {\n const newer = newerKindValue(field, value, { inCell });\n if (newer !== undefined) return <>{newer}</>;\n }\n if (\n inCell &&\n ui.grid === \"merged\" &&\n ui.renderText &&\n typeof value === \"string\" &&\n value.trim() !== \"\" &&\n editorKindFor(field) === \"long_text\" &&\n !shownAsOf(field) &&\n !wholeValueOf(document, field.key) &&\n !envelopeFor(document, field.key)?.absent &&\n // A long-text cell holding a kind is drawn by the kind system below, not as markdown.\n !kindValueOf(value)\n ) {\n // ONE LINE, AT A FIXED HEIGHT (live walk 2026-10-07, \"Note from the client\": a saved three-line\n // note grew its row 35 → 67px, and the markdown placeholder → rendered swap moved it again,\n // 43 → 47). The row is 35px whatever the note holds; the whole text is the peek and the editor.\n return (\n <span className=\"block h-[1.5em] min-w-0 overflow-hidden whitespace-normal\" data-records-cell-text=\"\">\n {ui.renderText(value, \"cell\")}\n </span>\n );\n }\n // A DATE COLUMN PRINTS EACH VALUE IN ITS OWN SHAPE (`dates.ts`): a bare date is a date,\n // a moment is a date and time, whatever the column's kind says — so the grid, the form, the\n // panel and the calendar read one date the same way.\n // THE COLUMN'S OWN \"SHOWS AS\" WHEN THE CALLER NAMED NONE (merge tranche 6e): the record panel,\n // a card and a public page read the Field's format the way the grid does, so a percent kept as\n // 0.45 is 45% everywhere and a rating is stars everywhere.\n // A signature in a grid cell is drawn at the row's height.\n if (isSignatureField(field) && value !== null && value !== undefined && value !== \"\") {\n return <SignatureValue value={value} inCell={inCell} recordId={recordId} fieldKey={field.key} document={document} />;\n }\n // A LINK CELL IS ONE LINE: as many chips as fit, then \"+N\" that opens the whole list.\n if (inCell) {\n const linkKind = editorKindFor(field);\n if (linkKind === \"relation\" || linkKind === \"entity_reference\") {\n const refs = referencesOf(field, value, linkKind, labels);\n if (refs.length > 1) {\n return (\n <ClampedChips\n dataAttr={field.key}\n items={refs.map((r) => ({ key: `${r.token}:${r.id}`, node: <ReferenceChip reference={r} waiting={stillWaitingFor} /> }))}\n />\n );\n }\n }\n }\n const shown = format ?? formatForField(field);\n // THE VALUE'S OWN SHAPE (date or date-and-time) CHOSEN BY `dateFormatFor`, THE COLUMN'S OPTIONS KEPT\n // (`dateStyle: \"long\"` — \"January 1, 2026\"). Taking the shape alone dropped the options, so a long\n // date read medium in every layout.\n const shape = shown && (shown.id === \"date\" || shown.id === \"datetime\") && isDateField(field)\n ? dateFormatFor(field, value)\n : undefined;\n const dated: FieldFormatConfig | undefined = shape\n ? { ...shape, ...(shown?.options ? { options: shown.options } : {}) }\n : undefined;\n const formatted = shown ? formatColumnValue({ format: dated ?? shown }, value) : null;\n // EMBEDDED (`embeddedLook.tsx`): an empty value with a display format is as blank as an unformatted\n // one — it falls through to `renderValue`, which keeps every reason an empty cell may owe.\n if (formatted && !(embeddedLook?.blankEmpty && formatted.empty)) return <FormattedValue value={value} format={dated ?? shown!} />;\n return <>{renderValue(field, value, document, labels, stillWaitingFor, embeddedLook)}</>;\n}\n\n/**\n * `useRecordLabels` takes an array and declares what it is about to draw. A new\n * array literal per cell would re-declare on every render, so each Field gets\n * exactly one array for the life of the process.\n */\nconst ONE_FIELD_ARRAYS = new WeakMap<Field, Field[]>();\nfunction ONE_FIELD_ARRAY_CACHE(field: Field): Field[] {\n const held = ONE_FIELD_ARRAYS.get(field);\n if (held) return held;\n const made = [field];\n ONE_FIELD_ARRAYS.set(field, made);\n return made;\n}\n\n/**\n * WHAT ONE CARD SAYS — the kanban's, the calendar's, the gallery's and the pipeline's alike, so\n * no card can read a record differently from another. `field` is the card's title column\n * (`cardTitleField`); a value the store withheld reads \"Withheld\" and carries the store's reason\n * for the card's hover (`withheld.tsx`), never a bare \"—\".\n */\nexport function cardWords(\n record: { document?: RecordDocument | null; hidden?: Record<string, HiddenFieldNotice> | null } & Parameters<typeof rowName>[0],\n field: Field | undefined,\n labels?: LabelLookup,\n): { text: string; withheld: string | null } {\n if (!field) return { text: rowName(record, null, \"Untitled\"), withheld: null };\n const value = (record.document ?? {})[field.key];\n const notice = withheldNoticeOf(record.hidden, field.key);\n if (notice && (value === null || value === undefined)) {\n return { text: WITHHELD_WORD, withheld: withheldSentence(field, notice) };\n }\n return { text: scalarText(field, value, labels), withheld: null };\n}\n","\"use client\";\n\n// src/embeddedLook.tsx — @ai-matrx/records-ui · CHAIR-EMBEDDED-FIDELITY\n//\n// THE EMBEDDED TABLE'S LOOK, AS NAMED OPTIONS (never free-form styling). `TablePage\n// presentation=\"embedded\"` is the grid a page holds inline, measured against Notion's inline\n// database. Every difference from the full page is ONE option here, switched on by `Grid`\n// when `embedded` and read by the pieces that draw a value:\n//\n// · `blankEmpty` an empty cell is blank, not \"—\" (\"Withheld\" and a worked-out column's reason\n// words stay: they say something a dash would not).\n// · `choiceDot` a choice chip carries a small leading dot in its option's colour.\n// · `plainRelation` a relation cell reads like Notion's: the record's icon (else a page glyph)\n// then its title — no fill, no badge, no coloured underline; hover underlines.\n//\n// Row height and column dividers are classes on the table (`EMBEDDED_TABLE_CLASS`), drawn from\n// the design system's own tokens (`border-border`).\n\nimport { createContext, useContext } from \"react\";\n\nexport interface EmbeddedLook {\n blankEmpty: boolean;\n choiceDot: boolean;\n plainRelation: boolean;\n}\n\nexport const EMBEDDED_LOOK: EmbeddedLook = { blankEmpty: true, choiceDot: true, plainRelation: true };\n\nconst EmbeddedLookContext = createContext<EmbeddedLook | null>(null);\nexport const EmbeddedLookProvider = EmbeddedLookContext.Provider;\n/** The embedded look in force here, or `null` on a full page. */\nexport function useEmbeddedLook(): EmbeddedLook | null {\n return useContext(EmbeddedLookContext);\n}\n\n/**\n * Embedded rows are 40px tall with the value centred in them (as every grid cell is), and thin\n * vertical dividers sit between columns in the existing border token.\n */\nexport const EMBEDDED_TABLE_CLASS = [\n \"[&_tbody_td]:h-10\",\n \"[&_tbody_td]:align-middle!\",\n \"[&_tbody_td]:border-r\",\n \"[&_tbody_td]:border-border\",\n \"[&_tbody_td:last-child]:border-r-0\",\n \"[&_thead_th]:border-r\",\n \"[&_thead_th]:border-border\",\n \"[&_thead_th:last-child]:border-r-0\",\n].join(\" \");\n\n/** With no calculation chosen, the footer holds only the new-row line: no grey band, no rule above it. */\nexport const EMBEDDED_PLAIN_FOOTER_CLASS = \"[&_tfoot]:bg-transparent [&_tfoot]:border-t-0\";\n\n/**\n * HOW MANY ROWS AN EMBEDDED TABLE READS AT A TIME (CHAIR-EMBEDDED-FIDELITY 16): its first page, and\n * each \"Show more\" press brings about this many more — never the whole table. Declared beside the\n * server's first-page builder (`firstPage.ts`), which asks the same first page (lane SSR-ROWS).\n */\nexport { EMBEDDED_PAGE_SIZE } from \"./firstPage\";\n","\"use client\";\n\n// src/labels.tsx — @ai-matrx/records-ui\n//\n// WHAT AN ID IS CALLED, ONCE, FOR EVERY SCREEN THAT DRAWS A VALUE.\n//\n// A choice field stores the ID of an option record and a relation field stores\n// the ID of the record it points at (FLD-5 / FLD-6, REL-1) — that is the store\n// being right, and it is also why the 19 September verdict saw a bare\n// 36-character identifier in a relation cell, in a choice cell, and as the\n// HEADING OF EVERY KANBAN COLUMN. The pickers resolved those ids because each\n// one loaded its own list; the read-only surfaces never did, so the same value\n// read as a name in the form and as a machine id in the grid.\n//\n// One resolver, provided once inside the mount, so every surface gets the same\n// answer and asks the store once per Field rather than once per cell:\n//\n// · a list field → `custom.field_options`, which resolves the options Table\n// from the Field's own config, so no screen has to know which Table it is\n// · a relation field → the read door on the Field's declared target\n//\n// WHAT IT DOES WHILE IT IS LOOKING. It returns `null`, and every caller draws\n// the word \"Loading…\" rather than the id. Showing the id \"until it resolves\" is\n// how the defect got shipped in the first place: it looks like a value.\n\nimport { fieldOptionsOnce } from \"./askOnce\";\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { useRecordsClient, type Field, type Uuid } from \"@ai-matrx/records/react\";\nimport { autonumberPrefixOf, autonumberWords } from \"@ai-matrx/records\";\nimport { newerKindExportWords, optionKey, type RecordDocument, type StoredRecord } from \"@ai-matrx/records\";\nimport { UNREAD_RECORD_LABEL, WITHHELD_RECORD_LABEL, recordName } from \"./names\";\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\nimport { isSignatureField } from \"./docs\";\nimport { signatureWords } from \"./signature\";\n\n/**\n * Answers \"what is the record with this id called\", for one Field's values. The resolver the mount\n * provides also answers `archived` — whether a referenced record sits in Archived items (an archive\n * keeps every reference to it, chair ruling B3-21) — so a chip can draw that state.\n */\nexport type LabelLookup = ((field: Field, id: string) => string | null) & {\n archived?: (field: Field, id: string) => boolean;\n /** The linked record's own icon, and its table's icon for one that has none (same call as the words). */\n icons?: (field: Field, id: string) => { icon: string | null; tableIcon: string | null } | undefined;\n};\n\nconst LabelContext = createContext<{\n lookup: LabelLookup;\n want: (field: Field) => void;\n waiting: (field: Field) => string | null;\n}>({\n // With no provider the resolver is ABSENT, not silently empty: a caller gets\n // null and says \"Loading…\" forever, which is visible. The mount always\n // provides one, so this is only ever a bare unit test.\n lookup: () => null,\n want: () => {},\n waiting: () => null,\n});\n\n/**\n * HOW LONG A CELL MAY SAY \"Loading…\" BEFORE IT HAS TO SAY WHAT IT IS WAITING\n * FOR. One second is the span at which a person stops reading a word as \"this\n * is about to happen\" and starts reading it as \"this is stuck\" — the same line\n * Nielsen's response-time work draws and the one Linear and Stripe design to.\n */\nexport const SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS = 1000;\n\n/**\n * WHAT THIS COLUMN IS WAITING FOR, in a person's words.\n *\n * 🚨 WHY A CELL MAY NOT JUST SAY \"Loading…\" (lane FRONT-DOOR, 2026-09-21;\n * VERIFIER-8 MEDIUM-1). On records-ui 0.57 the whole CUSTOMER column of a\n * 40-row Jobs grid read \"Loading…\" for 10–13 seconds with the rest of the grid\n * drawn and readable behind it. The bulk resolver below has since made that ~0.1 s\n * on the same real table — but \"Loading…\" is a word with no remedy in it, and\n * the moment a target table is big, a network is slow or a reader holds fewer\n * rows than the column points at, it is back to being a dead column that tells\n * nobody anything. A stand-in announces itself: after one second this column\n * says what it went to read.\n */\nfunction waitingLineFor(field: Field, target: string | null): string {\n return field.type === \"list\"\n ? \"Reading this column’s list of choices…\"\n : `Reading the ${target ?? \"records\"} this column points at…`;\n}\n\n/** Which ids a Field's stored value refers to. */\nexport function idsOf(value: unknown): string[] {\n if (Array.isArray(value)) return value.map(String).filter(isId);\n if (typeof value === \"string\" && isId(value)) return [value];\n return [];\n}\n\n/** Where a choice's words are kept under its KEY (ids and keys never collide: a key is no uuid). */\nexport function choiceKeyName(fieldId: string, key: string): string {\n return `${fieldId}\\u0000key\\u0000${key}`;\n}\n\nexport function isId(value: unknown): boolean {\n return typeof value === \"string\" && isUuidShape(value);\n}\n\n/** Whether the grid's own cell copy resolves this column through `shownValue` rather than the raw value. */\nexport function copiesAsWords(field: Field): boolean {\n return pointsAtRecords(field) || isSignatureField(field) || autonumberPrefixOf(field) !== \"\";\n}\n\n/** True when this Field's values are ids of other records rather than values. */\nexport function pointsAtRecords(field: Field): boolean {\n return field.type === \"list\" || field.type === \"relation\";\n}\n\n/**\n * WHAT THE PERSON SEES, NOT WHAT THE STORE KEEPS (GRID-PORT finding, 2026-09-24). A relation or a\n * choice stores the ID of the record it points at; the grid draws that record's words (\"Ojeda\n * residence\", \"Scheduled\"), and the older grid's export wrote those words too. So an exported,\n * copied or Copy-for-AI cell carries the same words the grid shows: each id resolved through the one label resolver the\n * grid uses (`useRecordLabels`). An id nobody could resolve stays the id, rather than a blank that\n * would claim the cell was empty. A worked-out column already holds the store's worked-out value.\n */\nexport function shownValue(field: Field, value: unknown, labels?: LabelLookup): unknown {\n // A DRAWN SIGNATURE is \"Signed\" wherever words are copied or exported — never its image data\n // (a spreadsheet cell cannot show it, and Excel cuts a cell at 32,767 characters). A name a\n // sealed document wrote stays the name (`signature.tsx`).\n if (isSignatureField(field)) return signatureWords(value);\n // NOTION-PROPS-3: a record number is copied as it is shown, with its prefix (TASK-42).\n if (autonumberPrefixOf(field)) return autonumberWords(field, value) ?? value;\n // An address, a length of time, who made it — copied and exported in words (lane 10 P4).\n const newerWords = value === null || value === undefined ? null : newerKindExportWords(field, value);\n if (newerWords !== null) return newerWords;\n if (!labels || !pointsAtRecords(field)) return value;\n const ids = idsOf(value);\n if (ids.length === 0) return value;\n const words = ids.map((id) => labels(field, id) ?? id);\n return Array.isArray(value) ? words : words[0];\n}\n\nexport function RecordLabelProvider({ children }: { children: ReactNode }) {\n const client = useRecordsClient();\n const [names, setNames] = useState<Record<string, string>>({});\n /** `${field.id}:${id}` of every referenced record the store says is archived. */\n const [archivedRefs, setArchivedRefs] = useState<Record<string, true>>({});\n /** id → the record's icon and its table's icon, learned with its words. */\n const [iconsOf, setIconsOf] = useState<Record<string, { icon: string | null; tableIcon: string | null }>>({});\n // Which Fields have FINISHED looking. Until a Field is in here its ids are\n // still loading; once it is in here, an id that is still missing is missing\n // for a reason, and the reason is asked for rather than waited out.\n const [settled, setSettled] = useState<Record<string, true>>({});\n /** Per Field: the sentence a cell shows once it has waited long enough to owe one. */\n const [waitingLines, setWaitingLines] = useState<Record<string, string>>({});\n const asked = useRef<Set<string>>(new Set());\n const chased = useRef<Set<string>>(new Set());\n const timers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n /** Start this Field's one-second clock. Cleared the moment it settles. */\n const startWaitClock = useCallback((field: Field, target: string | null) => {\n if (timers.current.has(field.id)) return;\n timers.current.set(\n field.id,\n setTimeout(() => {\n timers.current.delete(field.id);\n setWaitingLines((current) =>\n current[field.id] ? current : { ...current, [field.id]: waitingLineFor(field, target) },\n );\n }, SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS),\n );\n }, []);\n\n const stopWaitClock = useCallback((fieldId: string) => {\n const timer = timers.current.get(fieldId);\n if (timer) {\n clearTimeout(timer);\n timers.current.delete(fieldId);\n }\n setWaitingLines((current) => {\n if (!current[fieldId]) return current;\n const next = { ...current };\n delete next[fieldId];\n return next;\n });\n }, []);\n\n useEffect(\n () => () => {\n for (const timer of timers.current.values()) clearTimeout(timer);\n timers.current.clear();\n },\n [],\n );\n\n const want = useCallback(\n (field: Field) => {\n if (!pointsAtRecords(field)) return;\n if (asked.current.has(field.id)) return;\n asked.current.add(field.id);\n startWaitClock(field, null);\n\n void (async () => {\n if (field.type === \"list\") {\n const result = await fieldOptionsOnce(client, field.id);\n if (result.ok) {\n setNames((current) => {\n const next = { ...current };\n for (const option of result.data ?? []) {\n const words = recordName(option.data as RecordDocument | undefined, null, \"Unnamed choice\");\n next[option.id] = words;\n // A CHOICE HELD BY ITS KEY READS AS ITS WORDS TOO (DATA-V2-BASICS-2): a moved list\n // and the enum nudge's Add keep `backordered`, and the grid printed the key.\n const key = optionKey(option as unknown as StoredRecord);\n if (key) next[choiceKeyName(field.id, key)] = words;\n }\n return next;\n });\n }\n setSettled((current) => ({ ...current, [field.id]: true }));\n stopWaitClock(field.id);\n return;\n }\n // ── A RELATION'S WORDS ARE THE STORE'S ANSWER, NOT THIS FILE'S (lane\n // RELATION-DISPLAY-2, 2026-09-21). ───────────────────────────────────────────\n // This branch used to read 200 rows of the target Table plus `tableList()`, find\n // the Table's `title_field` and name every row itself. That was one of three\n // copies of the same derivation, and it had three faults nobody could fix here:\n //\n // · IT COULD NOT SEE A DISPLAY SPEC. REL-DISP lets a column say it shows\n // `first_name` + \" \" + `last_name`; this code knew only `title_field`, so\n // Rincon Plumbing's two Maria Chens stayed two identical chips no matter\n // what the column was configured to show.\n // · A 200-ROW CEILING. The 201st customer was never in the prefetch and fell\n // through to the per-id chase, so a big table quietly changed how it resolved.\n // · IT NAMED WHAT IT COULD READ. The read-access ladder runs inside the store's\n // `custom._words_for`; a name assembled out here has already been read.\n //\n // So the relation branch fetches NOTHING up front. It settles immediately, and\n // the ids the page actually draws go through the queue below into ONE\n // `relation_words_many` call per Field per tick — the store's own resolver,\n // this column's own display spec, the ladder asked before the name is read.\n if (!field.relation_target) {\n setSettled((current) => ({ ...current, [field.id]: true }));\n stopWaitClock(field.id);\n return;\n }\n setSettled((current) => ({ ...current, [field.id]: true }));\n })();\n },\n [client, startWaitClock, stopWaitClock],\n );\n\n // ── WHAT AN ID IS CALLED IS THE STORE'S QUESTION (RELATION-DECLARE 2026-09-20 ·\n // FRONT-DOOR 2026-09-21 · RELATION-DISPLAY-2 2026-09-21). ────────────────────────────\n //\n // A relation joins two records in two tables, and holding one end says nothing about\n // the other: a Job shared with you may point at a Client nobody shared. The three\n // possible answers for such a chip are the target's TITLE (a leak), a bare id (a bug\n // with a hex number in it) and a permanent \"Loading…\" (a lie with a spinner on it) —\n // and picking between them is not a decision a screen is entitled to make, because the\n // screen does not know the ladder.\n //\n // So the screen does not decide. Every id a cell draws is asked of the store's ONE\n // resolver through `relation_words_many`, which:\n // · applies THIS column's display spec — one column, or several joined by its own\n // separator, which is the whole of REL-DISP and which nothing out here could do;\n // · asks the read-access ladder BEFORE it reads a name, so a record this reader may\n // not open comes back withheld rather than named;\n // · answers a WHOLE PAGE in one round trip, with no 200-row ceiling anywhere.\n //\n // 🚨 ONE ROUND FOR THE WHOLE PAGE, NOT ONE PER CELL (FRONT-DOOR). The first version of\n // this chase fired the moment a cell asked and committed its own `setNames`, so forty\n // rows cost forty round trips AND forty re-renders of every cell on the page. The ids\n // therefore still GATHER and flush once a tick — that part was right and is kept. What\n // changes is that the flush is now ONE call per Field instead of one per id: the batch\n // door this file's own comment recorded as missing (\"there is still no batch door on\n // the store\") exists as of REL-DISP, so the per-id lane is gone entirely.\n //\n // AN ID THE DOOR GAVE NO WORDS FOR is not a missing name, it is a withheld one: the\n // door answered, and the answer was nothing. It reads the SAME SENTENCE the store\n // itself gives (`platform.relation_withheld_label()`), never the title, never the id,\n // and never a \"Loading…\" that resolves for nobody.\n const queued = useRef<Map<string, { field: Field; ids: Set<string> }>>(new Map());\n const flushing = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const flush = useCallback(() => {\n flushing.current = null;\n const batch = [...queued.current.values()];\n queued.current.clear();\n if (batch.length === 0) return;\n void (async () => {\n const learned: Record<string, string> = {};\n const archivedNow: Record<string, true> = {};\n const iconsNow: Record<string, { icon: string | null; tableIcon: string | null }> = {};\n // One call per FIELD — each one carries that field's whole page of ids. Several\n // relation columns on one grid are several calls, which is the number of distinct\n // display specs in play and cannot be fewer.\n await Promise.all(\n batch.map(async ({ field, ids }) => {\n const wanted = [...ids];\n const result = await client.relationWordsMany({\n field_id: field.id,\n record_ids: wanted as Uuid[],\n });\n for (const id of wanted) {\n const words = result.ok ? result.data[id] : undefined;\n // A FAILED read is unread, never withheld — only an answer of nothing is withheld.\n learned[id] = !result.ok\n ? UNREAD_RECORD_LABEL\n : typeof words === \"string\" && words !== \"\"\n ? words\n : WITHHELD_RECORD_LABEL;\n }\n if (result.ok) for (const id of result.archived ?? []) archivedNow[`${field.id}:${id}`] = true;\n if (result.ok) for (const [id, pair] of Object.entries(result.icons ?? {})) iconsNow[id] = pair;\n }),\n );\n // ONE commit for the whole page.\n setNames((current) => ({ ...current, ...learned }));\n if (Object.keys(archivedNow).length > 0) setArchivedRefs((current) => ({ ...current, ...archivedNow }));\n if (Object.keys(iconsNow).length > 0) setIconsOf((current) => ({ ...current, ...iconsNow }));\n for (const { field } of batch) stopWaitClock(field.id);\n })();\n }, [client, stopWaitClock]);\n\n const chase = useCallback(\n (field: Field, id: string) => {\n const key = `${field.id}:${id}`;\n if (chased.current.has(key)) return;\n chased.current.add(key);\n // Grouped BY FIELD, because the door's question is \"what does THIS column call\n // these records\" — the display spec belongs to the column, so two columns pointing\n // at the same table can legitimately give the same id two different answers. The\n // old map was keyed by id alone and would have collapsed exactly that case.\n const pending = queued.current.get(field.id);\n if (pending) pending.ids.add(id);\n else queued.current.set(field.id, { field, ids: new Set([id]) });\n startWaitClock(field, null);\n if (flushing.current === null) flushing.current = setTimeout(flush, 0);\n },\n [flush, startWaitClock],\n );\n\n useEffect(\n () => () => {\n if (flushing.current !== null) clearTimeout(flushing.current);\n },\n [],\n );\n\n /** A choice key this page has not seen yet asks the Field's options again, once per key. */\n const rereadFor = useRef<Set<string>>(new Set());\n const lookupWords = useCallback(\n (field: Field, id: string): string | null => {\n if (field.type === \"list\" && !isId(id)) {\n const named = names[choiceKeyName(field.id, id)];\n if (named !== undefined) return named;\n const once = choiceKeyName(field.id, id);\n if (settled[field.id] && !rereadFor.current.has(once)) {\n // A choice added after the options were read (the nudge's Add): read them again.\n rereadFor.current.add(once);\n asked.current.delete(field.id);\n want(field);\n }\n return null;\n }\n const known = names[id];\n if (known !== undefined) return known;\n if (settled[field.id]) chase(field, id);\n return null;\n },\n [names, settled, chase, want],\n );\n const lookup = useMemo<LabelLookup>(\n () => {\n const answer = ((field: Field, id: string) => lookupWords(field, id)) as LabelLookup;\n answer.archived = (field: Field, id: string) => archivedRefs[`${field.id}:${id}`] === true;\n answer.icons = (_field: Field, id: string) => iconsOf[id];\n return answer;\n },\n [lookupWords, archivedRefs, iconsOf],\n );\n\n const waiting = useCallback((field: Field) => waitingLines[field.id] ?? null, [waitingLines]);\n\n const value = useMemo(() => ({ lookup, want, waiting }), [lookup, want, waiting]);\n return <LabelContext.Provider value={value}>{children}</LabelContext.Provider>;\n}\n\n/**\n * The hook a surface uses: it declares the Fields it is about to draw, and gets\n * back the lookup. Declaring is what makes one request per Field instead of one\n * per cell, and it is why a grid of 200 rows asks the store twice.\n */\nexport function useRecordLabels(fields: readonly Field[] | undefined): LabelLookup {\n const { lookup, want } = useContext(LabelContext);\n useEffect(() => {\n for (const field of fields ?? []) want(field);\n }, [fields, want]);\n return lookup;\n}\n\n/**\n * WHAT THIS COLUMN IS STILL WAITING FOR, or null while \"Loading…\" is still an\n * honest word. A cell draws this INSTEAD of \"Loading…\" once the resolver has\n * been looking for a second — see `SAY_WHAT_YOU_ARE_WAITING_FOR_AFTER_MS`.\n */\nexport function useLabelWait(field: Field | undefined): string | null {\n const { waiting } = useContext(LabelContext);\n return field ? waiting(field) : null;\n}\n","\"use client\";\n\n// src/signature.tsx — @ai-matrx/records-ui · lane 10 VIEWS-AND-FIELDS W1-A\n//\n// A SIGNATURE IS DRAWN, AND IT IS SEEN AS A DRAWING.\n//\n// The store keeps a Signature column as `type: text, format: signature`\n// (`custom.doc_signature_field_ok`). Through a form, the value it takes is a string, and the\n// drawing travels as the same `data:image/(png|jpeg);base64,…` URL `custom.sign_request_sign`\n// already validates for its drawn mark — one image format for every signature on the platform.\n// A signature the document door sealed (`custom.doc_sign`) is the signer's NAME instead; both\n// read back here: a drawing as an image, a name as the name.\n//\n// THE PAD was lifted from matrx-frontend's `/sign/[token]` DrawPad (canvas + pointer events, no\n// library, `touch-none` so a phone draws instead of scrolling) so there is one pad, here, that\n// every host and every form shares. Ink is always dark on a white sheet (a stored image must read in\n// both themes — cells invert it in dark mode).\n//\n// 🚨 SIZE. A drawing's encoded size depends on what is drawn, not on the canvas: a dense signature\n// measured ~310 kB as a 600-px PNG (verifier, 2026-10-02) against the store's `value_max_bytes`\n// default of 100,000 — and over the ceiling the store keeps a cell's first 1,000 characters, which\n// is a broken image. So `fitDrawing` re-encodes down a ladder (smaller PNGs, then JPEG on white)\n// until the value is under `SIGNATURE_BUDGET_BYTES`; when nothing fits the pad sends nothing and\n// says so, so a form can never submit a signature the store would cut.\n//\n// WHERE THE DRAWING GOES is decided in ONE place, `fitDrawing`'s caller (`end` below) handing a data\n// URL to `onChange`. A form sends that data URL as the answer, and `custom.form_submit` (CHAIR-DOORS-1,\n// live 2026-10-02) turns it into a File record: the record keeps the word \"Signed\" and its value's\n// source names the File (`{kind: 'signature', mark: 'drawn', signature_file_id, signed_at, via:\n// 'form', form_id}`). The ladder still guards a FORM too: the File keeps the drawing inline as its\n// `content`, and one value is capped at 100,000 bytes there as anywhere (measured on the clone,\n// 2026-10-02: a 312,024-byte drawing was refused by `custom._value_envelope`).\n//\n// READING IT BACK. A drawing kept inline (every value written before the File door, a sign-link,\n// an offline capture) is drawn as it is. \"Signed\" whose source names a File is drawn from that File\n// (`SignatureDrawing`): the source through `recordValuesVersioned` (the read doors give the value\n// without its envelope), then the File record's `content`; a File the host keeps elsewhere draws\n// through the host's `fileImage` port, the gallery's picture renderer. Until it is read, and when it\n// cannot be, the cell says \"Signed\" — never a broken image.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Button, ErrorBox, cn } from \"@ai-matrx/design-system\";\nimport type { RecordDocument, Uuid } from \"@ai-matrx/records\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { isSignatureField } from \"./docs\";\nimport { useRecordsUi } from \"./host\";\n\n/** The exact shape `custom.sign_request_sign` accepts for a drawn mark. */\nconst DRAWN = /^data:image\\/(png|jpeg);base64,[A-Za-z0-9+/=]{64,}$/;\n\n/** Whether this column is a Signature column — the one test, `docs.ts` (VAL-10). */\nexport { isSignatureField };\n\n/** The drawing a signature value holds, or null when it holds none (empty, or a signer's name). */\nexport function drawnSignatureOf(value: unknown): string | null {\n return typeof value === \"string\" && DRAWN.test(value) ? value : null;\n}\n\n/** The word a text-only place (a card title, a sentence, an export) writes for a drawn signature. */\nexport const SIGNED_WORD = \"Signed\";\n\n/** A signature value in words: a drawing is \"Signed\"; a sealed name stays the name. */\nexport function signatureWords(value: unknown): string | null {\n if (value === null || value === undefined || value === \"\") return null;\n return drawnSignatureOf(value) ? SIGNED_WORD : String(value);\n}\n\n/** The File a signature value's source names (`custom.form_submit`, `custom.sign_request_sign`). */\nexport function signatureFileOf(source: unknown): string | null {\n if (!source || typeof source !== \"object\") return null;\n const src = source as Record<string, unknown>;\n const id = src[\"signature_file_id\"];\n return src[\"kind\"] === \"signature\" && typeof id === \"string\" && id !== \"\" ? id : null;\n}\n\n/**\n * The File a stored document's envelope names for one key, when the document carries its envelope\n * (`_values.<key>.src`, inline or a pointer into `_sources`). The read doors strip both, so a\n * screen usually has to ask (`SignatureDrawing`); a document that has them is answered here.\n */\nexport function signatureFileIn(document: RecordDocument | null | undefined, key: string): string | null {\n const values = document?.[\"_values\"] as Record<string, { src?: unknown }> | undefined;\n const src = values?.[key]?.src;\n if (typeof src === \"string\") {\n const sources = document?.[\"_sources\"] as Record<string, unknown> | undefined;\n return signatureFileOf(sources?.[src]);\n }\n return signatureFileOf(src);\n}\n\n/** What one record's signature File holds, as a picture: an inline drawing, or a host file id. */\ntype Drawing = { src: string | null; hostFileId: string | null };\n\nconst SOURCES = new WeakMap<RecordsClient, Map<string, Promise<Record<string, string | null>>>>();\nconst FILES = new WeakMap<RecordsClient, Map<string, Promise<Drawing>>>();\n\n/** Every signature File one record's values name, by field key — one read per record. */\nfunction signatureFilesOf(client: RecordsClient, recordId: string): Promise<Record<string, string | null>> {\n let held = SOURCES.get(client);\n if (!held) SOURCES.set(client, (held = new Map()));\n let asked = held.get(recordId);\n if (!asked) {\n asked = client.recordValuesVersioned({ record_id: recordId as Uuid }).then((answered) => {\n if (!answered.ok) return {};\n return Object.fromEntries(answered.data.map((v) => [v.field_key, signatureFileOf(v.source)]));\n });\n held.set(recordId, asked);\n }\n return asked;\n}\n\n/** The picture a signature File holds — one read per File. */\nfunction drawingOf(client: RecordsClient, fileId: string): Promise<Drawing> {\n let held = FILES.get(client);\n if (!held) FILES.set(client, (held = new Map()));\n let asked = held.get(fileId);\n if (!asked) {\n asked = client.recordRead({ record_id: fileId as Uuid }).then((answered) => {\n if (!answered.ok) return { src: null, hostFileId: null };\n const doc = (answered.data.document ?? {}) as RecordDocument;\n const content = drawnSignatureOf(doc[\"content\"]);\n const hostFileId = typeof doc[\"file_id\"] === \"string\" && doc[\"file_id\"] !== \"\" ? (doc[\"file_id\"] as string) : null;\n return { src: content, hostFileId };\n });\n held.set(fileId, asked);\n }\n return asked;\n}\n\nfunction DrawnImage({ src, inCell }: { src: string; inCell?: boolean | undefined }) {\n return (\n <img\n src={src}\n alt={SIGNED_WORD}\n data-records-signature=\"\"\n className={cn(\"max-w-[12rem] object-contain object-left dark:invert\", inCell ? \"h-7\" : \"h-12\")}\n />\n );\n}\n\n/** \"Signed\" whose drawing is a File: read the File, draw it; say \"Signed\" until then. */\nfunction SignatureDrawing({\n recordId,\n fieldKey,\n fileId: knownFile,\n value,\n inCell,\n}: {\n recordId: string | null;\n fieldKey: string | null;\n fileId: string | null;\n value: unknown;\n inCell?: boolean | undefined;\n}) {\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [drawing, setDrawing] = useState<Drawing | null>(null);\n useEffect(() => {\n let cancelled = false;\n setDrawing(null);\n if (!client) return;\n void (async () => {\n const fileId = knownFile ?? (recordId && fieldKey ? (await signatureFilesOf(client, recordId))[fieldKey] ?? null : null);\n if (!fileId || cancelled) return;\n const read = await drawingOf(client, fileId);\n if (!cancelled) setDrawing(read);\n })();\n return () => {\n cancelled = true;\n };\n }, [client, recordId, fieldKey, knownFile]);\n if (drawing?.src) return <DrawnImage src={drawing.src} inCell={inCell} />;\n if (drawing?.hostFileId && host.fileImage) {\n return (\n <span className={cn(\"inline-block max-w-[12rem] dark:invert\", inCell ? \"h-7\" : \"h-12\")} data-records-signature=\"\">\n {host.fileImage({ fileId: drawing.hostFileId as Uuid, alt: SIGNED_WORD })}\n </span>\n );\n }\n return <span className=\"font-serif italic\">{String(value)}</span>;\n}\n\n/**\n * A signature as it reads anywhere a value is shown: the drawing, or the signer's name. A drawing\n * kept as a File (a form's, `custom.form_submit`) needs to know whose value this is: `recordId` and\n * `fieldKey`, or the `document` when it carries its envelope.\n */\nexport function SignatureValue({\n value,\n inCell,\n recordId,\n fieldKey,\n document,\n}: {\n value: unknown;\n inCell?: boolean | undefined;\n recordId?: string | null | undefined;\n fieldKey?: string | null | undefined;\n document?: RecordDocument | null | undefined;\n}) {\n const drawn = drawnSignatureOf(value);\n if (drawn) return <DrawnImage src={drawn} inCell={inCell} />;\n const fileId = fieldKey ? signatureFileIn(document, fieldKey) : null;\n if (value === SIGNED_WORD && (fileId || (recordId && fieldKey))) {\n return <SignatureDrawing recordId={recordId ?? null} fieldKey={fieldKey ?? null} fileId={fileId} value={value} inCell={inCell} />;\n }\n return <span className=\"font-serif italic\">{String(value)}</span>;\n}\n\nconst INK = \"#111827\";\n\n/** The most a drawn signature may weigh as a value — well under the store's 100,000-byte default. */\nexport const SIGNATURE_BUDGET_BYTES = 60_000;\n\n/** Said on the pad when even the smallest encoding of a drawing is over the budget. */\nexport const SIGNATURE_TOO_DETAILED = \"Too detailed to save — clear and sign again.\";\n\n/**\n * THE ONE SIGNATURE PAD. Draw with a finger, a pen or a mouse; Clear starts again. `onChange`\n * receives the drawing as a PNG data URL when a stroke ends, and `null` when cleared.\n */\nexport function SignaturePad({\n value,\n onChange,\n disabled,\n id,\n className,\n}: {\n value: unknown;\n onChange: (value: string | null) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n}) {\n const kept = drawnSignatureOf(value);\n const named = !kept && typeof value === \"string\" && value !== \"\" ? value : null;\n // A value already there when the control opens is shown as itself until somebody chooses to\n // sign again; once the pad is open it stays open while they draw (their own strokes come back\n // as `value` and must not swap the pad for a picture mid-signature).\n const [showPad, setShowPad] = useState(() => !kept && !named);\n\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const drawing = useRef(false);\n const [dirty, setDirty] = useState(false);\n const [tooBig, setTooBig] = useState(false);\n\n useEffect(() => {\n if (!showPad) return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n // Backed at device resolution so the strokes are not blurred squares on the phone.\n const ratio = window.devicePixelRatio || 1;\n const rect = canvas.getBoundingClientRect();\n canvas.width = Math.round(rect.width * ratio);\n canvas.height = Math.round(rect.height * ratio);\n const context = canvas.getContext(\"2d\");\n if (!context) return;\n context.scale(ratio, ratio);\n context.lineWidth = 2.2;\n context.lineCap = \"round\";\n context.lineJoin = \"round\";\n context.strokeStyle = INK;\n }, [showPad]);\n\n const point = (event: React.PointerEvent<HTMLCanvasElement>) => {\n const rect = event.currentTarget.getBoundingClientRect();\n return { x: event.clientX - rect.left, y: event.clientY - rect.top };\n };\n\n const start = (event: React.PointerEvent<HTMLCanvasElement>) => {\n if (disabled) return;\n event.currentTarget.setPointerCapture?.(event.pointerId);\n const context = canvasRef.current?.getContext(\"2d\");\n if (!context) return;\n const { x, y } = point(event);\n context.beginPath();\n context.moveTo(x, y);\n drawing.current = true;\n };\n\n const move = (event: React.PointerEvent<HTMLCanvasElement>) => {\n if (!drawing.current) return;\n const context = canvasRef.current?.getContext(\"2d\");\n if (!context) return;\n const { x, y } = point(event);\n context.lineTo(x, y);\n context.stroke();\n if (!dirty) setDirty(true);\n };\n\n const end = () => {\n if (!drawing.current) return;\n drawing.current = false;\n const canvas = canvasRef.current;\n if (!canvas) return;\n // THE ONE PLACE the drawing becomes a value (see the header: CHAIR-DOORS-1 changes this line).\n const fitted = fitDrawing(canvas);\n setTooBig(fitted === null);\n onChange(fitted);\n setDirty(true);\n };\n\n const clear = () => {\n const canvas = canvasRef.current;\n const context = canvas?.getContext(\"2d\");\n if (canvas && context) {\n context.save();\n context.setTransform(1, 0, 0, 1, 0, 0);\n context.clearRect(0, 0, canvas.width, canvas.height);\n context.restore();\n }\n setDirty(false);\n setTooBig(false);\n setShowPad(true);\n onChange(null);\n };\n\n if (!showPad) {\n return (\n <div id={id} className={cn(\"flex items-center justify-between gap-2 rounded-md border px-3 py-2\", className)}>\n <SignatureValue value={value} />\n {!disabled ? (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={clear}>\n Sign again\n </Button>\n ) : null}\n </div>\n );\n }\n\n return (\n <div className={cn(\"flex w-full flex-col gap-1\", className)}>\n <div className=\"relative\">\n <canvas\n id={id}\n ref={canvasRef}\n role=\"img\"\n aria-label=\"Signature pad\"\n data-records-signature-pad=\"\"\n onPointerDown={start}\n onPointerMove={move}\n onPointerUp={end}\n onPointerLeave={end}\n onPointerCancel={end}\n // `touch-none` or a phone scrolls the page instead of drawing.\n className={cn(\n \"block h-36 w-full touch-none rounded-md border border-border bg-white\",\n disabled ? \"cursor-not-allowed opacity-60\" : \"cursor-crosshair\",\n )}\n />\n {!dirty ? (\n <span className=\"pointer-events-none absolute inset-x-0 bottom-3 text-center text-xs text-neutral-400\">\n Sign here\n </span>\n ) : null}\n </div>\n <div className=\"flex items-center justify-end gap-2\">\n {tooBig ? (\n <ErrorBox\n as=\"span\"\n className=\"mr-auto text-xs text-destructive\"\n message={SIGNATURE_TOO_DETAILED}\n operation=\"Save a signature\"\n origin=\"records-ui/signature\"\n />\n ) : null}\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={clear} disabled={disabled || !dirty}>\n Clear\n </Button>\n </div>\n </div>\n );\n}\n\n/** The encodings tried in order, smallest-loss first: [format, max width, JPEG quality]. */\nconst LADDER: Array<[\"image/png\" | \"image/jpeg\", number, number]> = [\n [\"image/png\", 600, 1],\n [\"image/png\", 400, 1],\n [\"image/jpeg\", 600, 0.7],\n [\"image/jpeg\", 400, 0.6],\n [\"image/jpeg\", 300, 0.5],\n];\n\n/**\n * The drawing as the smallest-loss data URL under `SIGNATURE_BUDGET_BYTES`, or null when none\n * fits. JPEG has no transparency, so it is drawn on white (the pad's own sheet).\n */\nexport function fitDrawing(canvas: HTMLCanvasElement): string | null {\n for (const [type, maxWidth, quality] of LADDER) {\n const encoded = encodeAt(canvas, type, maxWidth, quality);\n if (encoded && encoded.length <= SIGNATURE_BUDGET_BYTES) return encoded;\n }\n return null;\n}\n\nfunction encodeAt(canvas: HTMLCanvasElement, type: \"image/png\" | \"image/jpeg\", maxWidth: number, quality: number): string | null {\n const width = Math.min(maxWidth, canvas.width || maxWidth);\n const scale = canvas.width > 0 ? width / canvas.width : 1;\n const out = document.createElement(\"canvas\");\n out.width = width;\n out.height = Math.max(1, Math.round((canvas.height || 1) * scale));\n const context = out.getContext(\"2d\");\n if (!context) return null;\n if (type === \"image/jpeg\") {\n context.fillStyle = \"#ffffff\";\n context.fillRect(0, 0, out.width, out.height);\n }\n context.drawImage(canvas, 0, 0, out.width, out.height);\n return out.toDataURL(type, quality);\n}\n","// The person's time zone, as the app saved it (userPreferences.display.timeZone).\n//\n// The host app tells this package once (`setPersonTimeZone(\"America/Los_Angeles\")`); every \"today\" and\n// \"now\" a screen draws (the calendar's today marker and now-line, a timeline's today, a date picker's\n// today) is read in that zone instead of the device's. With nothing set the device zone applies, as before.\n// Nothing here stores a zone: the host's saved preference is the one place, this is its mirror.\n\nimport { useSyncExternalStore } from \"react\";\n\nlet zone: string | null = null;\nconst listeners = new Set<() => void>();\n\nfunction valid(z: unknown): z is string {\n if (typeof z !== \"string\" || !z.trim()) return false;\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: z });\n return true;\n } catch {\n return false;\n }\n}\n\n/** The host app's saved zone (IANA). `null` / junk clears it: the device zone applies. */\nexport function setPersonTimeZone(next: string | null | undefined): void {\n const clean = valid(next) ? next : null;\n if (clean === zone) return;\n zone = clean;\n listeners.forEach((l) => l());\n}\n\nexport function getPersonTimeZone(): string | null {\n return zone;\n}\n\n/** Re-renders the caller when the zone changes; returns it. */\nexport function usePersonTimeZone(): string | null {\n return useSyncExternalStore(\n (cb) => {\n listeners.add(cb);\n return () => listeners.delete(cb);\n },\n () => zone,\n () => null,\n );\n}\n\n/**\n * `at` as a Date whose LOCAL fields (getFullYear, getHours, ...) read the wall clock in the person's zone.\n * For day / hour math only: never compare it with a stored instant.\n */\nexport function personWallNow(at: Date = new Date()): Date {\n if (!zone) return at;\n const parts = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: zone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\",\n hourCycle: \"h23\",\n }).formatToParts(at);\n const n = (t: string) => Number(parts.find((p) => p.type === t)?.value ?? 0);\n return new Date(n(\"year\"), n(\"month\") - 1, n(\"day\"), n(\"hour\"), n(\"minute\"), n(\"second\"));\n}\n","/**\n * HOW A TABLE LOOKS — colors, formats and the frozen column.\n *\n * THE SPLIT, AND WHY IT IS THIS ONE. A Field declares WHAT it holds: a\n * currency, a percent, a date, a person. A VIEW declares HOW that reads and\n * what it is worth looking at: two decimal places or none, tint the row when\n * Status is Blocked, keep Name in place while the rest scrolls. Airtable draws\n * the line in exactly this place, and it has to be here: two people read one\n * table two different ways, and neither reading is a fact about the records.\n *\n * So nothing in this module is a new column on a Field and nothing here needed\n * a migration. A presentation lives on the saved-view record (`views.ts`), which\n * is an ordinary record of an ordinary Table — which means an agent sets it\n * through the same `records` tool it uses for everything else, and it travels\n * with the table the way every other record does.\n *\n * A FIELD STILL GETS ITS MONEY RIGHT WITH NO CONFIGURATION. `formatForField`\n * reads the Field's OWN declaration — a `currency` parity type with unit `$`, a\n * `percent`, a `datetime` with `config.kind` — and returns the format that\n * follows from it. The view's `formats` map only OVERRIDES that. A table nobody\n * has ever styled still shows `$1,250.50` and `45%`.\n */\n\n// The style parser from its own client-free subpath (lane SSR-ROWS): `@ai-matrx/records-ui/first-page`\n// runs in a host's SERVER component, and every export of the \"use client\" `data-table` entry is a\n// client reference there — calling `parseTableStyle` through it threw on the server.\nimport { parseTableStyle, tableStyleIsEmpty } from \"@ai-matrx/design-system/data-table/table-style\";\nimport {\n COLOR_ROTATION,\n type ChoiceColorLookup,\n type GroupAggregateKind,\n type GroupAggregateSpec,\n type GroupOrder,\n type StyleColor,\n type TableStyle,\n} from \"@ai-matrx/design-system/data-table\";\nimport { getFieldFormat, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport type { ColorRule } from \"@ai-matrx/design-system/data-table\";\nimport { newerKindOf, ratingMaxOf, type Field, type TableDecorations } from \"@ai-matrx/records\";\n\nimport { editorKindFor } from \"./parity\";\nimport { dateFormatFor } from \"./dates\";\n\n/**\n * SECTIONS BY A FIELD — the view's own grouping.\n *\n * `field` is a Field KEY, exactly like `frozen` and the keys of `formats`,\n * because a view is written against the Table's declaration and never against\n * whatever id a screen happened to build its columns with.\n *\n * `aggregates` is keyed by Field key too, and `collapsed` holds the data\n * table's own group keys (`s:Blocked`, `n:3`, `empty`), which is what the\n * primitive emits and the only thing that survives a value rendering the same\n * text as another.\n *\n * NOTHING HERE IS EVER CALLED `valueOf`, `toString` or `hasOwnProperty`: every\n * object in JavaScript already has all three, so an optional field by one of\n * those names is NEVER absent and a `config.valueOf ? … : …` check silently\n * reads `Object.prototype`. It cost the primitive a whole grouping once.\n */\nexport type GridGrouping = {\n /** The Field key whose value makes the sections. */\n field: string;\n /** Per-Field-key subtotal on every section header. */\n aggregates?: Record<string, GroupAggregateSpec>;\n /** Section order. The primitive's default is `value-asc`; blanks sort last. */\n order?: GroupOrder;\n /** The sections this view keeps shut, by the primitive's own group key. */\n collapsed?: string[];\n /** The grouped column drawn as a column too. Absent = it steps aside (the headers name its value). */\n showColumn?: boolean;\n /**\n * SUB-GROUPS (lane S1-PRIME VIEW-KEYS; ui-bench LISTS \"sub-grouping\"): up to two more levels\n * inside each section, by Field key. At most three levels in all — the store refuses a fourth\n * (`custom.view_declare`). A layout that draws one level ignores the rest; it never drops them,\n * because this list is parsed and written back whole with the rest of the look.\n */\n then?: GridSubGroup[];\n /**\n * DRILL (lane DRILL-TABLE-PRIMITIVE): the Dimension pivoted across the top — a Field key, or\n * `<key>:<grain>` for a date cut into periods.\n */\n across?: string;\n /** DRILL: the period `field` is cut into when it is a date (`month`); the store keeps `field` a Field key. */\n grain?: string;\n /** The Measures shown (\"what to display\"), by the store's own keys (`count`, `sum_quantity`). */\n show?: string[];\n /** The drill trail, in order: each crumb a Dimension reference and the value it narrowed to. */\n trail?: GridDrillStep[];\n};\n\n/** One crumb of a saved drill trail. `value: null` is \"no value\". */\nexport type GridDrillStep = { dim: string; value: string | null };\n\n/** One sub-group level: a Field key and its section order. */\nexport type GridSubGroup = { field: string; order?: GroupOrder; grain?: string };\n\n/** Everything a view says about how its table LOOKS. */\nexport type GridPresentation = {\n /** Color-by-a-column, rules and manual highlights. */\n style?: TableStyle;\n /** Per-column format overrides, by the Field's key. */\n formats?: Record<string, FieldFormatConfig>;\n /**\n * The columns that stay in place while the table scrolls sideways, by Field\n * key. Only the LEADING run of the view's column order can actually freeze —\n * the data table decides that, and declines rather than pinning a column at a\n * guessed offset.\n */\n frozen?: string[];\n /** Collapsible sections by one Field, with subtotals on each header. */\n grouping?: GridGrouping;\n /**\n * The width a person dragged a column to, by Field key. SPARSE on purpose —\n * a view saved before widths existed carries none and still parses, and a\n * column nobody resized is left to the table's own measurement.\n */\n widths?: Record<string, number>;\n /** The body row height this view remembers, in px. */\n rowHeight?: number;\n /**\n * Field keys hidden from this view — the SAME hidden-column list the grid's\n * own column picker holds, now given a place on the view so it survives a\n * reload and a layout switch reads the identical set gallery and grid agree\n * on, rather than a second \"fields shown\" list nobody kept in sync.\n */\n hiddenFields?: string[];\n /**\n * THE FIELDS A CARD LEAVES OFF (board, list, gallery, calendar, timeline), by Field key — the\n * card's own choice, kept apart from `hiddenFields` so a board's \"Card fields\" never hides the\n * grid's columns when the view switches layout (v7 TABLE-EXPERIENCE, walk 2026-10-05). An empty\n * list is a choice (every field shown); absent means the card never chose.\n */\n cardHidden?: string[];\n /**\n * THE ORDER A PERSON DRAGGED THE COLUMNS INTO, by Field key (merge tranche 6a). Sparse like\n * `widths`: a key it does not name keeps its Field's own place after the named ones, and a key\n * whose Field is gone is skipped — a column order can never hide or invent a column.\n */\n columnOrder?: string[];\n /**\n * The gallery's card size, remembered the same way the grid remembers its\n * row height — a per-view look, not a global default.\n */\n gallerySize?: \"small\" | \"medium\" | \"large\";\n /**\n * THIS VIEW'S OWN LAYOUT CHOICES, over the organization's `custom/grid_layout` knob (lane\n * DEFAULT-GRID-PARITY, TABLE-PARITY D1 D5 D6). Absent means \"whatever the organization\n * says\"; present is the view's word. `freezeFirst: false` is an explicit NO over an\n * organization that freezes the first column — an empty `frozen` cannot say that.\n */\n wrap?: boolean;\n /** NOTION'S \"WRAP COLUMN\" (N5): the columns that wrap their text when the view as a whole does not. */\n wrapColumns?: string[];\n fit?: \"auto\" | \"fit\" | \"scroll\";\n freezeFirst?: boolean;\n /**\n * THE SUMMARY BAR (TABLE-PARITY F1): Field key → the store measure shown under that column\n * (`count`, `sum`, `avg`, `min`, `max`, `median`, `filled`, `empty`, `unique`), worked out\n * by `custom.record_aggregate` over the whole table.\n */\n summaries?: Record<string, string>;\n /**\n * WHERE THE FOOTER SITS (lane TABLE-PAGE-CHROME, owner 2026-09-25) — the row count and the\n * pages: `sticky`, pinned to the bottom of the screen while the rows scroll (the older grid's\n * way, and the default when a view says nothing), or `inline`, right after the last row with\n * the page scrolling. Read by the Grid and a host's Sheet.\n */\n footer?: FooterPlacement;\n};\n\n/** Where a grid's footer sits. */\nexport type FooterPlacement = \"sticky\" | \"inline\";\n\n/** What a view that says nothing gets — the older grid's pinned footer. */\nexport const DEFAULT_FOOTER: FooterPlacement = \"sticky\";\n\n/** Where THIS view's footer sits, said or defaulted. */\nexport function footerOf(p: GridPresentation | null | undefined): FooterPlacement {\n return p?.footer ?? DEFAULT_FOOTER;\n}\n\nexport const EMPTY_PRESENTATION: GridPresentation = {};\n\n/** A frozen column needs a known width, or the table declines to freeze at all. */\nexport const FROZEN_COLUMN_WIDTH = 200;\n\n/**\n * WHAT A ROW HEIGHT IS ALLOWED TO BE. Below the floor the text is clipped and\n * no editor fits; above the ceiling one record fills the screen. A view asking\n * for anything outside it is DROPPED rather than obeyed, because a saved look\n * must not be able to make a table unreadable — and the Fields' own heights\n * still draw, which is the tolerant half.\n */\nexport const MIN_ROW_HEIGHT = 24;\nexport const MAX_ROW_HEIGHT = 96;\n\n/**\n * The aggregate kinds and orders the primitive actually implements. Listed here\n * because they are the tolerant parser's allow-list and a view is hostile input:\n * `satisfies` ties them to the primitive's own union, so a kind it renames stops\n * this file compiling instead of quietly parsing into a subtotal nobody draws.\n */\nconst AGGREGATE_KINDS = [\n \"count\",\n \"sum\",\n \"average\",\n \"min\",\n \"max\",\n \"empty\",\n \"filled\",\n \"unique\",\n \"checked\",\n \"unchecked\",\n \"percentFilled\",\n] as const satisfies readonly GroupAggregateKind[];\n\nconst GROUP_ORDERS = [\n \"value-asc\",\n \"value-desc\",\n \"count-desc\",\n \"first-seen\",\n] as const satisfies readonly GroupOrder[];\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\n/**\n * Read a presentation out of whatever the view record holds — an object, or the\n * JSON string a text field stores.\n *\n * Tolerant in exactly the way `parseTableStyle` is: an unreadable half is\n * dropped and the rest still applies, because a table must keep drawing when\n * one piece of its styling goes out of date.\n */\nexport function parseGridPresentation(raw: unknown): GridPresentation {\n let value = raw;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed === \"\") return {};\n try {\n value = JSON.parse(trimmed);\n } catch {\n return {};\n }\n }\n if (!isRecord(value)) return {};\n\n const out: GridPresentation = {};\n\n const style = parseTableStyle(value[\"style\"]);\n if (!tableStyleIsEmpty(style)) out.style = style;\n\n if (isRecord(value[\"formats\"])) {\n const formats: Record<string, FieldFormatConfig> = {};\n for (const [key, cfg] of Object.entries(value[\"formats\"])) {\n if (!isRecord(cfg)) continue;\n const id = cfg[\"id\"];\n if (typeof id !== \"string\") continue;\n const options = cfg[\"options\"];\n formats[key] = isRecord(options)\n ? {\n id: id as FieldFormatConfig[\"id\"],\n options: options as NonNullable<FieldFormatConfig[\"options\"]>,\n }\n : { id: id as FieldFormatConfig[\"id\"] };\n }\n if (Object.keys(formats).length > 0) out.formats = formats;\n }\n\n if (Array.isArray(value[\"frozen\"])) {\n const frozen = value[\"frozen\"].filter((k): k is string => typeof k === \"string\");\n if (frozen.length > 0) out.frozen = frozen;\n }\n\n const grouping = parseGrouping(value[\"grouping\"]);\n if (grouping) out.grouping = grouping;\n\n if (isRecord(value[\"widths\"])) {\n const widths: Record<string, number> = {};\n for (const [key, raw] of Object.entries(value[\"widths\"])) {\n // A width that is not a usable number is one column's loss, never the\n // view's: the rest of the widths still apply and that column is measured.\n if (typeof raw !== \"number\" || !Number.isFinite(raw) || raw <= 0) continue;\n widths[key] = Math.round(raw);\n }\n if (Object.keys(widths).length > 0) out.widths = widths;\n }\n\n const rowHeight = value[\"rowHeight\"];\n if (\n typeof rowHeight === \"number\" &&\n Number.isFinite(rowHeight) &&\n rowHeight >= MIN_ROW_HEIGHT &&\n rowHeight <= MAX_ROW_HEIGHT\n ) {\n out.rowHeight = Math.round(rowHeight);\n }\n\n if (Array.isArray(value[\"hiddenFields\"])) {\n const hiddenFields = value[\"hiddenFields\"].filter((k): k is string => typeof k === \"string\");\n if (hiddenFields.length > 0) out.hiddenFields = hiddenFields;\n }\n if (Array.isArray(value[\"cardHidden\"])) {\n out.cardHidden = value[\"cardHidden\"].filter((k): k is string => typeof k === \"string\");\n }\n\n if (Array.isArray(value[\"columnOrder\"])) {\n const columnOrder = value[\"columnOrder\"].filter((k): k is string => typeof k === \"string\");\n if (columnOrder.length > 0) out.columnOrder = columnOrder;\n }\n\n const gallerySize = value[\"gallerySize\"];\n if (gallerySize === \"small\" || gallerySize === \"medium\" || gallerySize === \"large\") {\n out.gallerySize = gallerySize;\n }\n\n if (typeof value[\"wrap\"] === \"boolean\") out.wrap = value[\"wrap\"];\n if (Array.isArray(value[\"wrapColumns\"])) {\n const wrapColumns = value[\"wrapColumns\"].filter((k): k is string => typeof k === \"string\");\n if (wrapColumns.length > 0) out.wrapColumns = wrapColumns;\n }\n const fit = value[\"fit\"];\n if (fit === \"auto\" || fit === \"fit\" || fit === \"scroll\") out.fit = fit;\n if (typeof value[\"freezeFirst\"] === \"boolean\") out.freezeFirst = value[\"freezeFirst\"];\n const footer = value[\"footer\"];\n if (footer === \"sticky\" || footer === \"inline\") out.footer = footer;\n if (isRecord(value[\"summaries\"])) {\n const summaries: Record<string, string> = {};\n for (const [key, op] of Object.entries(value[\"summaries\"])) {\n // A measure name is judged by the store when it is asked; a non-string is nobody's.\n if (typeof op === \"string\" && op.trim() !== \"\") summaries[key] = op;\n }\n if (Object.keys(summaries).length > 0) out.summaries = summaries;\n }\n\n return out;\n}\n\n/**\n * A grouping, or nothing. A grouping with no Field to group BY is not a partial\n * grouping — it is no grouping at all, so it is dropped whole; an unreadable\n * subtotal or a section order this primitive does not have costs only itself.\n */\nfunction parseGrouping(raw: unknown): GridGrouping | undefined {\n if (!isRecord(raw)) return undefined;\n const field = raw[\"field\"];\n if (typeof field !== \"string\" || field.trim() === \"\") return undefined;\n\n const out: GridGrouping = { field };\n\n if (isRecord(raw[\"aggregates\"])) {\n const aggregates: Record<string, GroupAggregateSpec> = {};\n for (const [key, spec] of Object.entries(raw[\"aggregates\"])) {\n if (!isRecord(spec)) continue;\n const kind = spec[\"kind\"];\n if (typeof kind !== \"string\") continue;\n if (!(AGGREGATE_KINDS as readonly string[]).includes(kind)) continue;\n const label = spec[\"label\"];\n aggregates[key] =\n typeof label === \"string\"\n ? { kind: kind as GroupAggregateKind, label }\n : { kind: kind as GroupAggregateKind };\n }\n if (Object.keys(aggregates).length > 0) out.aggregates = aggregates;\n }\n\n const order = raw[\"order\"];\n if (typeof order === \"string\" && (GROUP_ORDERS as readonly string[]).includes(order)) {\n out.order = order as GroupOrder;\n }\n\n if (Array.isArray(raw[\"collapsed\"])) {\n const collapsed = raw[\"collapsed\"].filter((k): k is string => typeof k === \"string\");\n if (collapsed.length > 0) out.collapsed = collapsed;\n }\n\n if (raw[\"showColumn\"] === true) out.showColumn = true;\n\n if (Array.isArray(raw[\"then\"])) {\n const then: GridSubGroup[] = [];\n for (const level of raw[\"then\"]) {\n if (!isRecord(level)) continue;\n const sub = level[\"field\"];\n if (typeof sub !== \"string\" || sub.trim() === \"\") continue;\n const subOrder = level[\"order\"];\n const subGrain = level[\"grain\"];\n then.push({\n field: sub,\n ...(typeof subOrder === \"string\" && (GROUP_ORDERS as readonly string[]).includes(subOrder)\n ? { order: subOrder as GroupOrder }\n : {}),\n ...(typeof subGrain === \"string\" && subGrain !== \"\" ? { grain: subGrain } : {}),\n });\n }\n if (then.length > 0) out.then = then.slice(0, 2);\n }\n\n const grain = raw[\"grain\"];\n if (typeof grain === \"string\" && grain !== \"\") out.grain = grain;\n const across = raw[\"across\"];\n if (typeof across === \"string\" && across.trim() !== \"\") out.across = across;\n if (Array.isArray(raw[\"show\"])) {\n const show = raw[\"show\"].filter((k): k is string => typeof k === \"string\" && k !== \"\");\n if (show.length > 0) out.show = show;\n }\n if (Array.isArray(raw[\"trail\"])) {\n const trail: GridDrillStep[] = [];\n for (const step of raw[\"trail\"]) {\n if (!isRecord(step) || typeof step[\"dim\"] !== \"string\" || step[\"dim\"] === \"\") continue;\n const value = step[\"value\"];\n if (value !== null && typeof value !== \"string\") continue;\n trail.push({ dim: step[\"dim\"], value });\n }\n if (trail.length > 0) out.trail = trail;\n }\n\n return out;\n}\n\n/** True when nothing here would change how anything looks. */\nexport function presentationIsEmpty(p: GridPresentation): boolean {\n return (\n (p.style === undefined || tableStyleIsEmpty(p.style)) &&\n Object.keys(p.formats ?? {}).length === 0 &&\n (p.frozen?.length ?? 0) === 0 &&\n p.grouping === undefined &&\n Object.keys(p.widths ?? {}).length === 0 &&\n p.rowHeight === undefined &&\n (p.hiddenFields?.length ?? 0) === 0 &&\n p.cardHidden === undefined &&\n (p.columnOrder?.length ?? 0) === 0 &&\n p.gallerySize === undefined &&\n p.wrap === undefined &&\n p.fit === undefined &&\n p.freezeFirst === undefined &&\n p.footer === undefined &&\n Object.keys(p.summaries ?? {}).length === 0\n );\n}\n\n/** The string a view record stores. Empty string for \"this view styles nothing\". */\nexport function presentationDocument(p: GridPresentation): string {\n return presentationIsEmpty(p) ? \"\" : JSON.stringify(p);\n}\n\n/** Kinds whose value is a control the record renderer draws, never a formatter's string. */\nconst DRAWN_KINDS = new Set([\"select\", \"multi_select\", \"relation\", \"member\", \"person\", \"attachment\", \"file\", \"entity_reference\", \"checkbox\", \"boolean\", \"signature\", \"json\"]);\n\n/**\n * The display format a column's settings chose for it, when it is one the platform registry\n * knows and the column is not one the record renderer draws itself. `undefined` otherwise.\n */\nexport function shownAsOf(field: Field): FieldFormatConfig | undefined {\n if (DRAWN_KINDS.has(String(editorKindFor(field)))) return undefined;\n const raw = (field as unknown as { display_format?: unknown }).display_format;\n if (!raw || typeof raw !== \"object\") return undefined;\n const id = (raw as { id?: unknown }).id;\n // `formula` is the column's KIND, never a look: a worked-out column shows as its result format.\n if (typeof id !== \"string\" || id === \"formula\" || !getFieldFormat(id)) return undefined;\n const options = (raw as { options?: unknown }).options;\n return options && typeof options === \"object\" && Object.keys(options).length > 0\n ? ({ id, options } as FieldFormatConfig)\n : ({ id } as FieldFormatConfig);\n}\n\n/**\n * The format a Field's OWN declaration implies, before any view says anything.\n *\n * Returns `undefined` for a Field whose value the record renderer already draws\n * better than a formatter could — a relation chip, a person, an attachment, a\n * choice — because handing those to a text formatter would REPLACE a working\n * control with a string.\n */\nexport function formatForField(field: Field): FieldFormatConfig | undefined {\n // \"SHOWS AS\" — THE FORMAT THE COLUMN'S OWN SETTINGS CHOSE (merge tranche 6a/6e). The column\n // keeps it on the Field (`display_format`, written by `custom.field_update`), so the grid, the\n // record panel and the export read one answer. A column the record renderer draws better than\n // a formatter (a choice, a link, a person, a file) keeps its own drawing.\n const shownAs = shownAsOf(field);\n // A RATING'S TOP STAR IS ITS MAX RULE (lane 10 P4), so changing the rule changes the stars.\n if (newerKindOf(field) === \"rating\" && (!shownAs || shownAs.id === \"rating\")) {\n return { id: \"rating\", options: { ...(shownAs?.options ?? {}), ratingMax: ratingMaxOf(field) } };\n }\n if (shownAs) return shownAs;\n // THE STORE'S OWN STAMPS (Created time, Last changed time) are instants and print like\n // every other date-and-time cell — `dates.ts` answers, the same helper every card reads.\n const stamp = dateFormatFor(field);\n if (stamp && editorKindFor(field) !== \"datetime\") return stamp;\n switch (editorKindFor(field)) {\n case \"currency\":\n return {\n id: \"currency\",\n options: { currency: currencyCodeFor(field.unit) },\n };\n case \"percent\":\n return { id: \"percent\" };\n case \"datetime\":\n // The COLUMN's declaration: a `kind: \"date\"` column is a date column, anything else can\n // hold a moment. Each VALUE is still printed in its own shape (`RecordValue` →\n // `dates.dateFormatFor(field, value)`), so a bare date in a datetime column reads as a date.\n return String(field.config?.[\"kind\"] ?? \"\") === \"date\" ? { id: \"date\" } : { id: \"datetime\" };\n case \"email\":\n return { id: \"email\" };\n case \"url\":\n return { id: \"url\" };\n case \"phone\":\n return { id: \"phone\" };\n case \"number\":\n return { id: \"number\" };\n default:\n return undefined;\n }\n}\n\n/**\n * THE FORMAT ONE CELL OF A COLUMN IS DRAWN IN — the grid's cell and the gallery's card alike\n * (guard G4 \"one format\", lane VIEWS-AND-FIELDS W1-B): the view's own format for the column when\n * it set one, else the Field's own (`formatForField`). One function, so no layout formats money\n * (or a date, or a percent) its own way.\n */\nexport function cellFormatFor(field: Field, viewFormat?: FieldFormatConfig | undefined): FieldFormatConfig | undefined {\n return viewFormat ?? formatForField(field);\n}\n\n/**\n * The store lets a person type the SYMBOL they think in (`$`, `€`), and\n * `Intl.NumberFormat` wants the ISO code. The symbols people actually enter are\n * mapped; anything else is passed straight through, because a real ISO code is\n * the other thing that lands in this field, and an unknown code still renders\n * (`1,234.00 XYZ`) rather than blanking — THE FALLBACK LAW.\n */\nconst SYMBOL_TO_CODE: Record<string, string> = {\n $: \"USD\",\n \"£\": \"GBP\",\n \"€\": \"EUR\",\n \"¥\": \"JPY\",\n \"₹\": \"INR\",\n \"₽\": \"RUB\",\n \"₩\": \"KRW\",\n \"R$\": \"BRL\",\n \"C$\": \"CAD\",\n \"A$\": \"AUD\",\n};\n\nexport function currencyCodeFor(unit: string | null | undefined): string {\n const raw = (unit ?? \"\").trim();\n if (raw === \"\") return \"USD\";\n return SYMBOL_TO_CODE[raw] ?? raw.toUpperCase();\n}\n\n/**\n * The color a value paints with when a view colors BY a column.\n *\n * NOTHING FAILS SILENTLY, so this never returns \"no color\" for a value that\n * exists. The store keeps a list column's choices as records of another Table,\n * and this grid has not read that Table's option colors, so the color is\n * derived from the value's own text: the same word always gets the same color,\n * different words get different ones, and `true` is green the way every\n * checklist reads. When those option colors do land, this is the ONE function\n * that changes and every screen follows.\n */\nexport const colorFromTheValue: ChoiceColorLookup = (_fieldKey, value) => {\n if (value === true) return \"green\";\n if (value === false || value === null || value === undefined) return undefined;\n const text = String(value).trim().toLowerCase();\n if (text === \"\") return undefined;\n let hash = 0;\n for (let i = 0; i < text.length; i += 1) {\n hash = (hash * 31 + text.charCodeAt(i)) >>> 0;\n }\n return COLOR_ROTATION[hash % COLOR_ROTATION.length] as StyleColor;\n};\n\n/**\n * G1's TABLE-LEVEL COLORS (`custom.table_decorations` / `client.tableDecorations`),\n * TRANSLATED INTO A `TableStyle` — the same document a saved view's own `presentation.style`\n * is, so one resolver (`resolveTableStyle`, below) can treat \"the table's colors\" and \"this\n * view's colors\" as two layers of the SAME thing instead of two unrelated systems.\n *\n * THE TRANSLATION IS NECESSARY AND IT IS THE ONLY ONE. G1 addresses a Field by its ID\n * (REC-17 — a column renamed keeps its color), because it is the STORE's own door; a\n * `TableStyle` addresses a Field by its KEY, because it reads straight off `row.document`,\n * which is keyed by Field key. A rule or a color-by whose Field has been deleted (its id no\n * longer resolves to a key) is dropped rather than crashing the whole style — a defect in\n * one rule costs that rule, never the read.\n */\nexport function styleFromDecorations(\n decorations: TableDecorations | null | undefined,\n fields: readonly Field[],\n): TableStyle {\n if (!decorations) return { version: 1 };\n const keyOf = (id: string) => fields.find((f) => f.id === id)?.key;\n const style: TableStyle = { version: 1 };\n\n if (decorations.color_by?.field) {\n const field = keyOf(decorations.color_by.field);\n if (field) style.colorBy = { field, target: decorations.color_by.target };\n }\n\n if (Array.isArray(decorations.rules) && decorations.rules.length > 0) {\n const rules: ColorRule[] = [];\n decorations.rules.forEach((rule, index) => {\n const field = keyOf(rule.field);\n if (!field) return;\n rules.push({\n id: rule.id ?? `decoration:${index}`,\n field,\n op: rule.op,\n color: rule.color,\n target: rule.target,\n ...(rule.value === undefined || rule.value === null ? {} : { value: String(rule.value) }),\n });\n });\n if (rules.length > 0) style.rules = rules;\n }\n\n if (decorations.rows && Object.keys(decorations.rows).length > 0) {\n style.rows = { ...decorations.rows };\n }\n\n const columns: Record<string, StyleColor> = {};\n for (const [id, color] of Object.entries(decorations.columns ?? {})) {\n const key = keyOf(id);\n if (key) columns[key] = color;\n }\n if (Object.keys(columns).length > 0) style.columns = columns;\n\n const cells: Record<string, Record<string, StyleColor>> = {};\n for (const [rowId, byField] of Object.entries(decorations.cells ?? {})) {\n for (const [id, color] of Object.entries(byField ?? {})) {\n const key = keyOf(id);\n if (!key) continue;\n (cells[rowId] ??= {})[key] = color;\n }\n }\n if (Object.keys(cells).length > 0) style.cells = cells;\n\n return style;\n}\n\n/**\n * THE ONE PRESENTATION RESOLVER every colored surface in this package reads —\n * `Grid`, and (via `Card`) the kanban board, the calendar and the gallery.\n *\n * THE CLASS THIS CLOSES (lane UI-QUICK-1, TABLE-PARITY review, 2026-09-24). Threading\n * `view.presentation.style` into `Card` closed the instance the CALENDAR-GALLERY bench\n * found — a VIEW that had its own color-by looked right everywhere — but it left the\n * class open: a table whose colors are the ORGANIZATION's decorations (G1's\n * `custom.table_decorations` — \"color rows by Account Type\", \"MAXED and NEAR rules\" on\n * Arman's own Coding Accounts table) and whose views never set a `presentation.style` of\n * their own drew NOTHING, on the grid exactly as much as on every other layout, because\n * nothing in this package had ever read G1's door at all.\n *\n * TWO LAYERS, ONE DOCUMENT. The table's decorations are the base coat — what every view\n * of this table shows until a view says otherwise. A view's OWN `presentation.style` is\n * an override, piece by piece: a view that only ever set manual row highlights still\n * inherits the table's color-by and rules for everything it never touched, and a view\n * that fully redecorated (its own `colorBy` AND its own `rules`) is not haunted by a\n * table rule it meant to replace. Per-piece, never all-or-nothing, because a view is a\n * LOOK on top of the table, not a wholesale substitute for it.\n */\nexport function resolveTableStyle(\n decorations: TableDecorations | null | undefined,\n fields: readonly Field[],\n viewStyle: TableStyle | undefined,\n): TableStyle {\n const base = styleFromDecorations(decorations, fields);\n if (!viewStyle) return base;\n const colorBy = viewStyle.colorBy ?? base.colorBy;\n const rules = viewStyle.rules ?? base.rules;\n const rows = viewStyle.rows ?? base.rows;\n const columns = viewStyle.columns ?? base.columns;\n const cells = viewStyle.cells ?? base.cells;\n return {\n version: 1,\n ...(colorBy !== undefined ? { colorBy } : {}),\n ...(rules !== undefined ? { rules } : {}),\n ...(rows !== undefined ? { rows } : {}),\n ...(columns !== undefined ? { columns } : {}),\n ...(cells !== undefined ? { cells } : {}),\n };\n}\n","// src/enumLabels.ts — @ai-matrx/records-ui\n//\n// ONE LABEL MAP PER ENUM. NOTHING ELSE IN THIS PACKAGE OWNS A COPY.\n//\n// Lane FRONT-DOOR's finding (2026-09-21): about twenty sites in this package\n// turned an enum VALUE the store already canonicalizes into a person-facing\n// word, each one on its own — worst example, `ChecklistRunner.tsx` called the\n// work-due state \"finished\" **\"Done\"** while `ActionInbox.tsx`, reading the\n// SAME `WorkDueState` off the SAME `custom.work_inbox`/`checklist_run` doors,\n// called it **\"Finished\"**. A person moving between a table's checklist tab\n// and her inbox saw two different words for one fact about her own work.\n//\n// So every enum this package draws a label for is named ONCE, here, keyed by\n// its canonical values — imported from `@ai-matrx/records` wherever the store\n// exports a named type/const for it, and named locally (with the reason) where\n// it does not. A panel imports the map; it never writes its own.\n//\n// THE GUARD: `enumLabels.test.tsx` renders every converted panel's label\n// function over the FULL canonical value list of its enum (pulled from\n// `@ai-matrx/records`, not retyped) and fails the moment a value has no entry\n// or a caller falls through to the raw token. See that file for RED/GREEN.\n\nimport type {\n ChecklistRequirementKind,\n ContextPolicy,\n FieldSensitivity,\n StageRuleOnFail,\n SubscriptionCadence,\n WorkDueState,\n WorkInboxKind,\n WorkApprovalState,\n} from \"@ai-matrx/records\";\n\n/**\n * An array literal checked, AT COMPILE TIME, to name every member of `T` and no\n * extra one. `WorkDueState`, `WorkInboxKind`, `ChecklistRequirementKind` and\n * `SubscriptionCadence` are typed unions in `@ai-matrx/records` with no\n * runtime array exported alongside them — so this is how the four `*_VALUES`\n * lists below stay tied to the PACKAGE'S OWN TYPE instead of drifting from it\n * by hand: add a sixth `WorkDueState` in `@ai-matrx/records` and `tsc` refuses\n * this file until the array is updated to name it too. The census test below\n * imports these arrays rather than the store's raw union so it is exercising\n * the same list this file's label maps are keyed against.\n */\nfunction exhaustiveValuesOf<T extends string>() {\n return function <const U extends readonly T[]>(values: [T] extends [U[number]] ? U : never): U {\n return values as U;\n };\n}\n\n// ── work due state — WorkDueState (packages/records/src/work.ts) ───────────\n//\n// Shared by a checklist step (`checklist_run().due_state`) and a work-inbox\n// row (`work_inbox().due_state`, `work_list().due_state`) — ONE enum, drawn in\n// both a checklist runner and an approvals inbox. This is the pair the finding\n// named: \"finished\" read \"Done\" in one and \"Finished\" in the other. **\"Done\"\n// wins** — it is the word a non-technical business owner actually says out\n// loud about a piece of work (\"is that job done yet?\"), it is one syllable\n// shorter than the other four words in this set are used to being read\n// alongside (\"Overdue\", \"Today\", \"Scheduled\", \"No date\"), and \"Finished\" reads\n// more like a formal status report than a plain answer to \"is it done\".\nexport const WORK_DUE_STATES = exhaustiveValuesOf<WorkDueState>()([\n \"overdue\",\n \"due_today\",\n \"scheduled\",\n \"undated\",\n \"finished\",\n]);\nexport const DUE_STATE_LABEL: Record<WorkDueState, string> = {\n overdue: \"Overdue\",\n due_today: \"Today\",\n scheduled: \"Scheduled\",\n undated: \"No date\",\n finished: \"Done\",\n};\n\n// ── work inbox kind — WorkInboxKind (packages/records/src/work.ts) ─────────\nexport const WORK_INBOX_KINDS = exhaustiveValuesOf<WorkInboxKind>()([\"assignment\", \"approval\", \"proposal\"]);\n// UI-FIX-19 (VERIFIER-19 #6): a kind is a NOUN. \"Approve\" in the row's bordered kind badge read as\n// a live Approve control on every withdrawn and decided item; only a control may be a verb.\nexport const WORK_INBOX_KIND_LABEL: Record<WorkInboxKind, string> = {\n assignment: \"Assigned\",\n approval: \"Approval\",\n proposal: \"Agent proposal\",\n};\n/** The heading an inbox grouped by kind reads (lane S5-PRIME) — plural, the way Linear groups. */\nexport const WORK_INBOX_KIND_GROUP_LABEL: Record<WorkInboxKind, string> = {\n approval: \"Approvals\",\n proposal: \"Agent proposals\",\n assignment: \"Assigned to you\",\n};\n\n// ── approval state — WorkApprovalState (packages/records/src/work.ts) ──────\n// Lane S5-PRIME: a closed item says what happened to it. `withdrawn` is the store's own close —\n// the thing it would change was archived — never a person's decision.\nexport const WORK_APPROVAL_STATES = exhaustiveValuesOf<WorkApprovalState>()([\"pending\", \"approved\", \"declined\", \"withdrawn\"]);\nexport const WORK_APPROVAL_STATE_LABEL: Record<WorkApprovalState, string> = {\n pending: \"Waiting\",\n approved: \"Approved\",\n declined: \"Declined\",\n withdrawn: \"Withdrawn\",\n};\n\n// ── checklist requirement kind — ChecklistRequirementKind (checklist.ts) ───\nexport const CHECKLIST_REQUIREMENT_KINDS = exhaustiveValuesOf<ChecklistRequirementKind>()([\n \"none\",\n \"note\",\n \"answer\",\n \"record_field\",\n \"form\",\n \"document\",\n]);\nexport const CHECKLIST_REQUIREMENT_LABEL: Record<ChecklistRequirementKind, string> = {\n none: \"\",\n note: \"Say what you did\",\n answer: \"Fill this in\",\n record_field: \"This has to be filled in on the record\",\n form: \"This step is a form\",\n document: \"This step is a document\",\n};\n\n// ── field sensitivity — FieldSensitivity (vocabulary.ts, FLD-12/AGT-7) ─────\nexport const FIELD_SENSITIVITY_LABEL: Record<FieldSensitivity, string> = {\n public: \"Anyone who can open the record\",\n internal: \"People in this organization\",\n confidential: \"People who have been given the record\",\n restricted: \"Owners and administrators only\",\n};\n\n// ── context policy — ContextPolicy (vocabulary.ts, FLD-12) ─────────────────\n// Whether an agent may see a Field's values at all — not `Delivery` (how much\n// of a merge field's value reaches a turn), a different vocabulary entirely.\nexport const CONTEXT_POLICY_LABEL: Record<ContextPolicy, string> = {\n include: \"Yes, an assistant can read it\",\n summarize: \"Only a summary of it\",\n on_request: \"Only when somebody asks for it\",\n exclude: \"No, keep it away from assistants\",\n};\n\n// ── stage-rule on_fail — StageRuleOnFail (pipeline.ts) ──────────────────────\nexport const STAGE_RULE_ON_FAIL_LABEL: Record<StageRuleOnFail, string> = {\n refuse: \"Turn it away\",\n require_approval: \"Ask for approval\",\n};\n\n// ── subscription cadence — SubscriptionCadence (subscription.ts) ───────────\n//\n// `DigestScheduler.tsx` carries its own copy of this enum's words as a\n// grammatical FRAGMENT dropped into a sentence (\"arrives the moment something\n// arrives\") rather than a standalone label (\"hourly summary\") — a different\n// job for the same four values. That file is owned by another lane right now\n// (lane preamble's do-not-touch list) so it is left exactly as it is; this map\n// is the standalone-label form used by every OTHER site that names a cadence.\nexport const SUBSCRIPTION_CADENCES = exhaustiveValuesOf<SubscriptionCadence>()([\"instant\", \"hourly\", \"daily\", \"weekly\"]);\nexport const SUBSCRIPTION_CADENCE_LABEL: Record<SubscriptionCadence, string> = {\n instant: \"as it happens\",\n hourly: \"hourly summary\",\n daily: \"daily summary\",\n weekly: \"weekly summary\",\n};\n\n// ── subscription channel — no named export in @ai-matrx/records ───────────\n//\n// `Subscription.channel` is typed inline as `\"in_app\" | \"email\" | \"sms\"`\n// (subscription.ts) with no exported const array, so the value list below IS\n// the canonical list — the same three literals the store's type carries.\nexport const SUBSCRIPTION_CHANNEL_VALUES = [\"in_app\", \"email\", \"sms\"] as const;\nexport type SubscriptionChannel = (typeof SUBSCRIPTION_CHANNEL_VALUES)[number];\n// `NotifyRuleEditor.tsx` used to say plain \"by email\" / \"by text\" with no\n// caveat; `SubscriptionsPanel.tsx` (and the untouched `DigestScheduler.tsx`)\n// say \"only if an address/number is on the account\". **The caveat wins** — a\n// person choosing email delivery needs to know up front that it silently does\n// nothing without an address on file, the way Linear and Notion surface a\n// precondition next to the control rather than failing quietly later.\nexport const SUBSCRIPTION_CHANNEL_LABEL: Record<SubscriptionChannel, string> = {\n in_app: \"in the app\",\n email: \"by email — only if an address is on the account\",\n sms: \"by text — only if a number is on the account\",\n};\n\n// ── rollup aggregate operation — NewFieldDeclaration[\"agg\"] (field.ts) ─────\n//\n// `field.ts` types this inline (`agg?: \"sum\" | \"count\" | \"min\" | \"max\" |\n// \"avg\"`) with no exported const array, so — same as the channel above — the\n// list below IS the canonical list.\nexport const ROLLUP_AGG_VALUES = [\"count\", \"sum\", \"avg\", \"min\", \"max\"] as const;\nexport type RollupAgg = (typeof ROLLUP_AGG_VALUES)[number];\nexport const ROLLUP_AGG_LABEL: Record<RollupAgg, string> = {\n count: \"How many there are\",\n sum: \"The total of\",\n avg: \"The average of\",\n min: \"The smallest\",\n max: \"The largest\",\n};\n\n// ── formula operation — the FormulaOperations menu (FieldEditor.tsx) ───────\n//\n// No `@ai-matrx/records` type names this set at all; it is this package's own\n// menu of what a two-column formula field can do, so this file is its one\n// canonical home.\nexport const FORMULA_OP_VALUES = [\"concat\", \"add\", \"sub\", \"mul\", \"div\"] as const;\nexport type FormulaOp = (typeof FORMULA_OP_VALUES)[number];\nexport const FORMULA_OP_LABEL: Record<FormulaOp, string> = {\n concat: \"Join them together\",\n add: \"Add them up\",\n sub: \"Take the second from the first\",\n mul: \"Multiply them\",\n div: \"Divide the first by the second\",\n};\n/** Whether this operation reads naturally as \"X and Y and Z…\" over more than two columns. */\nexport const FORMULA_OP_JOINS: Record<FormulaOp, boolean> = {\n concat: true,\n add: true,\n sub: false,\n mul: true,\n div: false,\n};\n\n// ── field validation-rule kind — FieldRule[\"kind\"] (field.ts) ──────────────\n//\n// `field.ts` types this inline with no exported const array; canonical here.\nexport const FIELD_RULE_KIND_VALUES = [\"min\", \"max\", \"length\", \"pattern\", \"equals_field\", \"differs_from_field\"] as const;\nexport type FieldRuleKindValue = (typeof FIELD_RULE_KIND_VALUES)[number];\nexport const FIELD_RULE_KIND_LABEL: Record<FieldRuleKindValue, string> = {\n min: \"At least\",\n max: \"At most\",\n length: \"Number of characters\",\n pattern: \"Looks like\",\n equals_field: \"Same as the column\",\n differs_from_field: \"Different from the column\",\n};\n\n// ── proposed-change act — `ProposedChange[\"act\"]` (ProposalRow.tsx, package-local) ──\n//\n// This type is not in `@ai-matrx/records` (`ProposalRow.tsx` declares it\n// itself, for an agent's field/table proposal), so it is canonical here.\nexport const PROPOSED_CHANGE_ACT_VALUES = [\"add\", \"update\", \"remove\"] as const;\nexport type ProposedChangeAct = (typeof PROPOSED_CHANGE_ACT_VALUES)[number];\nexport const PROPOSED_CHANGE_ACT_LABEL: Record<ProposedChangeAct, string> = {\n add: \"Add\",\n update: \"Update\",\n remove: \"Remove\",\n};\n\n// ── booking-page state — `FormSummary[\"state\"]` / `BookingSummary` (rule.ts) ──\n//\n// `rule.ts` types this inline (`\"draft\" | \"open\" | \"closed\" | \"full\"`) with no\n// exported const array; canonical here.\nexport const BOOKING_PAGE_STATE_VALUES = [\"draft\", \"open\", \"closed\", \"full\"] as const;\nexport type BookingPageState = (typeof BOOKING_PAGE_STATE_VALUES)[number];\nexport const BOOKING_PAGE_STATE_LABEL: Record<BookingPageState, string> = {\n draft: \"Not open yet — nobody can book until you open it.\",\n open: \"Open. Anyone with the link can book a time.\",\n closed: \"Closed. The link still works and says you are not taking bookings.\",\n full: \"Every time you offered is taken.\",\n};\n\n// ── value-envelope absence word — `ValueEnvelope.absent` (record.ts) ───────\n//\n// Kept for completeness of the census: `values.tsx` mapped each absence word\n// to itself (`\"none\" → \"none\"`), which is a passthrough with a safe fallback\n// rather than a wording decision, so there is no conflict to resolve — this is\n// still its one home so a future word change happens in one place.\nexport const ABSENCE_WORD_VALUES = [\"never asked\", \"none\", \"refused\", \"conflicting\"] as const;\nexport type AbsenceWord = (typeof ABSENCE_WORD_VALUES)[number];\nexport const ABSENCE_WORD_LABEL: Record<AbsenceWord, string> = {\n \"never asked\": \"never asked\",\n none: \"none\",\n refused: \"refused\",\n conflicting: \"conflicting\",\n};\n","\"use client\";\n\n// src/EntityReferenceControl.tsx — @ai-matrx/records-ui · lane SC-R (P12), REFERENCE-CARRY\n//\n// A CELL THAT POINTS AT A PLATFORM THING — the intake note of a client matter, the client's web\n// site, the agent a row runs — drawn as what it names, never as `[object Object]` in a text box,\n// and edited with a PICKER, never by typing ids.\n//\n// Every read door answers an entity-reference value as `{token, id, label}`, the label withheld\n// (null) from a reader who may not open the thing. This control draws one chip per reference with\n// the store's label (or, for a value not yet saved, the words `useEntityReferenceWords` reads for\n// THIS person), lets a person take a reference off, and — since lane REFERENCE-CARRY — ADD one:\n// the store's search door (`custom.entity_reference_search`) lists the things of the column's kinds\n// this person may point a record at, each one the store's own write check would accept.\n\nimport { useMemo, useState, type ReactNode } from \"react\";\nimport { entityRefsOf, entityRefsToWrite, type EntityRefWithWords, type Field } from \"@ai-matrx/records\";\nimport { useEntityReferenceKinds, useEntityReferenceSearch, useEntityReferenceWords, useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { Badge, Button, cn } from \"@ai-matrx/design-system\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { RefusalLine } from \"./Refusal\";\nimport { PickOne } from \"./PickOne\";\n\n/** What a chip says when the store withheld the thing's words from this reader. */\nexport const WITHHELD_ENTITY_LABEL = \"Something you have not been given access to\";\n\n/** What an empty entity-reference cell says where nothing can be added (a signed-out form). */\nexport const ENTITY_REFERENCE_EMPTY = \"Nothing is pointed at yet.\";\n\n/** The words of an entity-reference value for a sentence or a plain-text cell. */\nexport function entityReferenceText(value: unknown): string {\n const refs = entityRefsOf(value);\n if (refs.length === 0) return \"—\";\n return refs.map((r) => r.label ?? WITHHELD_ENTITY_LABEL).join(\", \");\n}\n\n/** The kinds a column may point at (`config.allowed_types`), in the order it names them. */\nexport function allowedKindsOf(field: Field): string[] {\n const config = (field.config ?? {}) as Record<string, unknown>;\n const kinds = Array.isArray(config.allowed_types) ? config.allowed_types : [];\n return kinds.map((k) => String(k).trim().toLowerCase()).filter(Boolean);\n}\n\nexport interface EntityReferenceControlProps {\n field: Field;\n value: unknown;\n onChange: (next: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n}\n\n/**\n * A signed-out public form mounts no store client, so there is nobody to ask for words or search:\n * the chips there draw what the value already carries and nothing can be added. Inside a client the\n * unlabelled ones are read and the picker is offered.\n */\nexport function EntityReferenceControl(props: EntityReferenceControlProps) {\n const client = useOptionalRecordsClient();\n return client ? <WithWords {...props} /> : <Chips {...props} words={null} picker={null} />;\n}\n\ntype Words = { data: { token: string; id: string; label: string | null }[] | null; loading: boolean } | null;\n\nfunction WithWords(props: EntityReferenceControlProps) {\n const refs = useMemo(() => entityRefsOf(props.value), [props.value]);\n // Picked in this editing session: their words are known, so nobody is asked for them again.\n const [known, setKnown] = useState<EntityRefWithWords[]>([]);\n const withKnown = refs.map((r) => (r.label === null ? (known.find((k) => k.token === r.token && k.id === r.id) ?? r) : r));\n // Only the references that arrived WITHOUT words (a value not yet saved) are asked about.\n const unlabelled = useMemo(\n () => withKnown.filter((r) => r.label === null).map((r) => ({ token: r.token, id: r.id })),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(withKnown)],\n );\n const words = useEntityReferenceWords(unlabelled);\n const picker = props.disabled ? null : (\n <EntityReferencePicker\n field={props.field}\n refs={withKnown}\n onPick={(picked) => {\n setKnown((k) => [...k.filter((x) => !(x.token === picked.token && x.id === picked.id)), picked]);\n const multi = Boolean(props.field.multi);\n const next = multi ? [...withKnown.filter((x) => !(x.token === picked.token && x.id === picked.id)), picked] : [picked];\n props.onChange(entityRefsToWrite(next, multi));\n }}\n />\n );\n return <Chips {...props} value={withKnown} words={words} picker={picker} />;\n}\n\n/**\n * THE PICKER: which kind (when the column allows more than one), a search box, the things found.\n * Built from the one pick-or-add builder (`PickOrAdd.tsx`), so it keeps the keys every picker keeps.\n * There is no add line: a platform thing is made where it lives, never from a table cell.\n */\nfunction EntityReferencePicker({\n field,\n refs,\n onPick,\n}: {\n field: Field;\n refs: EntityRefWithWords[];\n onPick: (picked: EntityRefWithWords) => void;\n}) {\n const allowed = allowedKindsOf(field);\n const kinds = useEntityReferenceKinds();\n const labelOfKind = (token: string) => kinds.data?.find((k) => k.token === token)?.label ?? token.replace(/_/g, \" \");\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n // \"Any of them\" first; one kind narrows the list.\n const [only, setOnly] = useState<string | null>(null);\n const tokens = only ? [only] : allowed;\n const found = useEntityReferenceSearch(tokens, search, open);\n const multi = Boolean(field.multi);\n const items = (found.data ?? []).map((r) => ({\n id: `${r.token}:${r.id}`,\n label: r.label ?? WITHHELD_ENTITY_LABEL,\n detail: allowed.length > 1 ? labelOfKind(r.token) : null,\n picked: refs.some((x) => x.token === r.token && x.id === r.id),\n attrs: { \"data-entity-reference-candidate\": `${r.token}:${r.id}` },\n }));\n const kindChoice =\n allowed.length > 1 ? (\n allowed.length <= 4 ? (\n <div className=\"mb-1 flex flex-wrap gap-1\" role=\"group\" aria-label={`Which kind — ${field.label}`}>\n {[null, ...allowed].map((token) => (\n <Button\n key={token ?? \"any\"}\n type=\"button\"\n size=\"sm\"\n variant={only === token ? \"secondary\" : \"ghost\"}\n className=\"h-6 px-2 text-[11px]\"\n aria-pressed={only === token}\n onClick={() => setOnly(token)}\n >\n {token ? labelOfKind(token) : \"Any\"}\n </Button>\n ))}\n </div>\n ) : (\n <PickOne\n label={`Which kind — ${field.label}`}\n className=\"mb-1 w-full\"\n value={only ?? \"\"}\n onChange={(picked) => setOnly(picked || null)}\n options={[{ value: \"\", label: \"Any kind\" }, ...allowed.map((token) => ({ value: token, label: labelOfKind(token) }))]}\n />\n )\n ) : null;\n const notice = (\n <>\n {kindChoice}\n {found.error ? <RefusalLine error={found.error} className=\"px-2 py-1 text-[11px]\" /> : null}\n {found.loading && !found.data ? <p className=\"px-2 py-1 text-[11px] text-muted-foreground\">Searching…</p> : null}\n </>\n );\n const kindWords = allowed.length === 1 ? labelOfKind(allowed[0]!).toLowerCase() : \"thing\";\n return (\n <PickOrAdd\n triggerLabel={`Pick for ${field.label}`}\n triggerText={refs.length > 0 && !multi ? \"Change\" : \"Pick\"}\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearch(\"\");\n }}\n search={search}\n onSearch={setSearch}\n items={items}\n notice={notice}\n empty={\n found.loading ? null : (\n <p className=\"px-2 py-1 text-[11px] text-muted-foreground\">\n {search.trim() ? `No ${kindWords} you can open is called “${search.trim()}”.` : `There is no ${kindWords} you can open yet.`}\n </p>\n )\n }\n onPick={(key) => {\n const r = (found.data ?? []).find((x) => `${x.token}:${x.id}` === key);\n if (!r) return;\n onPick(r);\n if (!multi) setOpen(false);\n }}\n />\n );\n}\n\nfunction Chips({\n field,\n value,\n onChange,\n disabled,\n id,\n className,\n words,\n picker,\n}: EntityReferenceControlProps & { words: Words; picker: ReactNode }) {\n const refs = useMemo(() => entityRefsOf(value), [value]);\n const labelOf = (token: string, refId: string, own: string | null): string => {\n if (own) return own;\n const read = words?.data?.find((w) => w.token === token && w.id === refId)?.label;\n if (read) return read;\n if (words === null) return \"A linked item (its name is read when you are signed in)\";\n if (words.loading) return \"Reading…\";\n return WITHHELD_ENTITY_LABEL;\n };\n const multi = Boolean(field.multi);\n\n return (\n <div id={id} className={cn(\"flex flex-wrap items-center gap-1\", className)} aria-label={`What ${field.label} points at`}>\n {refs.length === 0 && !picker ? <span className=\"text-[11px] text-muted-foreground\">{ENTITY_REFERENCE_EMPTY}</span> : null}\n {refs.map((r) => {\n const label = labelOf(r.token, r.id, r.label);\n return (\n <Badge key={`${r.token}:${r.id}`} variant=\"secondary\" className=\"gap-1 text-[11px]\" data-entity-reference-chip={`${r.token}:${r.id}`}>\n {label}\n {disabled ? null : (\n <button\n type=\"button\"\n className=\"ml-0.5 rounded-sm px-0.5 opacity-70 hover:opacity-100\"\n aria-label={`Take ${label} off`}\n onClick={() => {\n const rest = refs.filter((x) => !(x.token === r.token && x.id === r.id));\n onChange(entityRefsToWrite(rest, multi));\n }}\n >\n ×\n </button>\n )}\n </Badge>\n );\n })}\n {picker}\n </div>\n );\n}\n","\"use client\";\n\n// src/PickOne.tsx — @ai-matrx/records-ui · THE ONE \"PICK ONE OF THESE\" CONTROL (lane VIEWS-AND-FIELDS\n// W1-B, verifier item 4, 2026-10-02 — Airtable, Linear).\n//\n// The package drew about forty-five native <select>s: an OS menu that ignores the theme, cannot be\n// searched, and reads differently from every picker beside it. Every pick of one value from a list\n// now goes through here: the design system's Select for a short list, and past\n// `PICK_ONE_SEARCH_AFTER` options the package's own searchable list (`PickOrAdd`), so a table with\n// thirty columns is typed into, never scrolled. Guard: `no-native-select-in-the-package.test.ts`.\n//\n// An empty value (\"\" — \"no sort\", \"count only\", \"any kind\") is a real option here: Radix refuses an\n// empty item value, so it travels as a sentinel inside and comes back out as \"\".\n\nimport { useState } from \"react\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue, cn } from \"@ai-matrx/design-system\";\n\nimport { PickOrAdd } from \"./PickOrAdd\";\n\n/** One option: its value (may be \"\") and the words it reads as. */\nexport interface PickOneOption {\n value: string;\n label: string;\n /** The heading it sits under (a short list draws headings; a searchable one shows it under the item). */\n group?: string | undefined;\n}\n\n/** More options than this and the list is searchable. */\nexport const PICK_ONE_SEARCH_AFTER = 7;\n\nconst EMPTY = \"__records_pick_one_empty__\";\nconst inner = (v: string) => (v === \"\" ? EMPTY : v);\nconst outer = (v: string) => (v === EMPTY ? \"\" : v);\n\nexport function PickOne({\n value,\n onChange,\n options,\n label,\n placeholder,\n id,\n className,\n disabled,\n attrs,\n}: {\n value: string;\n onChange: (value: string) => void;\n options: readonly PickOneOption[];\n /** The control's accessible name. */\n label: string;\n /** What the trigger reads when the value is none of the options. */\n placeholder?: string | undefined;\n id?: string | undefined;\n className?: string | undefined;\n disabled?: boolean | undefined;\n /** Attributes a caller's tests and walks select by (`data-…`), put on the trigger. */\n attrs?: Record<string, string> | undefined;\n}) {\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const current = options.find((o) => o.value === value);\n\n if (options.length > PICK_ONE_SEARCH_AFTER) {\n const q = search.trim().toLowerCase();\n const shown = q === \"\" ? options : options.filter((o) => o.label.toLowerCase().includes(q));\n return (\n <span className={cn(\"inline-flex min-w-0\", className)} data-records-pick-one=\"search\" data-pick-value={value} {...(attrs ?? {})}>\n <PickOrAdd\n triggerSize=\"compact\"\n triggerLabel={label}\n triggerText={current?.label ?? placeholder ?? \"\"}\n triggerId={id}\n open={open && !disabled}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearch(\"\");\n }}\n search={search}\n onSearch={setSearch}\n items={shown.map((o) => ({\n id: inner(o.value),\n label: o.label,\n detail: o.group,\n picked: o.value === value,\n attrs: { \"data-pick-value\": o.value, ...(o.group ? { \"data-pick-group\": o.group } : {}) },\n }))}\n onPick={(picked) => {\n onChange(outer(picked));\n setOpen(false);\n setSearch(\"\");\n }}\n empty={<p className=\"p-2 text-xs text-muted-foreground\">No match</p>}\n />\n </span>\n );\n }\n return (\n <Select value={current ? inner(current.value) : \"\"} onValueChange={(v) => onChange(outer(v))} disabled={disabled ?? false}>\n <SelectTrigger\n id={id}\n size=\"sm\"\n aria-label={label}\n className={cn(\"h-7 w-auto min-w-[7rem] text-xs\", className)}\n data-records-pick-one=\"list\"\n data-pick-value={value}\n {...(attrs ?? {})}\n >\n <SelectValue placeholder={placeholder} />\n </SelectTrigger>\n <SelectContent>\n {groupsOf(options).map(([group, items]) =>\n group ? (\n <SelectGroup key={group}>\n <SelectLabel>{group}</SelectLabel>\n {items.map((o) => (\n <SelectItem key={inner(o.value)} value={inner(o.value)} data-pick-value={o.value} data-pick-group={group}>\n {o.label}\n </SelectItem>\n ))}\n </SelectGroup>\n ) : (\n items.map((o) => (\n <SelectItem key={inner(o.value)} value={inner(o.value)} data-pick-value={o.value}>\n {o.label}\n </SelectItem>\n ))\n ),\n )}\n </SelectContent>\n </Select>\n );\n}\n\n/** Options in their own order, cut into runs that share a heading. */\nfunction groupsOf(options: readonly PickOneOption[]): Array<[string | undefined, PickOneOption[]]> {\n const out: Array<[string | undefined, PickOneOption[]]> = [];\n for (const o of options) {\n const last = out[out.length - 1];\n if (last && last[0] === o.group) last[1].push(o);\n else out.push([o.group, [o]]);\n }\n return out;\n}\n","\"use client\";\n\n// src/WholeValue.tsx — @ai-matrx/records-ui\n//\n// A VALUE TOO BIG FOR ONE CELL, SHOWN HONESTLY. The store keeps the whole text as a file and the\n// cell holds its first words (`@ai-matrx/records/core` `wholeValueOf`). A cell that drew only the\n// words would pass the start of a 700 KB research text off as the whole value; so it draws the\n// words, then says how big the whole text is and opens it — through the host's page for files\n// (`hrefForFile`). Unbound, it says the whole text is kept as a file this screen cannot open:\n// absent or honest, never a dead link.\n\nimport { useEffect, useState } from \"react\";\nimport type { Field, Uuid } from \"@ai-matrx/records\";\nimport { wholeValueSize, type WholeValuePointer } from \"@ai-matrx/records/core\";\nimport { BasicTextarea } from \"@ai-matrx/design-system\";\nimport { useRecordsUi } from \"./host\";\nimport { fieldName } from \"./names\";\n\nexport const WHOLE_VALUE_UNBOUND =\n \"The whole text is kept as a file, and this screen has no way to open files yet.\";\n\nexport function wholeValueLine(pointer: WholeValuePointer): string {\n return `Open the whole text (${wholeValueSize(pointer)})`;\n}\n\nexport function WholeValueCell({ words, pointer }: { words: string; pointer: WholeValuePointer }) {\n const host = useRecordsUi();\n const href = host.hrefForFile?.({ fileId: pointer.file_id as Uuid });\n const line = wholeValueLine(pointer);\n return (\n <span className=\"flex min-w-0 items-baseline gap-2\" data-whole-value-file={pointer.file_id}>\n <span className=\"truncate\" title={`The first ${pointer.shown_chars} of ${pointer.chars} characters`}>\n {words}…\n </span>\n {href ? (\n host.Link ? (\n host.Link({ href, children: line, className: \"shrink-0 text-xs text-primary underline-offset-2 hover:underline\" })\n ) : (\n <a className=\"shrink-0 text-xs text-primary underline-offset-2 hover:underline\" href={href} target=\"_blank\" rel=\"noreferrer\">\n {line}\n </a>\n )\n ) : (\n <span className=\"shrink-0 text-xs italic text-muted-foreground\" title={WHOLE_VALUE_UNBOUND}>\n {`${wholeValueSize(pointer)} in a file`}\n </span>\n )}\n </span>\n );\n}\n\n// ── EDITING A TEXT KEPT AS A FILE (lane BIG-VALUES-WRITE, 2026-09-25) ─────────────────────────\n//\n// A text of any size simply saves: the store keeps the first 1000 characters in the cell and the\n// whole text as a file, behind the scenes. So an editor must never start from those 1000\n// characters — saving them would replace the whole text with its start. It opens the WHOLE text\n// (the host's `readFileText`), and a save writes the whole edited text; the store files it again as\n// the next version. A host that cannot read files gets the words and the link, never an editor\n// that would cut the value.\n\nexport const WHOLE_VALUE_NOT_EDITABLE_HERE =\n \"The whole text is kept as a file. Open it to read it; this screen cannot load it to edit.\";\n\n/** The sentence a person reads while the whole text is being opened. */\nexport function wholeValueOpening(pointer: WholeValuePointer): string {\n return `Opening the whole text (${wholeValueSize(pointer)})…`;\n}\n\nexport type WholeText =\n | { state: \"loading\" }\n | { state: \"ready\"; text: string }\n | { state: \"failed\"; why: string }\n | { state: \"unbound\" };\n\n/** The whole text behind a pointer, read once through the host. */\nexport function useWholeText(pointer: WholeValuePointer | null): WholeText {\n const host = useRecordsUi();\n const read = host.readFileText;\n const fileId = pointer?.file_id ?? null;\n const [answer, setAnswer] = useState<WholeText>({ state: \"loading\" });\n useEffect(() => {\n if (!fileId) return;\n if (!read) {\n setAnswer({ state: \"unbound\" });\n return;\n }\n let live = true;\n setAnswer({ state: \"loading\" });\n read({ fileId: fileId as Uuid }).then(\n (text) => live && setAnswer({ state: \"ready\", text }),\n (thrown: unknown) =>\n live && setAnswer({ state: \"failed\", why: thrown instanceof Error ? thrown.message : String(thrown) }),\n );\n return () => {\n live = false;\n };\n }, [fileId, read]);\n return answer;\n}\n\n/**\n * THE RECORD FORM'S EDITOR FOR A TEXT KEPT AS A FILE. `value` is what the form holds: the stored\n * words until the person types, then what they typed. Until they type, the box shows the whole text\n * read from the file — so nothing is marked changed by opening it.\n */\nexport function WholeValueEditor({\n field,\n pointer,\n words,\n value,\n onChange,\n id,\n disabled,\n}: {\n field: Field;\n pointer: WholeValuePointer;\n words: string;\n value: unknown;\n onChange: (value: unknown) => void;\n id: string;\n disabled?: boolean;\n}) {\n const whole = useWholeText(pointer);\n const touched = typeof value === \"string\" ? value !== words : value !== null && value !== undefined;\n if (touched) {\n return (\n <BasicTextarea\n id={id}\n rows={12}\n value={value === null || value === undefined ? \"\" : String(value)}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n data-whole-value-editor={pointer.file_id}\n />\n );\n }\n if (whole.state === \"ready\") {\n return (\n <BasicTextarea\n id={id}\n rows={12}\n value={whole.text}\n disabled={disabled}\n onChange={(e) => onChange(e.target.value === \"\" ? null : e.target.value)}\n data-whole-value-editor={pointer.file_id}\n aria-label={fieldName(field)}\n />\n );\n }\n return (\n <div id={id} className=\"flex flex-col gap-1 rounded border px-2 py-1.5 text-sm\">\n <WholeValueCell words={words} pointer={pointer} />\n <span className=\"text-xs text-muted-foreground\">\n {whole.state === \"loading\"\n ? wholeValueOpening(pointer)\n : whole.state === \"failed\"\n ? `The whole text could not be opened to edit (${whole.why}). Open it to read it.`\n : WHOLE_VALUE_NOT_EDITABLE_HERE}\n </span>\n </div>\n );\n}\n","\"use client\";\n\n// src/formattedValue.tsx — @ai-matrx/records-ui · merge tranche 6e (formats)\n//\n// A VALUE IN THE FORMAT ITS COLUMN SHOWS AS — the older /data grid's `FormattedFieldValue`,\n// rewritten onto the platform registry (`@ai-matrx/design-system/field-formats`) with no app\n// import: a star rating is stars, a progress column is a bar, an email is a mail link, an\n// address opens in maps, a colour is its swatch, tags are chips. Everything else is the\n// registry's own text, through the design-system's `FormattedCell`, so the fallback law rides\n// along: a value that does not fit its format is shown as stored, in amber, with the reason.\n//\n// A rating is ONE click from the read view (THE CLICK LAW, inventory A2): given `onRate`, each\n// star is a button that writes its number; without it the stars are a picture.\n\nimport { useRef, type ReactNode } from \"react\";\nimport { FormattedCell } from \"@ai-matrx/design-system/data-table\";\nimport { formatFieldValue, formatPhone, getFieldFormat, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\nimport { cn } from \"@ai-matrx/design-system\";\n\nconst LINK = \"inline-flex min-w-0 items-center gap-1 text-primary hover:underline\";\n\n/** Stop a link's click from also opening the cell or the row behind it. */\nconst own = (event: { stopPropagation: () => void }) => event.stopPropagation();\n\n/** The number a rating or a bar reads, or null. */\nfunction numberOf(value: unknown): number | null {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : null;\n if (typeof value === \"string\" && value.trim() !== \"\") {\n const n = Number(value.replace(/[,\\s%]/g, \"\"));\n return Number.isFinite(n) ? n : null;\n }\n return null;\n}\n\n/** A star rating. `onRate` makes each star a control; a second press on the chosen star clears it. */\nexport function RatingStars({\n value,\n max = 5,\n onRate,\n label,\n selectFirst,\n}: {\n value: unknown;\n max?: number;\n onRate?: ((next: number | null) => void) | undefined;\n label?: string;\n /**\n * IN A GRID, A CLICK SELECTS (grids review 3, 2026-09-30: one click on a rating cell wrote 4\n * stars). A press on a star of a cell that is not yet the grid's cursor reaches the grid, which\n * selects the cell, and writes nothing; once the cell is selected a star press rates it (Airtable).\n * A keyboard press on a star (`detail === 0`) always rates.\n */\n selectFirst?: boolean | undefined;\n}) {\n // Was this star's cell already the grid's cursor when the pointer came down? Read at the press,\n // before the grid's own mousedown moves the cursor there.\n const armed = useRef(true);\n const score = numberOf(value) ?? 0;\n const shown = Math.round(score);\n const said = `${shown} out of ${max}`;\n return (\n <span\n data-records-rating=\"\"\n role={onRate ? \"radiogroup\" : \"img\"}\n aria-label={label ? `${label}: ${said}` : said}\n title={said}\n className=\"inline-flex items-center gap-0.5\"\n {...(onRate ? { \"data-matrx-cell-control\": \"\" } : {})}\n >\n {Array.from({ length: max }, (_, i) => {\n const n = i + 1;\n const lit = n <= shown;\n const star = (\n <span aria-hidden className={cn(\"text-sm leading-none\", lit ? \"text-amber-400\" : \"text-muted-foreground/40\")}>\n ★\n </span>\n );\n return onRate ? (\n <button\n key={n}\n type=\"button\"\n role=\"radio\"\n aria-checked={n === shown}\n aria-label={`${n} out of ${max}`}\n data-records-rating-star={n}\n className=\"rounded px-px focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n onMouseDown={(event) => {\n if (!selectFirst) {\n own(event);\n return;\n }\n // The press goes on to the grid, which selects the cell and keeps the keyboard.\n armed.current = event.currentTarget.closest(\"td\")?.hasAttribute(\"data-matrx-cell-active\") === true;\n }}\n onDoubleClick={own}\n onClick={(event) => {\n event.stopPropagation();\n if (selectFirst && event.detail !== 0 && !armed.current) return;\n onRate(n === shown ? null : n);\n }}\n >\n {star}\n </button>\n ) : (\n <span key={n}>{star}</span>\n );\n })}\n </span>\n );\n}\n\n/** The rich drawing for a format that has one, or undefined for the registry's text. */\nfunction rich(id: string, text: string, raw: unknown, format: FieldFormatConfig): ReactNode | undefined {\n switch (id) {\n case \"email\":\n return (\n <a href={`mailto:${text}`} className={LINK} onClick={own}>\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"url\":\n return (\n <a href={text.includes(\"://\") ? text : `https://${text}`} target=\"_blank\" rel=\"noopener noreferrer\" className={LINK} onClick={own}>\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"phone\":\n return (\n <a href={`tel:${text.replace(/[^\\d+]/g, \"\")}`} className={LINK} onClick={own} title={text}>\n <span className=\"truncate tabular-nums\">{formatPhone(text)}</span>\n </a>\n );\n case \"address\":\n return (\n <a\n href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(text)}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={LINK}\n title=\"Open in maps\"\n onClick={own}\n >\n <span className=\"truncate\">{text}</span>\n </a>\n );\n case \"progress\": {\n const n = numberOf(raw);\n if (n === null) return undefined;\n const pct = format.options?.percentScale === \"fraction\" ? n * 100 : n;\n const clamped = Math.max(0, Math.min(100, pct));\n return (\n <span className=\"inline-flex w-full min-w-0 items-center gap-2\" title={text}>\n <span\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={Math.round(clamped)}\n className=\"h-1.5 min-w-8 flex-1 overflow-hidden rounded-full bg-muted\"\n >\n <span className={cn(\"block h-full rounded-full\", pct >= 100 ? \"bg-emerald-500\" : \"bg-primary\")} style={{ width: `${clamped}%` }} />\n </span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">{text}</span>\n </span>\n );\n }\n case \"color\":\n return (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"h-4 w-4 shrink-0 rounded border border-border\" style={{ backgroundColor: text }} />\n <code className=\"font-mono text-xs\">{text}</code>\n </span>\n );\n case \"tags\": {\n const items = Array.isArray(raw) ? raw.map(String) : text.split(\",\").map((s) => s.trim()).filter(Boolean);\n if (items.length === 0) return undefined;\n return (\n <span className=\"flex flex-wrap items-center gap-1\">\n {items.map((item, i) => (\n <span key={`${item}-${i}`} className=\"inline-flex items-center rounded-md border border-border bg-muted px-1.5 py-0.5 text-xs\">\n {item}\n </span>\n ))}\n </span>\n );\n }\n case \"rating\":\n return numberOf(raw) === null ? undefined : <RatingStars value={raw} max={format.options?.ratingMax ?? 5} />;\n default:\n return undefined;\n }\n}\n\n/**\n * ONE VALUE, DRAWN IN ITS FORMAT. `null` when there is no format (the caller keeps its own\n * drawing); otherwise never blank and never a throw.\n */\nexport function FormattedValue({\n value,\n format,\n onRate,\n selectFirst,\n}: {\n value: unknown;\n format: FieldFormatConfig;\n /** A rating's one-click write, when this person may change the value. */\n onRate?: ((next: number | null) => void) | undefined;\n /** In a grid: the first press selects the cell, a press on the selected cell rates (`RatingStars`). */\n selectFirst?: boolean | undefined;\n}): ReactNode {\n const def = getFieldFormat(format.id);\n // A rating a person may change is stars even when empty — the empty stars ARE the control.\n // (A stored score outside 0…max is not a rating: it falls to the registry's amber below, so a\n // 1250 never draws as five lit stars.)\n const score = numberOf(value);\n const max = format.options?.ratingMax ?? 5;\n if (def?.id === \"rating\" && onRate && (value === null || value === undefined || value === \"\" || (score !== null && score >= 0 && score <= max))) {\n return <RatingStars value={value} max={format.options?.ratingMax ?? 5} onRate={onRate} selectFirst={selectFirst} />;\n }\n const result = formatFieldValue(value, format);\n if (!result.ok || result.empty || !def?.rich) return <FormattedCell result={result} />;\n return rich(def.id, result.text, value, format) ?? <FormattedCell result={result} />;\n}\n\n/** What a link chip says: the site, and the page or file when there is one (\"unsplash.com · photo.jpg\"). */\nexport function linkChipText(raw: string): string {\n try {\n const url = new URL(raw.includes(\"://\") ? raw : `https://${raw}`);\n const host = url.hostname.replace(/^www\\./, \"\");\n const last = url.pathname.split(\"/\").filter(Boolean).pop();\n return last ? `${host} · ${decodeURIComponent(last)}` : host;\n } catch {\n return raw;\n }\n}\n","\"use client\";\n\n// src/gridAttachments.tsx — @ai-matrx/records-ui · one-grid merge, host port `pickFiles`\n//\n// A FILE COLUMN: ITS CHIPS, AND HOW A FILE GETS INTO IT.\n//\n// An attachment column is a relation to the kernel File Table (REC-31). The store turns the id a\n// writer actually holds — a file from the host's file service — into that File record at every\n// write door (`custom.relation_kernel_record`), and the File record keeps the host's file id in\n// its own document (`file_id`). So:\n// · A CHIP names the File record and opens the host's page for its file (`hrefForFile`). Unbound,\n// the chip is plain words that say the file cannot be opened here — never a dead link.\n// · THE EDITOR adds files through the host's own file window (`pickFiles`, Airtable's \"Attach\"\n// over the person's own files) and/or a fresh upload (`upload`). Whatever the host returns is\n// written as the cell's value through the grid's one-cell write, so the store's attachment door\n// decides and refuses in its own words. With neither port bound the editor offers no chooser\n// at all and says so (`NO_UPLOAD_REASON`) — absent or honest, never dead.\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { Field, RecordDocument, Uuid } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { Badge, Button } from \"@ai-matrx/design-system\";\n\nimport { NO_UPLOAD_REASON, useRecordsUi } from \"./host\";\nimport { idsOf } from \"./labels\";\nimport { fieldName } from \"./names\";\nimport { FilePicker } from \"./FilePicker\";\nimport { RefusalLine } from \"./Refusal\";\nimport { refusal as refusalOf } from \"./refusals\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** The ids an attachment cell holds, in order: File record ids (or a host file id not yet written). */\nexport function attachmentIdsOf(value: unknown): string[] {\n return idsOf(value);\n}\n\n/** What an attachment cell writes after adding `added` to what it holds. */\nexport function withAttached(field: Field, value: unknown, added: readonly string[]): unknown {\n const held = attachmentIdsOf(value);\n if (!field.multi) return added.length > 0 ? added[added.length - 1]! : (held[0] ?? null);\n const next = [...held];\n for (const id of added) if (!next.includes(id)) next.push(id);\n return next.length > 0 ? next : null;\n}\n\n/** What an attachment cell writes after taking `removed` out. */\nexport function withoutAttached(field: Field, value: unknown, removed: string): unknown {\n const next = attachmentIdsOf(value).filter((id) => id !== removed);\n if (!field.multi) return next[0] ?? null;\n return next.length > 0 ? next : null;\n}\n\n/**\n * THE APP'S FILE IDS THIS SCREEN WAS JUST HANDED (merged-grid review 2, fix lane F item 4). A cell\n * holds File record ids, but right after \"Attach files…\" / an upload it briefly holds the host's own\n * file ids — the store turns each into its File record at the write door. A chip must not ask the\n * record door about those (every attach logged a 403 \"You do not have access to this record\"): it\n * opens them as the host's files. Filled by the editor below; ids live for the page's lifetime.\n */\nconst handedHostFileIds = new Set<string>();\n\n/** Remember ids the host handed back as ITS file ids (`pickFiles`, `upload`). */\nexport function rememberHostFileIds(ids: readonly string[]): void {\n for (const id of ids) handedHostFileIds.add(id);\n}\n\n/** The words a chip reads while (or when) a File record cannot be read. */\nexport const FILE_CHIP_UNREAD = \"File\";\n/** A chip's hover when the host has no page for files. */\nexport const FILE_CHIP_NO_PAGE = \"This screen has no way to open files yet.\";\n\n/**\n * ONE FILE: the File record's own name, opening the host's page for its file. A File record the\n * reader may not open reads the store's refusal on hover, never a guessed name.\n */\nexport function AttachmentChip({ id, onRemove }: { id: string; onRemove?: (() => void) | undefined }) {\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [read, setRead] = useState<{ name: string | null; fileId: string | null; why: string | null } | null>(null);\n useEffect(() => {\n let cancelled = false;\n if (!client) {\n setRead({ name: null, fileId: null, why: null });\n return;\n }\n if (handedHostFileIds.has(id)) {\n // The host's own file id, not a File record yet: it opens as itself, and nobody asks the\n // record door about an id that is not a record.\n setRead({ name: null, fileId: id, why: null });\n return;\n }\n void client.recordRead({ record_id: id as Uuid }).then((answered) => {\n if (cancelled) return;\n if (!answered.ok) {\n // Not a File record (yet): a host file id written a moment ago opens as itself.\n setRead({ name: null, fileId: id, why: refusalSentence(answered.error) });\n return;\n }\n const doc = (answered.data.document ?? {}) as RecordDocument;\n const fileId = typeof doc[\"file_id\"] === \"string\" ? (doc[\"file_id\"] as string) : null;\n const name = typeof doc[\"name\"] === \"string\" && doc[\"name\"] !== \"\" ? (doc[\"name\"] as string) : null;\n setRead({ name, fileId, why: null });\n });\n return () => {\n cancelled = true;\n };\n }, [client, id]);\n\n const words = read?.name ?? (read ? FILE_CHIP_UNREAD : \"…\");\n const href = read?.fileId ? host.hrefForFile?.({ fileId: read.fileId as Uuid }) : undefined;\n const title = href ? `Open ${words}` : read?.why ?? FILE_CHIP_NO_PAGE;\n return (\n <Badge variant=\"secondary\" className=\"max-w-[14rem] gap-1 text-[11px]\" data-records-file-chip={id} title={title}>\n {href ? (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"truncate underline-offset-2 hover:underline\"\n data-records-file-link={read?.fileId ?? \"\"}\n onClick={(event) => event.stopPropagation()}\n onMouseDown={(event) => event.stopPropagation()}\n >\n {words}\n </a>\n ) : (\n <span className=\"truncate\">{words}</span>\n )}\n {onRemove ? (\n <button\n type=\"button\"\n aria-label={`Remove ${words}`}\n className=\"shrink-0 rounded px-0.5 text-muted-foreground hover:text-foreground\"\n onClick={(event) => {\n event.stopPropagation();\n onRemove();\n }}\n >\n ×\n </button>\n ) : null}\n </Badge>\n );\n}\n\n/** Every file a cell holds, as chips. */\nexport function AttachmentChips({ value, onRemove }: { value: unknown; onRemove?: ((id: string) => void) | undefined }) {\n const ids = attachmentIdsOf(value);\n if (ids.length === 0) return null;\n return (\n <span className=\"flex flex-wrap gap-1\" data-records-file-chips=\"\">\n {ids.map((id) => (\n <AttachmentChip key={id} id={id} {...(onRemove ? { onRemove: () => onRemove(id) } : {})} />\n ))}\n </span>\n );\n}\n\n/** Does this host have any way to put a file into a cell? */\nexport function hostTakesFiles(host: { pickFiles?: unknown; upload?: unknown }): boolean {\n return Boolean(host.pickFiles || host.upload);\n}\n\n/**\n * THE ATTACHMENT EDITOR. `autoOpen` (a grid cell opened by a click or Enter): the host's file\n * window opens at once, and whatever is picked is the commit (`onClose`), exactly as a choice\n * cell's list does. A cancelled window closes the cell with nothing changed.\n */\nexport function AttachmentControl({\n field,\n value,\n onChange,\n disabled,\n id,\n autoOpen,\n onClose,\n}: {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n autoOpen?: boolean | undefined;\n onClose?: (() => void) | undefined;\n}) {\n const host = useRecordsUi();\n const [busy, setBusy] = useState(false);\n const [why, setWhy] = useState<string | null>(null);\n const latest = useRef(value);\n latest.current = value;\n const multiple = Boolean(field.multi);\n\n const pick = async () => {\n if (!host.pickFiles || disabled) return;\n setBusy(true);\n setWhy(null);\n try {\n const picked = await host.pickFiles({ multiple });\n if (picked && picked.length > 0) {\n rememberHostFileIds(picked);\n onChange(withAttached(field, latest.current, picked));\n }\n } catch (cause) {\n setWhy(cause instanceof Error ? cause.message : String(cause));\n setBusy(false);\n return;\n }\n setBusy(false);\n onClose?.();\n };\n\n const opened = useRef(false);\n useEffect(() => {\n if (!autoOpen || opened.current || !host.pickFiles) return;\n opened.current = true;\n void pick();\n // Once per opening of the cell.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoOpen]);\n\n if (!hostTakesFiles(host)) {\n return (\n <p id={id} className=\"rounded border border-dashed px-2 py-1 text-xs text-muted-foreground\" data-records-no-file-door=\"\">\n {NO_UPLOAD_REASON}\n </p>\n );\n }\n\n return (\n <span id={id} className=\"flex flex-col gap-1\" data-records-attachment-editor=\"\">\n <AttachmentChips\n value={value}\n {...(disabled ? {} : { onRemove: (removed: string) => onChange(withoutAttached(field, latest.current, removed)) })}\n />\n <span className=\"flex flex-wrap items-center gap-1\">\n {host.pickFiles ? (\n <Button size=\"sm\" variant=\"outline\" disabled={disabled || busy} onClick={() => void pick()} data-records-attach-files=\"\">\n {busy ? \"Choosing…\" : attachmentIdsOf(value).length > 0 ? \"Add files…\" : \"Attach files…\"}\n </Button>\n ) : null}\n {host.upload ? (\n <FilePicker\n label=\"Upload a file\"\n inputLabel={`Upload a file to ${fieldName(field)}`}\n disabled={disabled || busy}\n onFile={(file) => {\n setBusy(true);\n setWhy(null);\n void host.upload!(file).then((result) => {\n setBusy(false);\n if (result.ok) {\n rememberHostFileIds([result.fileId]);\n onChange(withAttached(field, latest.current, [result.fileId]));\n }\n else setWhy(result.reason);\n });\n }}\n />\n ) : null}\n </span>\n {why ? <RefusalLine error={refusalOf(\"invalid_argument\", why, \"Pick another file, or try this one again.\")} /> : null}\n </span>\n );\n}\n","\"use client\";\n\n// src/FilePicker.tsx — @ai-matrx/records-ui · FIX-10C F10\n//\n// CHOOSING A FILE, DRAWN THE WAY THIS PLATFORM DRAWS EVERY OTHER CONTROL.\n//\n// WHAT THIS REPLACES, measured (VERIFIER-10 F10, 2026-09-22): pressing Import\n// produced `Import Jobs [Choose File] No file chosen` — the browser's own\n// unstyled control, in the browser's own font, with no instruction, no example\n// of what the file should look like and no way out. Airtable and Notion both\n// open an EXPLAINED import screen at this exact moment; a raw `<input\n// type=file>` is the one control on the screen that did not come from the\n// design system.\n//\n// AND IT IS A CLASS, NOT A SCREEN. Four components in this package drew their\n// own bare file input — the import wizard, the public form runner, the capture\n// sheet and the capture run. Four spellings of \"pick a file\", four different\n// accept lists, four different (absent) instructions. This is the one control,\n// built on `@ai-matrx/design-system`'s Button so it inherits focus rings, sizes,\n// disabled styling and dark mode like everything else, and exported so a host\n// app can use it too.\n//\n// WHAT IT PROMISES:\n// · it says what a good file looks like BEFORE the person opens their finder;\n// · it names the file once chosen, and offers to choose a different one —\n// never a control that silently keeps the old file;\n// · drag and drop works, because the file is usually already in a folder the\n// person is looking at;\n// · the native input is still the mechanism (it is the only thing that can\n// open a file dialog) — it is visually hidden and reached by label, so\n// keyboard and screen readers get the real control, not a div pretending.\n\nimport { useCallback, useId, useRef, useState, type DragEvent, type ReactNode } from \"react\";\nimport { Button, cn } from \"@ai-matrx/design-system\";\n\nexport interface FilePickerProps {\n /** What the button says when nothing is chosen yet. */\n label: string;\n /** The `accept` list, exactly as the native input takes it. */\n accept?: string | undefined;\n /**\n * The accessible name of the file input itself, when it must differ from the\n * button's word — an import screen's input has been called \"Choose a file to\n * import\" since it existed, and every automation and screen-reader script\n * that knows this screen resolves that sentence. A name is a contract.\n */\n inputLabel?: string | undefined;\n /**\n * One sentence describing a good file — the thing the bare input never said.\n * Shown under the control, before anything is chosen.\n */\n hint?: ReactNode;\n disabled?: boolean | undefined;\n /** The chosen file. Called once per choice; re-choosing calls it again. */\n onFile: (file: File) => void;\n /** Forget the chosen file and go back to the empty state. */\n onClear?: (() => void) | undefined;\n /** The name of the file currently in play, when the owner is holding one. */\n chosenName?: string | null | undefined;\n className?: string | undefined;\n}\n\nexport function FilePicker({\n label,\n accept,\n inputLabel,\n hint,\n disabled = false,\n onFile,\n onClear,\n chosenName,\n className,\n}: FilePickerProps) {\n const inputId = useId();\n const input = useRef<HTMLInputElement | null>(null);\n const [over, setOver] = useState(false);\n\n const take = useCallback(\n (file: File | undefined | null) => {\n if (!file || disabled) return;\n onFile(file);\n },\n [disabled, onFile],\n );\n\n const onDrop = useCallback(\n (e: DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n setOver(false);\n take(e.dataTransfer?.files?.[0]);\n },\n [take],\n );\n\n return (\n <div\n data-matrx-file-picker\n className={cn(\"flex min-w-0 flex-col gap-1\", className)}\n onDragOver={(e) => {\n if (disabled) return;\n e.preventDefault();\n setOver(true);\n }}\n onDragLeave={() => setOver(false)}\n onDrop={onDrop}\n >\n <div\n className={cn(\n \"flex min-w-0 flex-wrap items-center gap-2 rounded-md border border-dashed px-2 py-1.5\",\n over ? \"border-primary bg-primary/5\" : \"border-border\",\n disabled && \"opacity-60\",\n )}\n >\n {/* The real control — the only thing that can open a file dialog.\n Visually hidden rather than `display:none`, so it keeps its own\n accessible name and can still be driven; the Button beside it is the\n keyboard and pointer control, so this one is out of the tab order\n rather than a second stop that does the same thing. */}\n <input\n ref={input}\n id={inputId}\n type=\"file\"\n aria-label={inputLabel ?? label}\n tabIndex={-1}\n {...(accept ? { accept } : {})}\n disabled={disabled}\n className=\"sr-only\"\n onChange={(e) => {\n take(e.target.files?.[0]);\n // Choosing THE SAME file twice has to fire again — a person who\n // fixed the file and picked it again would otherwise press a\n // control that does nothing.\n e.target.value = \"\";\n }}\n />\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={disabled}\n onClick={() => input.current?.click()}\n >\n {chosenName ? \"Choose a different file\" : label}\n </Button>\n {chosenName ? (\n <span className=\"min-w-0 flex-1 truncate text-xs\" title={chosenName}>\n {chosenName}\n </span>\n ) : (\n <span className=\"text-xs text-muted-foreground\">or drop it here</span>\n )}\n {chosenName && onClear ? (\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" disabled={disabled} onClick={onClear}>\n Cancel\n </Button>\n ) : null}\n </div>\n {hint && !chosenName ? <p className=\"text-xs text-muted-foreground\">{hint}</p> : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/ReferenceChips.tsx — @ai-matrx/records-ui · lane REFERENCE-CARRY\n//\n// A REFERENCE IS A CHIP THAT OPENS WHAT IT NAMES — wherever a value is read (grid cell, peek, record\n// panel, card). Two store declarations carry a reference (PROGRESS-REFERENCE-CARRY §D.1): a\n// `relation` Field holds record ids of one Table, an entity reference holds `{token, id}` of any\n// platform thing. A person sees ONE thing — a chip with the thing's own words — and the host's\n// `renderReference` port makes it a door (route, new tab, peek). Before this a relation cell drew\n// grey text badges that opened nothing, and a many-relation read \"2 of them\".\n//\n// Also here: `KindValueCell`, a cell whose value names its own shape (`kindValues.ts`), drawn by the\n// host's kind system (`renderKind`) — never the raw ```matrx fence.\n\nimport type { ReactNode } from \"react\";\nimport { entityRefsOf, type Field } from \"@ai-matrx/records\";\nimport { Badge, Skeleton, cn } from \"@ai-matrx/design-system\";\nimport { useRecordsUi, type ReferenceChipRef } from \"./host\";\nimport { isId, type LabelLookup } from \"./labels\";\nimport { WITHHELD_ENTITY_LABEL } from \"./EntityReferenceControl\";\nimport { useEmbeddedLook } from \"./embeddedLook\";\nimport { kindItemWords, kindLabel, kindValueWords, type KindValue } from \"./kindValues\";\n\n/**\n * NOTION'S ORDER: the related record's own icon, else its table's, else (the chip's) page glyph. Only\n * a drawable GLYPH counts — an emoji or short symbol; a table's icon kept as an icon NAME\n * (\"graduation-cap\") is not a glyph and falls through to the next.\n */\nexport function glyphOf(icon: string | null | undefined): string | null {\n const text = (icon ?? \"\").trim();\n return text !== \"\" && text.length <= 8 && /[^\\u0000-\\u007f]/.test(text) ? text : null;\n}\n/** The icon an icon-NAME is kept as (\"Briefcase\"): a word a host's `renderIcon` may draw. */\nfunction nameOf(icon: string | null | undefined): string | null {\n const text = (icon ?? \"\").trim();\n return /^[A-Za-z][A-Za-z0-9_-]{1,40}$/.test(text) ? text : null;\n}\nfunction iconOf(pair: { icon: string | null; tableIcon: string | null } | undefined): { icon?: string } {\n // The record's own icon first, whichever way it is kept; then its table's.\n const own = glyphOf(pair?.icon) ?? nameOf(pair?.icon);\n const table = glyphOf(pair?.tableIcon) ?? nameOf(pair?.tableIcon);\n const chosen = own ?? table;\n return chosen ? { icon: chosen } : {};\n}\n\n/** The references a relation or entity-reference value names, in the order it holds them. */\nexport function referencesOf(field: Field, value: unknown, kind: string, labels?: LabelLookup): ReferenceChipRef[] {\n if (kind === \"entity_reference\") {\n return entityRefsOf(value).map((r) => ({ token: r.token, id: r.id, label: r.label }));\n }\n const ids = (Array.isArray(value) ? value : [value]).filter(isId).map(String);\n const tableId = typeof field.relation_target === \"string\" ? field.relation_target : undefined;\n return ids.map((id) => ({\n token: \"record\",\n id,\n label: labels?.(field, id) ?? null,\n tableId,\n ...iconOf(labels?.icons?.(field, id)),\n ...(labels?.archived?.(field, id) ? { archived: true } : {}),\n }));\n}\n\n/** The word an archived reference wears, and its one-sentence tooltip. */\nexport const ARCHIVED_REFERENCE_WORD = \"Archived\";\nexport const ARCHIVED_REFERENCE_TIP = \"In the Archived view; restore it to use it again\";\n\n/** A plain page glyph (Lucide file-text geometry), for a related record that has no icon. */\nfunction PageGlyph() {\n return (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width={14} height={14} fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" data-records-page-glyph=\"\">\n <path d=\"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n <path d=\"M10 13H8\" /><path d=\"M16 17H8\" />\n </svg>\n );\n}\n\n/** One chip. The host's door when it has one; otherwise the words, and nothing that looks openable. */\nexport function ReferenceChip({ reference, waiting }: { reference: ReferenceChipRef; waiting?: string | null | undefined }) {\n const host = useRecordsUi();\n const look = useEmbeddedLook();\n // A NAME ON ITS WAY IS A PULSE INSIDE THE CHIP, never the word \"Loading…\" in a capsule\n // (STABLE-TABLES, night walk 2026-10-06): the chip and its door are there; the name lands in the\n // box the placeholder held.\n const pending = reference.label == null && reference.token === \"record\" && !waiting && !host.renderReference;\n const pendingMark = <Skeleton aria-label=\"Loading\" data-records-reference-pending=\"\" className=\"inline-block h-3 w-16 shrink-0 rounded-sm align-middle\" />;\n const words = reference.label ?? (reference.token === \"record\" ? (waiting ?? \"Loading…\") : WITHHELD_ENTITY_LABEL);\n const drawn: ReactNode = host.renderReference ? host.renderReference({ ...reference, label: reference.label ?? words }) : null;\n // EMBEDDED (`embeddedLook.tsx` `plainRelation`): Notion's relation — icon, then title, nothing else.\n if (look?.plainRelation) {\n return (\n <span\n className={cn(\n \"inline-flex max-w-full min-w-0 items-center gap-1.5 text-sm text-foreground hover:underline [&_a]:text-inherit [&_a]:no-underline [&_a:hover]:underline\",\n reference.archived && \"opacity-70\",\n )}\n data-records-reference-chip={reference.token}\n data-records-reference-plain=\"\"\n data-records-reference-archived={reference.archived ? \"\" : undefined}\n title={reference.archived ? ARCHIVED_REFERENCE_TIP : words}\n >\n <span aria-hidden=\"true\" data-records-reference-icon=\"\" className=\"inline-flex size-4 shrink-0 items-center justify-center text-muted-foreground\">\n {glyphOf(reference.icon) ? <span className=\"text-sm leading-none\">{reference.icon}</span> : (reference.icon && host.renderIcon?.(reference.icon)) || <PageGlyph />}\n </span>\n {drawn ?? (pending ? pendingMark : <span className=\"truncate\">{words}</span>)}\n {reference.archived ? <span className=\"shrink-0 text-muted-foreground\">{ARCHIVED_REFERENCE_WORD}</span> : null}\n </span>\n );\n }\n // AN ARCHIVED RECORD IS STILL NAMED (chair ruling B3-21): the chip keeps its words and door, is\n // drawn muted, and says \"Archived\" — state, not prose. Restoring it brings the plain chip back.\n return (\n <Badge\n variant=\"secondary\"\n className={cn(\n \"max-w-full min-w-0 gap-1 px-1.5 py-0 text-[11px] font-normal\",\n reference.archived && \"opacity-70\",\n )}\n data-records-reference-chip={reference.token}\n data-records-reference-archived={reference.archived ? \"\" : undefined}\n title={reference.archived ? ARCHIVED_REFERENCE_TIP : words}\n >\n {drawn ?? (pending ? pendingMark : <span className=\"truncate\">{words}</span>)}\n {reference.archived ? <span className=\"shrink-0 text-muted-foreground\">{ARCHIVED_REFERENCE_WORD}</span> : null}\n </Badge>\n );\n}\n\n/** Every reference a value holds, as chips (a dash when it holds none). */\nexport function ReferenceChips({ refs, waiting }: { refs: ReferenceChipRef[]; waiting?: string | null | undefined }) {\n if (refs.length === 0) return <span className=\"text-muted-foreground\">—</span>;\n return (\n <span className=\"flex min-w-0 flex-wrap gap-1\" data-records-reference-chips=\"\">\n {refs.map((r) => (\n <ReferenceChip key={`${r.token}:${r.id}`} reference={r} waiting={waiting} />\n ))}\n </span>\n );\n}\n\n/**\n * A CELL HOLDING A KIND. The host's kind system draws it (`renderKind`): a reference directive as\n * chips, any other kind as a compact button that opens the real view. Unbound, a neutral chip names\n * what it is and the raw text is one hover away.\n */\nexport function KindValueCell({\n kv,\n where,\n title,\n}: {\n kv: KindValue;\n where: \"cell\" | \"panel\";\n title: string;\n}) {\n const host = useRecordsUi();\n if (host.renderKind) {\n return <span className=\"flex min-w-0 max-w-full items-center\" data-records-kind-value={kv.kind}>{host.renderKind({ value: kv.value, kind: kv.kind, where, title })}</span>;\n }\n const named = kv.items.map(kindItemWords).filter((w): w is string => w !== null);\n return (\n <span className={cn(\"flex min-w-0 flex-wrap gap-1\")} data-records-kind-value={kv.kind} title={JSON.stringify(kv.value)}>\n {named.length > 0 ? (\n named.map((w, i) => (\n <Badge key={`${w}-${i}`} variant=\"secondary\" className=\"px-1.5 py-0 text-[11px] font-normal\">\n {w}\n </Badge>\n ))\n ) : (\n <Badge variant=\"outline\" className=\"px-1.5 py-0 text-[11px] font-normal\">\n {kindLabel(kv.kind)}\n </Badge>\n )}\n </span>\n );\n}\n\nexport { kindValueWords };\n","// src/kindValues.ts — @ai-matrx/records-ui · lane REFERENCE-CARRY\n//\n// A CELL THAT HOLDS A KIND. A value is a kind value when it names its own shape — `__kind` — or\n// when it is a stored Matrx directive written before the Kind Directives merge (the retired 4-key\n// shell `{\"matrx_version\": 1, \"kind\": \"reference\", \"type\": \"scope\", \"items\": [...]}`, usually inside\n// a ```matrx fence). Before this, a text cell holding either printed the raw fence: Arman's\n// Department table, 2026-09-28 — Team Leader read ```matrx {\"matrx_version\":1,…}```.\n//\n// THE SHELL IS UNDERSTOOD IN ONE PLACE. Whether an object is a directive — the current shell, or\n// the retired one stored before the merge — is `@ai-matrx/content-ir/directives`' `tryDecodeDirective`\n// alone (its containment guard keeps the retired shell there). This module only takes the object out\n// of its fence and hands it, untouched, to the host's `renderKind` port, which draws it through the\n// kind system. New values are stored as `__kind` JSON, never as a fence.\n\nimport { tryDecodeDirective } from \"@ai-matrx/content-ir/directives\";\nimport { humanizeIdentifier } from \"@ai-matrx/kit/text-case\";\n\n/** What a cell holds when it holds a kind. */\nexport interface KindValue {\n /** The parsed object, exactly as stored (`__kind` kept — it is part of the data). */\n value: Record<string, unknown>;\n /**\n * The kind's own name: `__kind`, or for a directive the slug the one decoder reads\n * (`directive_v1_reference_scope`, the retired shell included).\n */\n kind: string;\n /** True when the one decoder read this as a Matrx directive. */\n directive: boolean;\n /** The items a directive carries (a reference's chips), when it carries any. */\n items: Record<string, unknown>[];\n}\n\nconst KIND_KEY = \"__kind\";\n/** One fenced block and nothing else: ```matrx {…}``` or ```json {…}```. */\nconst WHOLE_FENCE = /^\\s*```(?:matrx|json)?[ \\t]*\\r?\\n?([\\s\\S]*?)\\r?\\n?[ \\t]*```\\s*$/;\n\nfunction asObject(value: unknown): Record<string, unknown> | null {\n return typeof value === \"object\" && value !== null && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n}\n\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\n const trimmed = text.trim();\n if (!trimmed.startsWith(\"{\") || !trimmed.endsWith(\"}\")) return null;\n try {\n return asObject(JSON.parse(trimmed));\n } catch {\n return null;\n }\n}\n\nfunction fromObject(obj: Record<string, unknown>): KindValue | null {\n // THE ONE DECODER decides what a directive is — the current two-key shell and, for stored\n // content only, the retired 4-key one. A directive it cannot honour is not drawn as one.\n const directive = tryDecodeDirective(obj);\n if (directive) return { value: obj, kind: directive.slug, directive: true, items: [...directive.items] };\n const named = obj[KIND_KEY];\n if (typeof named === \"string\" && named.trim() !== \"\") {\n const items = Array.isArray(obj.items) ? obj.items.filter((i): i is Record<string, unknown> => asObject(i) !== null) : [];\n return { value: obj, kind: named.trim(), directive: false, items };\n }\n return null;\n}\n/**\n * The kind value a cell holds, or null. An object with `__kind`, a string that is such an object's\n * JSON, or a string that is ONE fenced block of it (```matrx / ```json), the retired directive shell\n * included. Text that merely mentions a fence among other words is text, and stays text.\n */\nexport function kindValueOf(value: unknown): KindValue | null {\n const obj = asObject(value);\n if (obj) return fromObject(obj);\n if (typeof value !== \"string\" || value.length > 200_000) return null;\n const fenced = WHOLE_FENCE.exec(value);\n const parsed = parseJsonObject(fenced ? fenced[1]! : value);\n return parsed ? fromObject(parsed) : null;\n}\n\n/** The words an item names itself by (a reference's label, a title, a name). */\nexport function kindItemWords(item: Record<string, unknown>): string | null {\n for (const key of [\"label\", \"title\", \"name\", \"display_name\"]) {\n const v = item[key];\n if (typeof v === \"string\" && v.trim() !== \"\") return v.trim();\n }\n return null;\n}\n\n/**\n * A kind value in words, for a sentence, a card, a copy or an export: the items' own names when it\n * carries named items (\"Arman Sadeghi, Tahir Mahfooz\"), else what kind of thing it is.\n */\nexport function kindValueWords(kv: KindValue): string {\n const named = kv.items.map(kindItemWords).filter((w): w is string => w !== null);\n if (named.length > 0) return named.join(\", \");\n return kindLabel(kv.kind);\n}\n\n/** A kind's name the way a person reads it: `directive_v1_reference_scope` → \"Reference Scope\". */\nexport function kindLabel(kind: string): string {\n return humanizeIdentifier(kind.replace(/^directive_v\\d+_/, \"\").replace(/_v\\d+$/, \"\")) || \"Structured value\";\n}\n","// src/formulaNames.ts — @ai-matrx/records-ui\n//\n// A FORMULA READS WITH TODAY'S COLUMN NAMES (merged-grid review 2, 2026-09-27, C3).\n//\n// A formula written as `{Quote} * 1.08` kept reading `{Quote}` after the column was renamed\n// \"Quote amount\" — it still computed, because the store keeps the parsed expression by FIELD ID\n// (`config.expr`: `{\"field\": \"<id>\"}` nodes), but the words a person reads were the text as first\n// typed (`config.formula_text`). Airtable and Sheets both show a formula with the column's current\n// name. So the text is DRAWN from the ids: each `{name}` in the text is paired, in order, with the\n// expression's field references (the parser keeps left-to-right order), and a name that no longer\n// belongs to the id it points at is replaced by that id's current label.\n//\n// It changes only what is SHOWN. When the pairing cannot be trusted — the counts differ, or one\n// name would have to become two different columns — the text is shown exactly as it was.\n\nimport { sourceArchivedOf, type Field, type SourceArchived } from \"@ai-matrx/records\";\nimport { fieldName } from \"./names\";\n\n/** Every `{\"field\": id}` in an expression, depth-first, left to right. */\nexport function fieldRefsOf(expr: unknown): string[] {\n const out: string[] = [];\n const walk = (node: unknown) => {\n if (Array.isArray(node)) {\n for (const n of node) walk(n);\n return;\n }\n if (node === null || typeof node !== \"object\") return;\n const obj = node as Record<string, unknown>;\n if (typeof obj[\"field\"] === \"string\" && Object.keys(obj).length === 1) {\n out.push(obj[\"field\"]);\n return;\n }\n for (const value of Object.values(obj)) walk(value);\n };\n walk(expr);\n return out;\n}\n\nconst BRACE = /\\{([^{}]*)\\}/g;\n\n/** The formula's text with every column named as it is called NOW. */\nexport function formulaTextNow(text: string, expr: unknown, fields: readonly Field[] | null | undefined): string {\n if (!text || !fields || fields.length === 0) return text;\n const refs = fieldRefsOf(expr);\n const names = [...text.matchAll(BRACE)].map((m) => m[1] ?? \"\");\n if (refs.length === 0 || refs.length !== names.length) return text;\n const byId = new Map(fields.map((f) => [String(f.id), f]));\n // One stale name must become ONE column; otherwise the pairing is not trusted.\n const becomes = new Map<string, string>();\n const replacement: string[] = [];\n for (let i = 0; i < names.length; i += 1) {\n const name = names[i]!;\n const field = byId.get(refs[i]!);\n if (!field) return text;\n const now = fieldName(field);\n if (now.trim().toLowerCase() === name.trim().toLowerCase()) {\n replacement.push(name);\n continue;\n }\n const seen = becomes.get(name);\n if (seen !== undefined && seen !== now) return text;\n becomes.set(name, now);\n replacement.push(now);\n }\n let i = 0;\n return text.replace(BRACE, () => `{${replacement[i++]}}`);\n}\n\n/** The Field with its formula's text drawn in today's names (a copy; the Field is untouched). */\nexport function withFormulaNamesNow(field: Field, fields: readonly Field[] | null | undefined): Field {\n const config = (field.config ?? {}) as Record<string, unknown>;\n const text = typeof config[\"formula_text\"] === \"string\" ? (config[\"formula_text\"] as string) : \"\";\n if (text === \"\") return field;\n const now = formulaTextNow(text, config[\"expr\"] ?? (field as { expr?: unknown }).expr, fields);\n return now === text ? field : ({ ...field, config: { ...config, formula_text: now } } as Field);\n}\n\n/* ═══ HOW A WORKED-OUT COLUMN SHOWS BY DEFAULT (merged-grid review 2, 2026-09-27, A12) ══════════════\n *\n * A formula over money showed 2,639.875 until somebody set \"Shows as Currency\" by hand, and a row\n * with nothing typed yet showed \"$0.00\". Airtable: a formula's result format follows its inputs\n * (money in, money out) and a formula with nothing to work on is blank. So, when the column's own\n * settings chose no look:\n * · arithmetic over a money column shows as that money; arithmetic over plain numbers shows as a\n * number with the inputs' declared precision (2 when none says);\n * · a row where every column the formula reads is empty shows the cell empty.\n * A look the column's settings chose always wins; a formula that is not plain arithmetic (a\n * comparison, words, a date) keeps the value as the store answers it.\n */\n\n/** The store's arithmetic nodes: a result made only of these is a number. */\nconst ARITHMETIC = new Set([\"fx.add\", \"fx.sub\", \"fx.mul\", \"fx.div\", \"fx.sum\", \"fx.round\", \"fx.min\", \"fx.max\", \"fx.abs\", \"fx.avg\", \"fx.neg\", \"fx.ceil\", \"fx.floor\"]);\n\nfunction opsOf(expr: unknown, out: string[] = []): string[] {\n if (Array.isArray(expr)) for (const n of expr) opsOf(n, out);\n else if (expr && typeof expr === \"object\") {\n const obj = expr as Record<string, unknown>;\n if (typeof obj[\"op\"] === \"string\") out.push(obj[\"op\"]);\n for (const value of Object.values(obj)) if (value && typeof value === \"object\") opsOf(value, out);\n }\n return out;\n}\n\nfunction exprOf(field: Field): unknown {\n const config = (field.config ?? {}) as Record<string, unknown>;\n return config[\"expr\"] ?? (field as { expr?: unknown }).expr;\n}\n\n/** The columns a formula reads, as Fields (in order, once each); `null` when one cannot be found. */\nexport function formulaInputs(field: Field, fields: readonly Field[] | null | undefined): Field[] | null {\n const refs = fieldRefsOf(exprOf(field));\n if (refs.length === 0 || !fields) return null;\n const byId = new Map(fields.map((f) => [String(f.id), f]));\n const out: Field[] = [];\n for (const id of new Set(refs)) {\n const f = byId.get(id);\n if (!f) return null;\n out.push(f);\n }\n return out;\n}\n\nconst NUMERIC_KINDS = new Set([\"number\", \"currency\", \"percent\"]);\n\n/** The default look of a formula's result, from its inputs — or `undefined` to leave it as answered. */\nexport function formulaDefaultFormat(\n field: Field,\n fields: readonly Field[] | null | undefined,\n kindOf: (f: Field) => string,\n currencyCodeOf: (unit: string | null | undefined) => string,\n): { id: string; options?: Record<string, unknown> } | undefined {\n const inputs = formulaInputs(field, fields);\n if (!inputs || inputs.length === 0) return undefined;\n const ops = opsOf(exprOf(field));\n if (ops.length === 0 || !ops.every((op) => ARITHMETIC.has(op))) return undefined;\n if (!inputs.every((f) => NUMERIC_KINDS.has(kindOf(f)))) return undefined;\n const precisions = inputs\n .map((f) => ((f as unknown as { display_format?: { options?: { precision?: unknown } } }).display_format?.options?.precision))\n .filter((p): p is number => typeof p === \"number\");\n const precision = precisions.length > 0 ? Math.max(...precisions) : 2;\n // Money is a money column, or a number column whose settings show it as money.\n const lookOf = (f: Field) => (f as unknown as { display_format?: { id?: unknown; options?: { currency?: unknown } } }).display_format;\n const money = inputs.find((f) => kindOf(f) === \"currency\" || lookOf(f)?.id === \"currency\");\n if (money) {\n const code = lookOf(money)?.options?.currency;\n return { id: \"currency\", options: { currency: typeof code === \"string\" && code !== \"\" ? code : currencyCodeOf(money.unit) } };\n }\n return { id: \"decimal\", options: { precision } };\n}\n\n/** The keys a formula reads, stamped on the drawn copy so a cell can tell \"nothing to work on\". */\nexport const FORMULA_INPUT_KEYS = \"__formula_input_keys\";\n\n/** True when every column this formula reads is empty on this record: the cell is drawn empty. */\nexport function formulaHasNothingToWorkOn(field: Field, document: Record<string, unknown> | null | undefined): boolean {\n const keys = ((field.config ?? {}) as Record<string, unknown>)[FORMULA_INPUT_KEYS];\n if (!Array.isArray(keys) || keys.length === 0 || !document) return false;\n return keys.every((key) => {\n const v = document[String(key)];\n return v === null || v === undefined || v === \"\" || (Array.isArray(v) && v.length === 0);\n });\n}\n\n/**\n * A FORMULA THAT READS A COLUMN WHOSE SOURCE IS ARCHIVED (v7 TABLE-EXPERIENCE item 7, Law 4): the\n * first input holding the store's \"source archived\" answer, so an empty formula cell says why\n * instead of drawing a blank. Null when none does (or the inputs are not known on this copy).\n */\nexport function formulaSourceArchived(field: Field, document: Record<string, unknown> | null | undefined): SourceArchived | null {\n const keys = ((field.config ?? {}) as Record<string, unknown>)[FORMULA_INPUT_KEYS];\n if (!Array.isArray(keys) || !document) return null;\n for (const key of keys) {\n const state = sourceArchivedOf(document[String(key)]);\n if (state) return state;\n }\n return null;\n}\n\n/**\n * THE ONE DRAWN COPY OF A WORKED-OUT COLUMN: today's names in its text, its default look when its\n * settings chose none, and the keys it reads. Every other column comes back untouched.\n */\nexport function withFormulaDisplayNow(\n field: Field,\n fields: readonly Field[] | null | undefined,\n kindOf: (f: Field) => string,\n currencyCodeOf: (unit: string | null | undefined) => string,\n): Field {\n if (kindOf(field) !== \"formula\") return field;\n let next = withFormulaNamesNow(field, fields);\n const inputs = formulaInputs(field, fields);\n const config = (next.config ?? {}) as Record<string, unknown>;\n if (inputs && inputs.length > 0) next = { ...next, config: { ...config, [FORMULA_INPUT_KEYS]: inputs.map((f) => f.key) } } as Field;\n const chosen = (field as unknown as { display_format?: { id?: unknown } }).display_format;\n const hasLook = chosen && typeof chosen === \"object\" && typeof chosen.id === \"string\" && chosen.id !== \"formula\";\n if (!hasLook) {\n const look = formulaDefaultFormat(field, fields, kindOf, currencyCodeOf);\n if (look) next = { ...next, display_format: look } as unknown as Field;\n }\n return next;\n}\n","\"use client\";\n\n// src/Condition.tsx — @ai-matrx/records-ui\n//\n// THE ONE CONDITION BUILDER, AND IT IS THE ONE THAT WAS ALREADY HERE.\n//\n// It was a private function inside `FormBuilder.tsx` — \"Ask only when <field> <is> <value>\"\n// — writing the store's own Rule expression by Field id. Lane STAGE-RULES-2 needed a\n// condition builder for the stage-settings screen, and building a second one is how a\n// platform ends up with two dialects of the same language that disagree about what `gt`\n// does to an empty value. So the form builder's one moved here, unchanged in what it\n// writes, and both screens mount it.\n//\n// ONE THING DID CHANGE, AND IT IS A DEFECT THIS MOVE FOUND. The value was written as a\n// STRING, always. `{\"op\":\"gt\",\"args\":[{\"field\":…},{\"const\":\"5000\"}]}` compares a number\n// column against the TEXT \"5000\", which is not the question anybody asked — and on a\n// stage gate it is the difference between \"nothing over $5,000\" working and not. A value\n// that is a number is now written as a number, and a value that is not is left exactly as\n// it was typed. `true`/`false` go the same way, for the same reason.\n//\n// IT NESTS NOW, AND IT IS STILL ONE BUILDER (TAILS-2, 2026-09-21). \"It stays deliberately\n// SMALL: one field, one comparison, one value… when a second clause is actually needed, it\n// is added HERE and both screens get it\" — this is that day. The gate the homeowner\n// actually wanted, *\"anything over $10,000 without a signed contract needs sign-off\"*, is\n// two clauses, and until now writing it meant a raw `pipeline_declare` call, which is not\n// something a non-technical person does.\n//\n// SO: `ConditionGroup` draws a list of clauses joined by ALL / ANY, and a clause may itself\n// be one more ALL / ANY group.\n//\n// GROUPS INSIDE GROUPS, AS DEEP AS THE STORE (lane S2-PRIME FILTER-GROUPS, 2026-09-24). A\n// dispatcher's morning view — \"(Open or Scheduled) and (in Ojai or Maria's) and not Low\" — is\n// three groups, one of them a NOT, and the one-level limit could not draw it. The store now\n// compiles the Rule shape to any depth into the one WHERE clause the grid, the board and the\n// dashboard share (`custom.record_filter_sql`), so the builder draws what the store answers:\n// every group carries its own joiner (All / Any / None / Not all), and \"Add a group\" nests a\n// new one under any group. Airtable's and Notion's filter builders are the bar: a group is a\n// box with its own and/or, and nothing about depth is special. A condition the builder still\n// cannot draw (a sibling count, a comparison between two columns) keeps STAGE-RULES-2's\n// answer, unchanged: it is read out in the store's own words with a \"Replace it\" button.\n//\n// THE WORDS ARE ALL / ANY, NOT AND / OR. \"All of these are true\" and \"any of these are\n// true\" is what the person is choosing; `and`/`or` is what the store stores. The store's\n// own node names never reach the screen.\n\nimport { useEffect, useState } from \"react\";\nimport { BasicInput, Button } from \"@ai-matrx/design-system\";\nimport { optionKey, optionLabel, rankTypedMatches, type Field, type RuleExpression } from \"@ai-matrx/records\";\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { choiceChipLookOf } from \"./choiceLooks\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { RelationPicker } from \"./RelationPicker\";\nimport { PickOne } from \"./PickOne\";\nimport { fieldOptionsOnce } from \"./askOnce\";\nimport { editorKindFor } from \"./parity\";\n\n/** The comparisons a condition can make. The store's own operator names. */\nexport const CONDITION_OPS: Array<{ op: string; label: string }> = [\n { op: \"eq\", label: \"is\" },\n { op: \"ne\", label: \"is not\" },\n { op: \"present\", label: \"has been answered\" },\n { op: \"gt\", label: \"is more than\" },\n { op: \"lt\", label: \"is less than\" },\n { op: \"gte\", label: \"is at least\" },\n { op: \"lte\", label: \"is at most\" },\n];\n\n/**\n * A column this condition may speak about, by id — which is how the store names them.\n *\n * 🚨 IT CARRIES THE FIELD NOW, AND THAT IS A DEFECT BEING FIXED (lane RELATION-DISPLAY-2,\n * 2026-09-21). This was `{id, key, label}` and nothing else, so the builder could not know\n * that a column POINTS AT ANOTHER RECORD. A relation clause therefore rendered the same\n * plain text box every other clause gets — and since a relation's stored value is the\n * other record's id (FLD-6 / REL-1), the only way to write a true one was for a person to\n * find and TYPE A UUID. Nobody does that, which means \"only jobs for this customer\" was a\n * gate a non-technical person could not write at all, on a builder whose whole purpose is\n * that they can.\n *\n * `field` is OPTIONAL and everything still works without it: a caller that passes only the\n * three strings gets exactly the old behaviour. Both callers in this package already hold\n * the whole `Field` and were throwing it away one line before handing it over.\n */\nexport interface ConditionField {\n id: string;\n key: string;\n label: string;\n /**\n * The Field itself, when the caller has it. Present, a relation clause picks a record BY\n * ITS DISPLAYED WORDS through `RelationPicker` — the same picker the cell uses, reading\n * the same `relation_words_many` the cell reads, so what a person chooses in a filter and\n * what they see in the column are the same string. It writes the ID, which is what the\n * store compares.\n */\n field?: Field;\n}\n\n/** Does this clause compare against a record rather than a typed value? */\nfunction pointsAtARecord(f: ConditionField | undefined): f is ConditionField & { field: Field } {\n return !!f?.field && f.field.type === \"relation\" && !!f.field.relation_target;\n}\n\n/** Is this a column of choices (a pick-list, one or many)? */\nfunction isChoiceColumn(f: ConditionField | undefined): f is ConditionField & { field: Field } {\n if (!f?.field) return false;\n const kind = String(editorKindFor(f.field));\n return kind === \"select\" || kind === \"multi_select\";\n}\n\n/**\n * A CHOICE COLUMN IS COMPARED BY ONE OF ITS CHOICES, picked from the column's own list: \"Status\n * is [Scheduled]\" never asks a person to type the word and hope it matches. A column whose\n * choices cannot be read (no store on this screen, or a refusal) keeps the typed box.\n */\nfunction ChoiceValue({ field, value, onChange }: { field: Field; value: string; onChange: (word: string) => void }) {\n const client = useOptionalRecordsClient();\n const [choices, setChoices] = useState<Array<{ key: string; label: string }> | null>(null);\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n useEffect(() => {\n if (!client) return;\n let cancelled = false;\n void fieldOptionsOnce(client, field.id).then((got) => {\n if (cancelled) return;\n setChoices(\n got.ok\n ? (got.data ?? [])\n .map((o) => ({ key: optionKey(o), label: optionLabel(o) ?? \"\" }))\n .filter((c) => c.label !== \"\")\n : [],\n );\n });\n return () => {\n cancelled = true;\n };\n }, [client, field.id]);\n if (!choices || choices.length === 0) {\n return (\n <BasicInput\n className=\"h-8 w-28 text-xs\"\n aria-label=\"Condition value\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n // THE SAME COLOURED, SEARCHABLE LIST AS THE CELL EDITOR (lane CELL-EDITORS, night walk 2026-10-06): the\n // filter's value was a bare text list with no search and no colours. It is the one pick list\n // (`PickOrAdd`), each choice the chip its column wears (`choiceChipLookOf`).\n const shown = rankTypedMatches(choices, search.trim(), (c) => c.label);\n return (\n <span className=\"inline-flex min-w-0\" data-records-condition-choice=\"\" data-pick-value={value}>\n <PickOrAdd\n triggerSize=\"compact\"\n triggerLabel={`Choice for ${field.label || field.key}`}\n // THE CHOICE'S WORDS, NEVER ITS KEY (TYPEFORM-2): a condition written by an agent or a form\n // holds the option key; it is shown by the label the person reads.\n triggerText={choices.find((c) => c.key === value || c.label === value)?.label ?? (value || \"Choose\")}\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearch(\"\");\n }}\n search={search}\n onSearch={setSearch}\n items={shown.map((c) => ({\n id: c.key,\n label: c.label,\n chip: choiceChipLookOf(field, c.key, c.label).className,\n picked: c.label === value || c.key === value,\n attrs: { \"data-pick-value\": c.label },\n }))}\n onPick={(key) => {\n const picked = choices.find((c) => c.key === key);\n if (picked) onChange(picked.label);\n setOpen(false);\n setSearch(\"\");\n }}\n empty={<p className=\"p-2 text-xs text-muted-foreground\">No match</p>}\n />\n </span>\n );\n}\n\nexport interface ConditionRowProps {\n /** The words before the row: \"Ask only when\", \"When\". */\n lead: string;\n /** The expression as it stands, or null for \"no condition at all\". */\n expr: RuleExpression | Record<string, unknown> | null | undefined;\n fields: ConditionField[];\n onChange: (next: RuleExpression | null) => void;\n /** What the empty option says: \"always\" on a form question, \"every card\" on a gate. */\n emptyLabel?: string;\n className?: string | undefined;\n}\n\n/**\n * CAN THIS ROW DRAW THAT CONDITION? The builder writes ONE clause — a field, a comparison\n * and a value — and the store's Rule language is bigger than that. A node it cannot draw\n * (a `sibling_count`, an `and`/`or`, a comparison between two columns) rendered as an empty\n * picker is a screen SAYING there is no condition when there is one, and it invites somebody\n * to replace a rule they cannot see. Every caller asks this first and says so instead.\n *\n * Found by a screenshot: the homeowner's own rule — \"a second quote from a DIFFERENT\n * contractor\", a `sibling_count` — opened in the editor as \"— pick a column —\".\n */\nexport function conditionIsSimple(expr: RuleExpression | Record<string, unknown> | null | undefined): boolean {\n if (expr === null || expr === undefined) return true;\n const node = expr as { op?: unknown; args?: unknown };\n if (typeof node.op !== \"string\" || !CONDITION_OPS.some((c) => c.op === node.op)) return false;\n if (!Array.isArray(node.args)) return false;\n const first = node.args[0] as { field?: unknown } | undefined;\n if (!first || typeof first.field !== \"string\") return false;\n if (node.op === \"present\") return node.args.length === 1;\n const second = node.args[1] as { const?: unknown } | undefined;\n return node.args.length === 2 && !!second && \"const\" in second;\n}\n\n/**\n * What a condition this row cannot draw actually ASKS, in the words the store uses for it.\n * Not a pretty-printer for the whole Rule language — enough that a person reading a rule\n * they cannot edit here still knows what it does before deciding to replace it.\n */\nexport function conditionInWords(\n expr: RuleExpression | Record<string, unknown> | null | undefined,\n fields: ConditionField[],\n): string {\n const name = (id: unknown) => {\n const f = fields.find((x) => x.id === id);\n return f ? f.label || f.key : \"a column\";\n };\n const said: Record<string, string> = {\n eq: \"is\", ne: \"is not\", gt: \"is more than\", lt: \"is less than\",\n gte: \"is at least\", lte: \"is at most\", and: \"and\", or: \"or\",\n matches: \"matches\",\n };\n const walk = (node: unknown): string => {\n if (node === null || node === undefined) return \"nothing\";\n const n = node as Record<string, unknown>;\n if (\"const\" in n) return JSON.stringify(n[\"const\"]);\n if (typeof n[\"field\"] === \"string\" && !(\"op\" in n)) return name(n[\"field\"]);\n const op = typeof n[\"op\"] === \"string\" ? n[\"op\"] : \"\";\n if (op === \"previous\" && typeof n[\"field\"] === \"string\") return `what ${name(n[\"field\"])} used to say`;\n if (op === \"sibling_count\") {\n const same = (n[\"same\"] as unknown[] | undefined) ?? [];\n const differs = (n[\"differs\"] as unknown[] | undefined) ?? [];\n const sameWords = same.length > 0 ? ` for the same ${same.map(name).join(\" and \")}` : \"\";\n const diffWords = differs.length > 0 ? ` from a different ${differs.map(name).join(\" and \")}` : \"\";\n return `how many others there are${sameWords}${diffWords}`;\n }\n if (op === \"stage_count\") return \"how many are in that column already\";\n if (op === \"actor_at_least\") return `whoever is moving it is at least ${String(n[\"level\"] ?? \"somebody\")}`;\n const args = Array.isArray(n[\"args\"]) ? (n[\"args\"] as unknown[]) : [];\n if (op === \"not\") return `not ${walk(args[0])}`;\n if (op === \"present\") return `${walk(args[0])} has been answered`;\n const word = said[op] ?? op;\n if (op === \"and\" || op === \"or\") return args.map(walk).join(` ${word} `);\n if (args.length === 2) return `${walk(args[0])} ${word} ${walk(args[1])}`;\n if (args.length === 1) return `${walk(args[0])} ${word}`;\n return op;\n };\n return walk(expr);\n}\n\n/**\n * A value typed into a text box, as the store should hold it. A number column compared\n * against the text \"5000\" is not the comparison anybody meant, and the store has no way\n * to guess which was intended after the fact.\n */\nexport function conditionValue(typed: string): string | number | boolean {\n const trimmed = typed.trim();\n if (trimmed === \"\") return typed;\n if (trimmed === \"true\") return true;\n if (trimmed === \"false\") return false;\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n const asNumber = Number(trimmed);\n if (Number.isFinite(asNumber)) return asNumber;\n }\n return typed;\n}\n\n/** The one condition row. It writes the store's own Rule expression, by Field id. */\nexport function ConditionRow({ lead, expr, fields, onChange, emptyLabel = \"always\", className }: ConditionRowProps) {\n const node = (expr ?? null) as { op?: string; args?: Array<{ field?: string; const?: unknown }> } | null;\n const op = node?.op ?? \"\";\n const onField = node?.args?.[0]?.field ?? \"\";\n const value = node?.args?.[1]?.const ?? \"\";\n const chosen = fields.find((f) => f.id === onField);\n\n function write(next: { op?: string; field?: string; value?: unknown }) {\n // A FRESH ROW STARTS AT \"is\". Picking a column on an empty row used to write `null` —\n // no comparison had been chosen yet, and no comparison picker is drawn until a column is —\n // so on a row with nothing in it the column picker was a control that did nothing\n // (found by S2-PRIME's \"Add a group\" test). The first comparison in the list is the default.\n const chosenOp = next.op ?? (op || (next.field ? CONDITION_OPS[0]!.op : \"\"));\n const chosenField = next.field ?? onField;\n const chosenValue = next.value ?? value;\n if (!chosenOp || !chosenField) {\n onChange(null);\n return;\n }\n onChange(\n chosenOp === \"present\"\n ? ({ op: \"present\", args: [{ field: chosenField }] } as RuleExpression)\n : ({ op: chosenOp, args: [{ field: chosenField }, { const: chosenValue }] } as RuleExpression),\n );\n }\n\n return (\n <div className={className ?? \"flex flex-wrap items-center gap-1 text-xs\"}>\n <span className=\"text-muted-foreground\">{lead}</span>\n <PickOne\n label=\"Condition field\"\n className=\"h-8 w-auto min-w-[7rem] text-xs\"\n value={onField}\n onChange={(field) => write({ field })}\n options={[{ value: \"\", label: emptyLabel }, ...fields.map((f) => ({ value: f.id, label: f.label || f.key }))]}\n attrs={{ \"data-condition\": \"field\" }}\n />\n {/* A CONDITION ON A QUESTION THAT IS GONE SAYS SO (TYPEFORM-2), never a blank picker. */}\n {onField && !fields.some((f) => f.id === onField) ? (\n <span\n className=\"rounded bg-destructive px-1.5 py-0.5 text-[11px] font-medium text-destructive-foreground\"\n title=\"This condition names a question that is no longer on the form.\"\n data-records-condition-missing=\"\"\n >\n Missing question\n </span>\n ) : null}\n {onField ? (\n <>\n <PickOne\n label=\"Condition comparison\"\n className=\"h-8 w-auto min-w-[6rem] text-xs\"\n value={op}\n onChange={(next) => write({ op: next })}\n options={CONDITION_OPS.map((c) => ({ value: c.op, label: c.label }))}\n attrs={{ \"data-condition\": \"comparison\" }}\n />\n {op === \"present\" ? null : pointsAtARecord(chosen) ? (\n // A RECORD IS PICKED BY ITS WORDS, NEVER TYPED AS AN ID. The same picker the\n // cell uses, on the same `relation_words_many` the cell reads, so a filter and\n // the column it filters can never disagree about what a record is called. It\n // is asked for ONE record even when the column holds several: a clause compares\n // against one value, and a picker that let somebody choose three would be\n // writing an expression this row cannot draw back.\n <RelationPicker\n field={{ ...chosen.field, multi: false }}\n value={value === \"\" ? null : value}\n onChange={(next) => write({ value: next === null || next === undefined ? \"\" : String(next) })}\n id=\"condition-value-record\"\n className=\"min-w-[8rem]\"\n // PICKING A VALUE TO FILTER BY IS NOT A REASON TO ADD A CUSTOMER TO THE\n // BOOK. Every other relation surface offers \"New <thing>\"; this one is\n // choosing what to LOOK at, and a create here would put a row in the\n // target Table that nobody asked for.\n allowCreate={false}\n />\n ) : isChoiceColumn(chosen) && (op === \"eq\" || op === \"ne\") ? (\n <ChoiceValue field={chosen.field} value={String(value ?? \"\")} onChange={(word) => write({ value: word })} />\n ) : (\n <BasicInput\n className=\"h-8 w-28 text-xs\"\n aria-label=\"Condition value\"\n value={String(value ?? \"\")}\n onChange={(e) => write({ value: conditionValue(e.target.value) })}\n />\n )}\n </>\n ) : null}\n </div>\n );\n}\n\n// ═══════════════════════════════════════════════════════════════════════════════════════\n// GROUPS OF CLAUSES, NESTED AS DEEP AS A PERSON BUILDS THEM.\n// ═══════════════════════════════════════════════════════════════════════════════════════\n\n/**\n * The four ways a group's clauses can be joined, in the words a person chooses between.\n * `none` is NOT(ANY …) and `notall` is NOT(ALL …) — the store's own `not` over its own `or` /\n * `and`, so a group is still nothing but Rule nodes.\n */\nexport type ConditionJoiner = \"and\" | \"or\" | \"none\" | \"notall\";\n\nconst JOINERS: ReadonlyArray<{ op: ConditionJoiner; label: string }> = [\n { op: \"and\", label: \"All of these are true\" },\n { op: \"or\", label: \"Any of these is true\" },\n { op: \"none\", label: \"None of these is true\" },\n { op: \"notall\", label: \"Not all of these are true\" },\n];\n\ntype Node = Record<string, unknown>;\n\nfunction asNode(expr: unknown): Node | null {\n return expr && typeof expr === \"object\" && !Array.isArray(expr) ? (expr as Node) : null;\n}\n\nfunction argsOf(node: Node): unknown[] {\n return Array.isArray(node[\"args\"]) ? (node[\"args\"] as unknown[]) : [];\n}\n\n/**\n * Is this node a group, and which? An `and` / `or` with its arguments; a `not` of an `or` is\n * \"None of these\", a `not` of an `and` is \"Not all of these\", and a `not` of one clause is\n * \"None of these\" with one clause in it — which is exactly what \"priority is not Low, as a group\"\n * reads as.\n */\nexport function conditionGroupOf(expr: unknown): { joiner: ConditionJoiner; args: unknown[] } | null {\n const node = asNode(expr);\n if (!node) return null;\n const op = node[\"op\"];\n if (op === \"and\" || op === \"or\") return { joiner: op, args: argsOf(node) };\n if (op === \"not\") {\n const inner = asNode(argsOf(node)[0]);\n if (!inner) return null;\n if (inner[\"op\"] === \"or\") return { joiner: \"none\", args: argsOf(inner) };\n if (inner[\"op\"] === \"and\") return { joiner: \"notall\", args: argsOf(inner) };\n if (conditionIsSimple(inner)) return { joiner: \"none\", args: [inner] };\n }\n return null;\n}\n\n/**\n * CAN THE BUILDER DRAW THIS CONDITION? — the question every caller asks before it renders,\n * and the reason a rule somebody cannot see is never silently saved over.\n *\n * Drawable means: nothing; one clause; or a group of drawable members, to any depth. `depth`\n * still limits it for a caller that wants a shallower builder (0 = one level of clauses and no\n * nested group). `conditionIsSimple` is still the leaf test and still exported.\n */\nexport function conditionIsDrawable(\n expr: RuleExpression | Record<string, unknown> | null | undefined,\n depth = Number.POSITIVE_INFINITY,\n): boolean {\n if (expr === null || expr === undefined) return true;\n const group = conditionGroupOf(expr);\n if (!group) return conditionIsSimple(expr);\n if (group.args.length === 0) return true;\n return group.args.every((arg) => {\n const node = asNode(arg);\n if (node === null) return false;\n return conditionIsSimple(node) || (depth > 0 && conditionIsDrawable(node, depth - 1));\n });\n}\n\n/** The clauses of an expression, as the group editor holds them: always a list. */\nfunction clausesOf(expr: RuleExpression | Record<string, unknown> | null | undefined): {\n joiner: ConditionJoiner;\n args: unknown[];\n} {\n const group = conditionGroupOf(expr);\n if (group) return group;\n return { joiner: \"and\", args: expr === null || expr === undefined ? [] : [expr] };\n}\n\n/**\n * The store's expression for a group. ONE clause of an ALL / ANY is written as that clause and\n * never as a one-armed `and` — a person who writes one condition and reads back\n * `{\"op\":\"and\",\"args\":[…]}` has been given something they did not type — unless `keep` says the\n * person is holding a group open (they just made it, or just changed its joiner). A NOT group\n * always keeps its `not`, because dropping it would reverse the question.\n */\nexport function writeConditionGroup(joiner: ConditionJoiner, args: unknown[], keep = false): RuleExpression | null {\n const kept = args.filter((a) => a !== null && a !== undefined);\n if (kept.length === 0) return null;\n if (joiner === \"none\" || joiner === \"notall\") {\n const inner = kept.length === 1 && joiner === \"none\"\n ? kept[0]\n : { op: joiner === \"none\" ? \"or\" : \"and\", args: kept };\n return { op: \"not\", args: [inner] } as unknown as RuleExpression;\n }\n if (kept.length === 1 && !keep) return kept[0] as RuleExpression;\n return { op: joiner, args: kept } as unknown as RuleExpression;\n}\n\nexport interface ConditionGroupProps {\n /** The words before the condition: \"When\", \"Ask only when\", \"Show jobs where\". */\n lead: string;\n expr: RuleExpression | Record<string, unknown> | null | undefined;\n fields: ConditionField[];\n onChange: (next: RuleExpression | null) => void;\n /** What the empty option says: \"always\", \"every card\". */\n emptyLabel?: string;\n /**\n * false draws one level of clauses and no \"Add a group\". Left out, groups nest as deep as a\n * person builds them — the depth the store compiles.\n */\n allowNesting?: boolean;\n /**\n * How many levels of groups a person may make below the whole condition (Notion's advanced\n * filter: 2 — a group, and a group inside it). Left out, no limit. A deeper saved question still\n * draws; only \"Add a group\" stops at the limit.\n */\n maxDepth?: number | undefined;\n /** How deep this group sits (0 = the whole condition). Set by the builder itself. */\n depth?: number;\n /** A nested group can take itself away; the outermost one cannot. */\n onRemove?: (() => void) | undefined;\n className?: string | undefined;\n}\n\n/**\n * THE ONE CONDITION BUILDER. One clause reads exactly as it always has — a single row, no\n * joiner, no chrome — and the joiner appears once there is something to join, so a person\n * writing one condition never meets a control for a problem they do not have. A nested group\n * always shows its joiner: it is a box with its own and / or, and that is the whole point of it.\n */\nexport function ConditionGroup({\n lead,\n expr,\n fields,\n onChange,\n emptyLabel = \"always\",\n allowNesting = true,\n maxDepth,\n depth = 0,\n onRemove,\n className,\n}: ConditionGroupProps) {\n const { joiner, args } = clausesOf(expr);\n // A CLAUSE BEING TYPED IS NOT YET A CLAUSE. Pressing \"Add another condition\" or \"Add a group\"\n // opens an empty row; it joins the expression the moment it says something. Appending a `null`\n // to the saved expression instead would either write a half-clause the store cannot read or\n // vanish on the next render, which is a button that does nothing. AN EMPTY GROUP IS NEVER\n // WRITTEN either: `{\"op\":\"or\",\"args\":[]}` is a rule that refuses nobody (STAGE-RULES-2 found\n // exactly that standing in for a real house rule), so a new group is born with its first clause.\n const [drafting, setDrafting] = useState<\"clause\" | \"group\" | null>(null);\n\n const nested = depth > 0;\n const replaceAt = (index: number, next: unknown) => {\n const nextArgs = args.slice();\n if (next === null || next === undefined) nextArgs.splice(index, 1);\n else nextArgs[index] = next;\n onChange(writeConditionGroup(joiner, nextArgs, nested));\n };\n const joinWord = (index: number) =>\n index === 0 ? lead : joiner === \"or\" || joiner === \"none\" ? \"or\" : \"and\";\n const showJoiner = nested || args.length > 1 || joiner === \"none\" || joiner === \"notall\";\n /** The joiner a new group starts with: the other one, which is why anybody makes a group. */\n const opposite: ConditionJoiner = joiner === \"or\" || joiner === \"none\" ? \"and\" : \"or\";\n\n return (\n <div\n className={className ?? \"flex flex-col gap-1 text-xs\"}\n data-testid={nested ? \"condition-nested-group\" : \"condition-group\"}\n data-depth={depth}\n >\n {showJoiner ? (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-muted-foreground\">{nested ? \"Group:\" : lead}</span>\n <PickOne\n label={nested ? `How the conditions in this group are joined (level ${depth + 1})` : \"How these conditions are joined\"}\n className=\"h-8 w-auto min-w-[9rem] text-xs\"\n value={joiner}\n onChange={(next) => onChange(writeConditionGroup(next as ConditionJoiner, args, true))}\n options={JOINERS.map((j) => ({ value: j.op, label: j.label }))}\n attrs={{ \"data-condition\": \"joiner\" }}\n />\n {nested && onRemove ? (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1 text-xs\"\n data-testid=\"condition-remove-group\"\n onClick={onRemove}\n >\n Remove this group\n </Button>\n ) : null}\n </div>\n ) : null}\n\n {args.length === 0 ? (\n <ConditionRow\n lead={lead}\n emptyLabel={emptyLabel}\n expr={null}\n fields={fields}\n onChange={(next) => onChange(next)}\n />\n ) : (\n args.map((arg, index) => {\n const group = conditionGroupOf(arg);\n const key = `clause-${index}`;\n if (group && allowNesting) {\n return (\n <div key={key} className=\"ml-4 rounded border border-dashed p-1\">\n <ConditionGroup\n lead={joinWord(index)}\n expr={arg as RuleExpression}\n fields={fields}\n onChange={(next) => replaceAt(index, next)}\n onRemove={() => replaceAt(index, null)}\n emptyLabel={emptyLabel}\n maxDepth={maxDepth}\n depth={depth + 1}\n />\n </div>\n );\n }\n return (\n <ConditionRow\n key={key}\n lead={showJoiner || args.length > 1 ? joinWord(index) : lead}\n emptyLabel={emptyLabel}\n expr={arg as RuleExpression}\n fields={fields}\n onChange={(next) => replaceAt(index, next)}\n />\n );\n })\n )}\n\n {drafting ? (\n <div className={drafting === \"group\" ? \"ml-4 rounded border border-dashed p-1\" : undefined}>\n <ConditionRow\n lead={drafting === \"group\" ? `${joinWord(1)}, a group where` : joinWord(1)}\n emptyLabel={emptyLabel}\n expr={null}\n fields={fields}\n onChange={(next) => {\n if (next === null) return;\n const born = drafting === \"group\" ? writeConditionGroup(opposite, [next], true) : next;\n setDrafting(null);\n onChange(writeConditionGroup(joiner, [...args, born], nested || drafting === \"group\"));\n }}\n />\n </div>\n ) : null}\n\n {args.length > 0 && !drafting ? (\n <div className=\"flex items-center gap-1\">\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1 text-xs\"\n data-testid=\"condition-add-clause\"\n onClick={() => setDrafting(\"clause\")}\n >\n Add another condition\n </Button>\n {allowNesting && (maxDepth === undefined || depth < maxDepth) ? (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1 text-xs\"\n data-testid=\"condition-add-group\"\n onClick={() => setDrafting(\"group\")}\n >\n Add a group\n </Button>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/FieldRetype.tsx — @ai-matrx/records-ui\n//\n// CHANGE WHAT A COLUMN HOLDS (merged-grid review 2, 2026-09-27, C3).\n//\n// The field panel used to say \"What a column holds cannot be changed here… add a new column and move\n// the values across\" — while the store has always been able to do it: `custom.migrate_retype`\n// converts every value that converts and keeps each one that does not in that record's `_retired`,\n// with the reason (FLD-4 / T12). The older /data grid reached it through its seam\n// (`changeFieldType`). This carries it into the package's panel, Airtable's \"change field type\",\n// bettered in the two places Airtable is weakest:\n// · BEFORE anything changes, the panel says how many values convert and how many will be kept\n// aside, with examples — counted from the store's own grouping of the column's values and the\n// mirror of the store's conversion rules (`previewRetype`, @ai-matrx/records);\n// · nothing is ever cleared: a value that does not fit stays with its record, with the reason.\n// A refusal from the store is shown in its own words, and nothing was changed.\n\nimport { useEffect, useState } from \"react\";\nimport { previewRetype, type Field, type RecordsError, type RetypePreview, type Uuid } from \"@ai-matrx/records\";\nimport { tableShapeChanged, useRecordsClient } from \"@ai-matrx/records/react\";\nimport { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@ai-matrx/design-system\";\nimport { editorKindFor } from \"./parity\";\nimport { fieldName } from \"./names\";\nimport { RefusalNotice } from \"./Refusal\";\nimport { useRecordsUi } from \"./host\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** What a column can be changed INTO here, in the words the add-column menu uses. */\nexport const RETYPE_TARGETS = [\n { id: \"text\", behaviour: \"text\", kind: null, label: \"Text\", holds: \"words\" },\n { id: \"number\", behaviour: \"range\", kind: \"number\", label: \"Number\", holds: \"a number\" },\n // A DATE is a `range` of kind date: `migrate_retype` alone cannot say \"date\" (it keeps the old\n // kind, so every date would be kept aside), so this one goes through `custom.field_update`'s own\n // retype arm (`parity_type: datetime`), which converts on the SAME trigger and keeps what does not\n // fit in `_retired` with the reason — measured on the live store 2026-09-28.\n { id: \"date\", behaviour: \"range\", kind: \"date\", label: \"Date\", holds: \"a date\" },\n { id: \"checkbox\", behaviour: \"boolean\", kind: null, label: \"Yes / no\", holds: \"a yes or a no\" },\n] as const;\n\ntype Target = (typeof RETYPE_TARGETS)[number];\n\n/** How many different values the preview asks the store to group — one question, one answer. */\nconst PREVIEW_GROUPS = 1000;\n\n/**\n * Which columns this panel can change. A choice list or a link stores record ids, and a worked-out\n * column stores nothing typed, so changing any of them to words or numbers would keep ids nobody can\n * read — those are left to their own panels and say so.\n */\nexport function retypeableFrom(field: Field): boolean {\n const behaviour = String(field.type);\n return behaviour === \"text\" || behaviour === \"range\" || behaviour === \"boolean\";\n}\n\n/**\n * WHY THIS COLUMN'S KIND IS NOT CHANGED HERE, in its own kind's words (lane VIEWS-AND-FIELDS W1-B\n * item 7a). One sentence for every kind `retypeableFrom` turns away — a plain choice column used\n * to be told it \"holds records picked from a list or another table… record ids\". The why behind\n * all of them (the store keeps ids or works the value out) is the author's, kept above.\n */\nexport function whyNotRetypeable(field: Field): string {\n const kind = String(editorKindFor(field));\n if (kind === \"select\" || kind === \"multi_select\") return \"A choice column. Its choices are edited below.\";\n if (kind === \"member\") return \"Holds people, so its kind is not changed here.\";\n if (kind === \"attachment\") return \"Holds files, so its kind is not changed here.\";\n if (kind === \"relation\" || kind === \"entity_reference\") return \"Links to records, so its kind is not changed here.\";\n if (kind === \"formula\" || kind === \"lookup\" || kind === \"rollup\" || String(field.type) === \"formula\") {\n return \"Worked out by the table, so its kind is not changed here.\";\n }\n return \"Its kind is not changed here.\";\n}\n\n/** What this column holds now, as one of the targets' ids. */\nfunction currentTarget(field: Field): string {\n const kind = String(editorKindFor(field));\n if (String(field.type) === \"boolean\") return \"checkbox\";\n if (kind === \"datetime\" || kind === \"date\") return \"date\";\n if (String(field.type) === \"range\") return \"number\";\n return \"text\";\n}\n\nexport function FieldRetype({ field, tableId, onRetyped }: { field: Field; tableId: Uuid; onRetyped?: (() => void) | undefined }) {\n const client = useRecordsClient();\n const notify = useRecordsUi().notify;\n const [to, setTo] = useState<Target | null>(null);\n const [preview, setPreview] = useState<RetypePreview | null>(null);\n const [asking, setAsking] = useState(false);\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n const [busy, setBusy] = useState(false);\n const [said, setSaid] = useState<string | null>(null);\n const name = fieldName(field);\n const targets = RETYPE_TARGETS.filter((t) => t.id !== currentTarget(field));\n\n // THE COUNT BEFORE THE CHANGE: the store groups the column's values; the mirror judges each.\n useEffect(() => {\n if (!to) return;\n let cancelled = false;\n setPreview(null);\n setRefusal(null);\n setAsking(true);\n void client\n .recordAggregate({ table_id: tableId, groupBy: [field.key], measures: [{ op: \"count\" }], limit: PREVIEW_GROUPS })\n .then((answer) => {\n if (cancelled) return;\n setAsking(false);\n if (!answer.ok) {\n setRefusal(answer.error);\n return;\n }\n const groups = answer.data.map((row) => ({ value: row.groups[field.key] ?? null, count: row.row_count }));\n setPreview(previewRetype({ type: to.behaviour, kind: to.kind }, groups, answer.data.length >= PREVIEW_GROUPS));\n });\n return () => {\n cancelled = true;\n };\n }, [client, tableId, field.key, to]);\n\n if (!retypeableFrom(field)) {\n return (\n <p className=\"text-[11px] text-muted-foreground\" data-records-retype=\"not-here\">\n {whyNotRetypeable(field)}\n </p>\n );\n }\n\n const change = async () => {\n if (!to) return;\n setBusy(true);\n setRefusal(null);\n let holding: number;\n let aside: number;\n if (to.id === \"date\") {\n const done = await client.fieldUpdate({ field_id: field.id as Uuid, patch: { parity_type: \"datetime\" } });\n setBusy(false);\n if (!done.ok) {\n setRefusal(done.error);\n return;\n }\n holding = preview?.converts ?? 0;\n aside = preview?.keptAside ?? 0;\n } else {\n const done = await client.migrateRetype({ field_id: field.id as Uuid, to: to.behaviour });\n setBusy(false);\n if (!done.ok) {\n setRefusal(done.error);\n return;\n }\n holding = done.data.records_still_holding_a_value ?? 0;\n aside = done.data.values_in_retired_for_this_field ?? 0;\n // UNDO, AT ONCE (TABLE-ACTIONS wave 5, T5.2): the store recorded the change as a Migration;\n // `custom.migrate_undo` puts the column's kind back and the trigger converts the values again.\n const migration = done.data.migration_id;\n if (migration && notify?.reversible) {\n notify.reversible({\n verb: \"change\",\n noun: \"column\",\n subject: name,\n undo: async () => {\n const back = await client.migrateUndo({ migration_id: migration as Uuid });\n if (!back.ok) throw new Error(refusalSentence(back.error));\n tableShapeChanged(tableId);\n onRetyped?.();\n },\n });\n }\n }\n setSaid(\n `${name} now holds ${to.holds}. ${holding} ${holding === 1 ? \"record holds\" : \"records hold\"} a value` +\n (aside > 0 ? `; ${aside} ${aside === 1 ? \"value that did not fit was\" : \"values that did not fit were\"} kept with ${aside === 1 ? \"its record\" : \"their records\"}, with the reason.` : \".\"),\n );\n setTo(null);\n setPreview(null);\n tableShapeChanged(tableId);\n onRetyped?.();\n };\n\n return (\n <div className=\"flex flex-col gap-1.5\" data-records-retype=\"\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Select value={to?.id ?? \"\"} onValueChange={(next) => setTo(targets.find((t) => t.id === next) ?? null)}>\n <SelectTrigger size=\"sm\" aria-label=\"Change what this column holds\" className=\"w-auto min-w-[12rem]\">\n <SelectValue placeholder=\"Change what this column holds\" />\n </SelectTrigger>\n <SelectContent>\n {targets.map((t) => (\n <SelectItem key={t.id} value={t.id}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {to ? (\n <Button size=\"sm\" disabled={busy || asking || preview === null} onClick={() => void change()} data-records-retype-go=\"\">\n {busy ? \"Changing…\" : `Change to ${to.label}`}\n </Button>\n ) : null}\n {to ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => setTo(null)} disabled={busy}>\n Cancel\n </Button>\n ) : null}\n </div>\n {to && asking ? <p className=\"text-[11px] text-muted-foreground\">Counting {name}'s values…</p> : null}\n {to && preview ? (\n <p className=\"text-[11px] text-muted-foreground\" data-records-retype-preview=\"\">\n {preview.converts} {preview.converts === 1 ? \"value converts\" : \"values convert\"} to {to.label.toLowerCase()}\n {preview.keptAside > 0\n ? `; ${preview.keptAside} ${preview.keptAside === 1 ? \"value does\" : \"values do\"} not fit and will be kept aside with ${preview.keptAside === 1 ? \"its record\" : \"their records\"}, with the reason — nothing is deleted` +\n (preview.examples.length > 0 ? ` (for example ${preview.examples.map((e) => `“${e}”`).join(\", \")})` : \"\")\n : \"\"}\n {preview.partial ? \". Counted over the first 1,000 different values.\" : \".\"}\n </p>\n ) : null}\n {refusal ? <RefusalNotice error={refusal} /> : null}\n {said ? (\n <p role=\"status\" className=\"text-[11px] text-muted-foreground\" data-records-retype-done=\"\">\n {said}\n </p>\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/FieldRulePreview.tsx — @ai-matrx/records-ui · lane 10 P4c (V13 #4)\n//\n// THE COUNT BEFORE A CHECK TIGHTENS. Saving a smaller largest, a larger smallest, a shorter\n// longest, a new pattern or a lower top star sets aside every value already written that no longer\n// fits — kept in its record with the reason, never deleted. A person is told how many, with\n// examples, before pressing Save: the same question and the same sentence `FieldRetype` asks\n// before a retype (the store groups the column's values; the mirror `previewRuleChange` judges\n// each group). The store still decides on Save.\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { previewRuleChange, type Field, type FieldRule, type RecordsError, type RetypePreview, type Uuid } from \"@ai-matrx/records\";\nimport { useRecordsClient } from \"@ai-matrx/records/react\";\nimport { RefusalNotice } from \"./Refusal\";\nimport { fieldName } from \"./names\";\n\nconst PREVIEW_GROUPS = 1000;\n\n/** The checks as the store compares them: kind, value, shortest. Order does not matter. */\nfunction ruleWords(rules: ReadonlyArray<FieldRule>): string {\n return rules\n .map((r) => JSON.stringify([r.kind, r.value === undefined || r.value === \"\" ? null : String(r.value), r.min ?? null, r.example ?? null]))\n .sort()\n .join(\"|\");\n}\n\n/** True when the edited checks differ from what the column holds now. */\nexport function rulesChanged(was: ReadonlyArray<FieldRule>, now: ReadonlyArray<FieldRule>): boolean {\n return ruleWords(was) !== ruleWords(now);\n}\n\n/** A column the store keeps numbers in (`range` is the store's one number type). */\nfunction holdsNumbers(field: Field): boolean {\n return field.type === \"range\";\n}\n\n/**\n * THE GROUP AS THE COLUMN HOLDS IT. The store groups by the value's TEXT (`data ->> key`), so a\n * number column's 0 comes back as \"0\" — and the mirror judges `min` / `max` on numbers only, so\n * \"at least 1\" over a stored 0 was counted as fitting while the store then set the 0 aside (live\n * walk, 2026-10-05). On a number column a group that reads as a number is judged as that number.\n */\nexport function groupValue(value: unknown, numbers: boolean): unknown {\n if (!numbers || typeof value !== \"string\") return value;\n const text = value.trim();\n return /^-?(\\d+\\.?\\d*|\\.\\d+)([eE][-+]?\\d+)?$/.test(text) ? Number(text) : value;\n}\n\nexport function FieldRulePreview({ field, tableId, rules }: { field: Field; tableId: Uuid; rules: ReadonlyArray<FieldRule> }) {\n const client = useRecordsClient();\n const [preview, setPreview] = useState<RetypePreview | null>(null);\n const [refusal, setRefusal] = useState<RecordsError | null>(null);\n const key = useMemo(() => ruleWords(rules), [rules]);\n // `key` stands for `rules` by value, so typing the same check twice asks once; the ref is what is judged.\n const latest = useRef(rules);\n latest.current = rules;\n const name = fieldName(field);\n\n useEffect(() => {\n let cancelled = false;\n setPreview(null);\n setRefusal(null);\n const timer = setTimeout(() => {\n void client\n .recordAggregate({ table_id: tableId, groupBy: [field.key], measures: [{ op: \"count\" }], limit: PREVIEW_GROUPS })\n .then((answer) => {\n if (cancelled) return;\n if (!answer.ok) {\n setRefusal(answer.error);\n return;\n }\n const numbers = holdsNumbers(field);\n const groups = answer.data.map((row) => ({ value: groupValue(row.groups[field.key] ?? null, numbers), count: row.row_count }));\n setPreview(previewRuleChange(latest.current, groups, answer.data.length >= PREVIEW_GROUPS));\n });\n }, 300);\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [client, tableId, field.key, key]);\n\n if (refusal) return <RefusalNotice error={refusal} />;\n if (!preview) {\n return (\n <p className=\"text-[11px] text-muted-foreground\" data-records-rule-preview=\"counting\">\n Counting {name}'s values…\n </p>\n );\n }\n if (preview.keptAside === 0) {\n return (\n <p className=\"text-[11px] text-muted-foreground\" data-records-rule-preview=\"fits\">\n Every value already in {name} still fits{preview.partial ? \" (counted over the first 1,000 different values)\" : \"\"}.\n </p>\n );\n }\n return (\n <p className=\"text-[11px] text-amber-700 dark:text-amber-400\" role=\"status\" data-records-rule-preview=\"sets-aside\">\n {preview.keptAside} {preview.keptAside === 1 ? \"value no longer fits and will be\" : \"values no longer fit and will be\"} kept aside with{\" \"}\n {preview.keptAside === 1 ? \"its record\" : \"their records\"}, with the reason — nothing is deleted\n {preview.examples.length > 0 ? ` (for example ${preview.examples.map((e) => `“${e}”`).join(\", \")})` : \"\"}\n {preview.partial ? \". Counted over the first 1,000 different values.\" : \".\"}\n </p>\n );\n}\n","\"use client\";\n\n// src/ColumnLook.tsx — @ai-matrx/records-ui · merge tranche 6a (column settings)\n//\n// HOW A COLUMN LOOKS, SET IN ITS OWN SETTINGS: each choice's colour (drawn on each row of the one\n// choice editor, `ChoiceListEditor.tsx`; this file turns those rows into the Field's document), and what a plain column\n// \"shows as\" (money, a percent, a star rating, a date style…). The older /data grid kept both in\n// its Column settings dialog (`ColumnSettingsDialog.tsx`, `ChoiceOptionsEditor.tsx`,\n// `FieldFormatPicker.tsx`); the store keeps both ON THE FIELD as its `display_format`, written by\n// `custom.field_update`'s settings arm — the same document the /data Sheet's seam writes, so\n// the colours a person set on either grid are the colours the other one draws.\n//\n// Colours are names from the design-system palette (`STYLE_COLORS`), never a raw hex; the\n// swatches are the design-system's own classes.\n\nimport type { Field } from \"@ai-matrx/records\";\nimport type { StyleColor } from \"@ai-matrx/design-system/data-table\";\n\nimport type { ChoiceListRow } from \"./ChoiceListEditor\";\nimport { choiceLooksOf, choiceWord, displayFormatOf } from \"./choiceLooks\";\nimport { editorKindFor } from \"./parity\";\n\n/** One choice and the colour it wears (null: none). */\nexport interface ChoiceColorRow {\n value: string;\n color: StyleColor | null;\n}\n\n/** The words a choice option record keeps (`title` for a list the store made, `name` for a moved one). */\nexport function optionWords(options: ReadonlyArray<{ data?: Record<string, unknown> | null } | Record<string, unknown>>): string[] {\n const out: string[] = [];\n for (const option of options) {\n const data = ((option as { data?: Record<string, unknown> | null }).data ?? option) as Record<string, unknown>;\n const word = [data[\"title\"], data[\"name\"], data[\"label\"]].find((w) => typeof w === \"string\" && w.trim() !== \"\");\n if (typeof word === \"string\" && !out.includes(word.trim())) out.push(word.trim());\n }\n return out;\n}\n\n/** The rows the colour editor starts from: every option, with the colour the Field keeps for it. */\nexport function startingChoiceColors(field: Field, words: readonly string[]): ChoiceColorRow[] {\n const looks = choiceLooksOf(field);\n const rows: ChoiceColorRow[] = words.map((value) => {\n const look = looks.find((l) => choiceWord(l.value) === choiceWord(value) || (l.label && choiceWord(l.label) === choiceWord(value)));\n return { value, color: look?.color ?? null };\n });\n // A colour kept for a word that is no longer an option stays in the list, so saving never drops it.\n for (const look of looks) {\n if (!rows.some((r) => choiceWord(r.value) === choiceWord(look.value))) rows.push({ value: look.value, color: look.color ?? null });\n }\n return rows;\n}\n\n/**\n * THE DISPLAY DOCUMENT A SAVE SENDS for a choice column: the Field's own document with its\n * choices' colours replaced — every other option it carries (labels, groups, help) kept. `null`\n * means nothing changed and nothing is sent.\n */\nexport function choiceDisplayPatch(field: Field, rows: readonly ChoiceColorRow[]): { id: string; options: Record<string, unknown> } | null {\n const held = displayFormatOf(field);\n const before = choiceLooksOf(field);\n const changed = rows.some((row) => {\n const was = before.find((l) => choiceWord(l.value) === choiceWord(row.value))?.color ?? null;\n return was !== row.color;\n });\n if (!changed) return null;\n const heldChoices = Array.isArray(held?.options[\"choices\"]) ? (held!.options[\"choices\"] as Array<Record<string, unknown>>) : [];\n const choices = rows\n .map((row) => {\n const kept = heldChoices.find((c) => typeof c[\"value\"] === \"string\" && choiceWord(c[\"value\"]) === choiceWord(row.value)) ?? {};\n const { color: _old, ...rest } = kept;\n return { ...rest, value: typeof kept[\"value\"] === \"string\" ? kept[\"value\"] : row.value, ...(row.color ? { color: row.color } : {}) };\n })\n .filter((c) => Object.keys(c).length > 1);\n const id = held?.id ?? (editorKindFor(field) === \"multi_select\" ? \"multi_choice\" : \"choice\");\n return { id, options: { ...(held?.options ?? {}), choices } };\n}\n\n/**\n * A RE-WORDED CHOICE KEEPS ITS LOOK (lane CHOICE-COLUMN-EDIT). The colour is kept on the Field by\n * the choice's WORDS, so re-wording \"Cusor\" to \"Cursor\" in place left the colour on words no choice\n * has any more. `renames` is old words → new words; the look (the one being saved, else the one the\n * Field holds) follows each re-worded choice. Null when there is nothing to carry.\n */\nexport function lookFollowsRenames(\n field: Field,\n look: { id: string; options: Record<string, unknown> } | null,\n renames: ReadonlyMap<string, string>,\n): { id: string; options: Record<string, unknown> } | null {\n if (renames.size === 0) return look;\n const base = look ?? displayFormatOf(field);\n const choices = base && Array.isArray(base.options[\"choices\"]) ? (base.options[\"choices\"] as Array<Record<string, unknown>>) : null;\n if (!base || !choices) return look;\n let moved = false;\n const next = choices.map((c) => {\n const was = typeof c[\"value\"] === \"string\" ? c[\"value\"] : null;\n const now = was === null ? undefined : [...renames].find(([old]) => choiceWord(old) === choiceWord(was))?.[1];\n if (now === undefined) return c;\n moved = true;\n return { ...c, value: now };\n });\n if (!moved) return look;\n return { id: base.id, options: { ...base.options, choices: next } };\n}\n\n/**\n * THE LOOK A SAVE SENDS FOR AN EXISTING CHOICE COLUMN, from the ONE choice editor's rows\n * (`ChoiceListEditor` — each row carries its colour; lane VIEWS-AND-FIELDS W1-B). The colours\n * are kept by WORDS, so the rows are compared under the words the store held (`start`), then the\n * look follows each re-worded choice (`lookFollowsRenames`). A colour kept for a choice that was\n * removed, or for words no option has, stays — a save never drops a colour nobody touched.\n * Null: nothing about the look changed.\n */\nexport function choiceLookFromList(\n field: Field,\n start: readonly ChoiceListRow[],\n rows: readonly ChoiceListRow[],\n): { id: string; options: Record<string, unknown> } | null {\n const base = startingChoiceColors(field, start.map((r) => r.words.trim()).filter((w) => w !== \"\"));\n const colorRows: ChoiceColorRow[] = base.map((row) => {\n const was = start.find((r) => choiceWord(r.words) === choiceWord(row.value));\n const now = was?.id ? rows.find((r) => r.id === was.id) : undefined;\n return now ? { value: row.value, color: now.color ?? null } : row;\n });\n for (const r of rows) {\n if (r.id !== null || r.words.trim() === \"\") continue;\n if (colorRows.some((c) => choiceWord(c.value) === choiceWord(r.words))) continue;\n colorRows.push({ value: r.words.trim(), color: r.color ?? null });\n }\n const renames = new Map<string, string>();\n for (const was of start) {\n const now = was.id ? rows.find((r) => r.id === was.id) : undefined;\n if (now && now.words.trim() !== \"\" && now.words.trim() !== was.words.trim()) renames.set(was.words.trim(), now.words.trim());\n }\n return lookFollowsRenames(field, choiceDisplayPatch(field, colorRows), renames);\n}\n\n/** THE LOOK A NEW CHOICE COLUMN IS MADE WITH: its rows' colours, or null when none wears one. */\nexport function choiceLookForNewList(\n multi: boolean,\n rows: readonly ChoiceListRow[],\n): { id: string; options: { choices: Array<{ value: string; color: StyleColor }> } } | null {\n const choices = rows.flatMap((r) => (r.words.trim() !== \"\" && r.color ? [{ value: r.words.trim(), color: r.color }] : []));\n return choices.length === 0 ? null : { id: multi ? \"multi_choice\" : \"choice\", options: { choices } };\n}\n\n// \"Shows as\" for a plain column lives in `FieldFormatPicker.tsx` (merge tranche 6e): the whole\n// registry, grouped, with \"Other kinds\".\n","\"use client\";\n\n// src/ChoiceListEditor.tsx — @ai-matrx/records-ui\n//\n// THE CHOICES OF AN EXISTING CHOICE COLUMN, ONE ROW EACH (lane CHOICE-COLUMN-EDIT, 2026-09-27).\n//\n// A software team's \"Account Type\" column offers Cusor · Claude · Codex, and \"Cusor\" is a typo.\n// The panel used to hand them an empty \"one per line\" box: fixing one letter meant retyping the\n// whole list, and a re-typed word was a NEW choice, so every cell holding the old one kept the\n// typo. Here each choice is its own row, read from the store in its own order\n// (`metadata.option_position`): its words are edited IN PLACE (the choice keeps its key, so every\n// cell holding it reads the new words), a choice can be added, removed (retired, never deleted —\n// cells holding it keep it) and moved up or down. Save sends the whole list, in order, in the\n// panel's one `fieldUpdate` call: `{id, words}` for a choice that was there, plain words for a new\n// one (`FieldPatch.options`). The same list for a table that was moved and one that was not.\n//\n// ONE EDITOR, WITH ITS COLOURS (lane VIEWS-AND-FIELDS W1-B, 2026-10-02 — Airtable). Add column used\n// to take choices in a one-per-line box and the colours only appeared later, in a second \"Choice\n// colours\" block of the column's settings. Each row now carries its own swatch (the colour kept on\n// the Field, `display_format.options.choices`, `choiceLooks.ts`), a new choice takes the next\n// palette colour by itself, and the SAME component serves a new column (no `field`: the rows live\n// in the panel) and an existing one (rows read from the store).\n\nimport { useEffect, useRef, useState, type KeyboardEvent } from \"react\";\nimport type { ChoiceRehome, ChoiceUsage, Field, FieldOptionEdit, StoredRecord } from \"@ai-matrx/records\";\nimport { optionLabel, recordsUseSentence, rehomeSentence } from \"@ai-matrx/records\";\nimport { useRecordsClient } from \"@ai-matrx/records/react\";\nimport {\n BasicInput,\n Button,\n Label,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n cn,\n} from \"@ai-matrx/design-system\";\nimport { STYLE_COLORS, STYLE_COLOR_LABELS, SWATCH_CLASS, type StyleColor } from \"@ai-matrx/design-system/data-table\";\nimport { nextChoiceColor, storedChoiceColor } from \"./choiceLooks\";\nimport { inTheStoresOrder } from \"./editors\";\nimport { refusalSentence } from \"./plainWords\";\n\n/** One row of the list: a choice that was there (`id`) or one being added (`id: null`). */\nexport interface ChoiceListRow {\n /** The option record's id, or null for a choice this panel is adding. */\n id: string | null;\n /** What it reads as. */\n words: string;\n /** A stable React key for a row that has no id yet. */\n row: string;\n /** The colour it wears (`display_format.options.choices`); null or absent: none. */\n color?: StyleColor | null | undefined;\n}\n\nlet rowSeed = 0;\nconst nextRow = () => `new-${(rowSeed += 1)}`;\n\n/** The rows a column's live options start as, in the store's order, each in the colour its Field keeps. */\nexport function choiceRowsFrom(options: readonly StoredRecord[], field?: Field): ChoiceListRow[] {\n return inTheStoresOrder([...options]).map((option) => {\n const words = optionLabel(option);\n const key = (option.data as { key?: unknown } | null | undefined)?.key;\n const color = field ? (storedChoiceColor(field, words) ?? storedChoiceColor(field, key)) : undefined;\n return { id: option.id, words, row: option.id, color: color ?? null };\n });\n}\n\n/** A new, empty row, already wearing the next palette colour the list does not wear (Airtable). */\nexport function newChoiceRow(rows: readonly ChoiceListRow[], words = \"\"): ChoiceListRow {\n return { id: null, words, row: nextRow(), color: nextChoiceColor(rows.map((r) => r.color)) };\n}\n\n/**\n * WHAT A SAVE SENDS as `options`, or `undefined` when the list is what the store already holds\n * (so a rename of the column alone does not rewrite its choices).\n */\nexport function choiceListPatch(\n start: readonly ChoiceListRow[],\n rows: readonly ChoiceListRow[],\n): Array<string | FieldOptionEdit> | undefined {\n const kept = rows.filter((r) => r.words.trim() !== \"\");\n const same =\n kept.length === start.length && kept.every((r, i) => r.id === start[i]!.id && r.words.trim() === start[i]!.words.trim());\n if (same) return undefined;\n return kept.map((r) => (r.id ? { id: r.id, words: r.words.trim() } : r.words.trim()));\n}\n\n/** Why this list cannot be saved yet, in the panel's words, or null. */\nexport function whatTheChoiceListIsMissing(rows: readonly ChoiceListRow[] | null): string | null {\n if (!rows) return null;\n const words = rows.map((r) => r.words.trim()).filter((w) => w !== \"\");\n // A choice column with no choices yet is still a choice column (lane CHOICE-COLUMN-EDIT b): its\n // first choice is added here later, or from a cell, which asks before adding what was typed.\n if (words.length === 0) return null;\n const seen = new Set<string>();\n for (const word of words) {\n const low = word.toLowerCase();\n if (seen.has(low)) return `“${word}” is in the list twice. Each choice needs its own words.`;\n seen.add(low);\n }\n return null;\n}\n\nexport function ChoiceListEditor({\n field,\n isNew = false,\n rows,\n onRows,\n onStart,\n allowOther = false,\n rehome = {},\n onRehome,\n}: {\n /** The column, when it exists. Absent: a column being made, whose rows the panel holds. */\n field?: Field | undefined;\n /** A column being made: no store read, no removal question. */\n isNew?: boolean | undefined;\n rows: ChoiceListRow[] | null;\n onRows: (next: ChoiceListRow[]) => void;\n /** The list as the store answered it, once — what a save is compared against. */\n onStart?: ((start: ChoiceListRow[]) => void) | undefined;\n /** Whether the column takes other values — the only case \"keep the words\" is offered. */\n allowOther?: boolean | undefined;\n /**\n * REMOVING A CHOICE RECORDS STILL HOLD (lane CHOICE-TAILS): where the records of each removed\n * choice go, keyed by the option's id — sent in the same save as the list. Without `onRehome`\n * a removal is immediate and its records keep the retired choice, as before.\n */\n rehome?: Record<string, ChoiceRehome> | undefined;\n onRehome?: ((next: Record<string, ChoiceRehome>) => void) | undefined;\n}) {\n const client = useRecordsClient();\n const [refused, setRefused] = useState<string | null>(null);\n const [usage, setUsage] = useState<Record<string, ChoiceUsage> | null>(null);\n const [asking, setAsking] = useState<ChoiceListRow | null>(null);\n const [moveTo, setMoveTo] = useState(\"\");\n const focusRow = useRef<string | null>(null);\n const [removed, setRemoved] = useState<Record<string, { row: ChoiceListRow; index: number }>>({});\n const fieldId = field?.id ?? null;\n useEffect(() => {\n if (rows !== null || !fieldId || !field) return;\n let live = true;\n void client.fieldOptions({ field_id: fieldId }).then((got) => {\n if (!live) return;\n if (!got.ok) {\n setRefused(refusalSentence(got.error));\n return;\n }\n const start = choiceRowsFrom(got.data ?? [], field);\n onStart?.(start);\n onRows(start);\n });\n return () => {\n live = false;\n };\n // `field` is read for its colours once, with the options; its id is what re-asks.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, fieldId, rows, onRows, onStart]);\n // HOW MANY RECORDS HOLD EACH CHOICE, read once. Unreadable, nothing is asked and a removal\n // behaves as it always has (its records keep the retired choice) — never a guessed count.\n useEffect(() => {\n if (!onRehome || !fieldId) return;\n let live = true;\n // A door that throws (not just refuses) is the same answer: unread, nothing asked.\n void client.fieldChoiceUsage({ field_id: fieldId }).then(\n (got) => {\n if (live && got.ok) setUsage(got.data);\n },\n () => undefined,\n );\n return () => {\n live = false;\n };\n }, [client, fieldId, onRehome]);\n\n if (refused) {\n return (\n <p className=\"text-[11px] text-muted-foreground\" data-records-choice-list=\"\">\n The choices could not be read, so they are left as they are: {refused}\n </p>\n );\n }\n if (rows === null) return <p className=\"text-[11px] text-muted-foreground\">Reading this column’s choices…</p>;\n\n const set = (index: number, words: string) => onRows(rows.map((r, i) => (i === index ? { ...r, words } : r)));\n const paint = (index: number, color: StyleColor | null) => onRows(rows.map((r, i) => (i === index ? { ...r, color } : r)));\n // THE BOX A PERSON ASKED FOR TAKES FOCUS, THE FIRST ONE TOO. A row the panel starts with (a new\n // column opens on one empty row) must not steal focus from the name box, so focus follows the\n // row `addRow` made — by its key — rather than a guess from the row's place in the list.\n const addRow = () => {\n const made = newChoiceRow(rows);\n focusRow.current = made.row;\n onRows([...rows, made]);\n };\n // ENTER IN THE LAST CHOICE STARTS THE NEXT ONE (Airtable): a list is typed without the mouse.\n const enterAdds = (index: number) => (e: KeyboardEvent<HTMLInputElement>) => {\n if (e.key !== \"Enter\" || e.nativeEvent.isComposing) return;\n e.preventDefault();\n if (rows[index]!.words.trim() === \"\") return;\n if (index === rows.length - 1) {\n addRow();\n return;\n }\n // A choice in the middle of the list: Enter moves on to the next box.\n const next = (e.currentTarget.closest(\"li\")?.nextElementSibling as HTMLElement | null)?.querySelector(\"input\");\n next?.focus();\n };\n const move = (index: number, by: -1 | 1) => {\n const to = index + by;\n if (to < 0 || to >= rows.length) return;\n const next = [...rows];\n [next[index], next[to]] = [next[to]!, next[index]!];\n onRows(next);\n };\n const named = (r: ChoiceListRow, i: number) => (r.words.trim() === \"\" ? `choice ${i + 1}` : `“${r.words.trim()}”`);\n const heldBy = (r: ChoiceListRow) => (r.id && onRehome ? (usage?.[r.id]?.records ?? 0) : 0);\n const remove = (i: number) => {\n const r = rows[i]!;\n if (heldBy(r) > 0) {\n setAsking(r);\n setMoveTo(\"\");\n return;\n }\n onRows(rows.filter((_, j) => j !== i));\n };\n const answer = (spec: ChoiceRehome) => {\n if (!asking?.id || !onRehome) return;\n const index = rows.findIndex((r) => r.id === asking.id);\n setRemoved({ ...removed, [asking.id]: { row: asking, index: index < 0 ? rows.length : index } });\n onRows(rows.filter((r) => r.id !== asking.id));\n onRehome({ ...rehome, [asking.id]: spec });\n setAsking(null);\n };\n const putBack = (id: string) => {\n const was = removed[id];\n if (!was || !onRehome) return;\n const next = [...rows];\n next.splice(Math.min(was.index, next.length), 0, was.row);\n onRows(next);\n const { [id]: _gone, ...rest } = rehome;\n onRehome(rest);\n const { [id]: _was, ...keep } = removed;\n setRemoved(keep);\n };\n const targets = rows.filter((r) => r.id && r.id !== asking?.id && r.words.trim() !== \"\");\n const wordsOf = (id: string) => rows.find((r) => r.id === id)?.words.trim() ?? usage?.[id]?.words ?? \"\";\n\n return (\n <div className=\"flex flex-col gap-1\" data-records-choice-list=\"\">\n <Label className=\"text-xs\">The choices</Label>\n {rows.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\" data-records-choice-list-empty=\"\">\n No choices yet.\n </p>\n ) : null}\n <ul className=\"flex flex-col gap-1\">\n {rows.map((r, i) => (\n <li key={r.row} className=\"flex items-center gap-1\" data-records-choice-row=\"\">\n <ChoiceSwatch words={r.words.trim() === \"\" ? `choice ${i + 1}` : r.words.trim()} color={r.color ?? null} onColor={(c) => paint(i, c)} />\n <BasicInput\n value={r.words}\n aria-label={`Choice ${i + 1}`}\n className=\"h-7 min-w-0 flex-1 text-xs\"\n ref={(box) => {\n if (box && focusRow.current === r.row) {\n focusRow.current = null;\n box.focus();\n }\n }}\n onChange={(e) => set(i, e.target.value)}\n onKeyDown={enterAdds(i)}\n />\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-7 px-1.5 text-xs\" aria-label={`Move ${named(r, i)} up`} disabled={i === 0} onClick={() => move(i, -1)}>\n ↑\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-7 px-1.5 text-xs\" aria-label={`Move ${named(r, i)} down`} disabled={i === rows.length - 1} onClick={() => move(i, 1)}>\n ↓\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-7 px-1.5 text-xs\" aria-label={`Remove ${named(r, i)}`} onClick={() => remove(i)}>\n ×\n </Button>\n </li>\n ))}\n </ul>\n {asking ? (\n // THE QUESTION, Notion-style: where do the records that hold it go?\n <div\n role=\"group\"\n aria-label={recordsUseSentence(heldBy(asking), asking.words.trim())}\n data-records-choice-removal-ask=\"\"\n className=\"flex flex-col gap-1 rounded border bg-muted/40 p-2\"\n >\n <p className=\"text-xs\">{recordsUseSentence(heldBy(asking), asking.words.trim())}</p>\n <div className=\"flex flex-wrap items-center gap-1\">\n {targets.length > 0 ? (\n <>\n <Button type=\"button\" size=\"sm\" className=\"h-7 px-2 text-xs\" disabled={moveTo === \"\"} onClick={() => answer({ then: \"move\", to: moveTo })}>\n Move them to\n </Button>\n <Select value={moveTo} onValueChange={setMoveTo}>\n <SelectTrigger size=\"sm\" className=\"h-7 w-36 text-xs\" aria-label=\"Another choice\">\n <SelectValue placeholder=\"Another choice\" />\n </SelectTrigger>\n <SelectContent>\n {targets.map((r) => (\n <SelectItem key={r.id!} value={r.id!}>\n {r.words.trim()}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </>\n ) : null}\n {allowOther ? (\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-7 px-2 text-xs\" onClick={() => answer({ then: \"keep\" })}>\n Keep the words as other values\n </Button>\n ) : null}\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-7 px-2 text-xs\" onClick={() => answer({ then: \"clear\" })}>\n Clear them\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-7 px-2 text-xs\" onClick={() => setAsking(null)}>\n Cancel\n </Button>\n </div>\n </div>\n ) : null}\n {Object.entries(rehome).map(([id, spec]) =>\n removed[id] ? (\n <div key={id} className=\"flex items-center justify-between gap-2 text-[11px] text-muted-foreground\" data-records-choice-rehome=\"\">\n <span>{rehomeSentence(usage?.[id]?.records ?? 0, removed[id]!.row.words.trim(), spec, spec.then === \"move\" ? wordsOf(spec.to) : undefined)}</span>\n <Button type=\"button\" size=\"sm\" variant=\"ghost\" className=\"h-6 px-1.5 text-[11px]\" onClick={() => putBack(id)}>\n Put it back\n </Button>\n </div>\n ) : null,\n )}\n <Button type=\"button\" size=\"sm\" variant=\"outline\" className=\"h-7 self-start text-xs\" onClick={addRow}>\n Add a choice\n </Button>\n {isNew ? null : (\n <p className=\"text-[11px] text-muted-foreground\">\n Changing a choice’s words changes them in every record that holds it. Removing a choice that records hold\n asks where those records go.\n </p>\n )}\n </div>\n );\n}\n\n/**\n * ONE CHOICE'S COLOUR: a dot in the colour it wears that opens the palette (Airtable). Every\n * colour is a name from the design-system palette (`STYLE_COLORS`), never a raw hex.\n */\nfunction ChoiceSwatch({ words, color, onColor }: { words: string; color: StyleColor | null; onColor: (color: StyleColor | null) => void }) {\n const [open, setOpen] = useState(false);\n const pick = (next: StyleColor | null) => {\n onColor(next);\n setOpen(false);\n };\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Colour for ${words}: ${color ? STYLE_COLOR_LABELS[color] : \"none\"}`}\n title={color ? STYLE_COLOR_LABELS[color] : \"No colour\"}\n data-records-choice-swatch={color ?? \"none\"}\n className={cn(\n \"h-4 w-4 shrink-0 rounded-full\",\n color ? SWATCH_CLASS[color] : \"border border-border bg-background\",\n )}\n />\n </PopoverTrigger>\n <PopoverContent sizing=\"content\" align=\"start\" className=\"p-2\">\n <div className=\"flex items-center gap-1\" role=\"radiogroup\" aria-label={`Colour for ${words}`}>\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={color === null}\n aria-label=\"No colour\"\n title=\"No colour\"\n onClick={() => pick(null)}\n className={cn(\"h-5 w-5 rounded-full border border-border bg-background\", color === null && \"ring-2 ring-ring ring-offset-1\")}\n />\n {STYLE_COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n role=\"radio\"\n aria-checked={color === c}\n aria-label={STYLE_COLOR_LABELS[c]}\n title={STYLE_COLOR_LABELS[c]}\n data-records-choice-color={`${words}:${c}`}\n onClick={() => pick(c)}\n className={cn(\"h-5 w-5 rounded-full\", SWATCH_CLASS[c], color === c && \"ring-2 ring-ring ring-offset-1\")}\n />\n ))}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\n// src/NewerKindQuestions.tsx — @ai-matrx/records-ui\n//\n// WHAT THE COLUMN PANEL ASKS ABOUT THREE OF THE NEWER KINDS (lane 10 P4). Airtable asks a rating\n// how many stars it goes to; Notion's Status asks which group each option sits in; a barcode may\n// name the code it holds. Each answer goes to the store as a word it judges\n// (`custom._field_document_for` / `custom.field_update`): `max`, `status_groups`, `symbology`.\n\nimport {\n BARCODE_SYMBOLOGIES,\n STATUS_GROUPS,\n STATUS_GROUP_WORDS,\n statusGroupOf,\n type Field,\n type FieldRule,\n type StatusGroup,\n} from \"@ai-matrx/records\";\nimport { Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@ai-matrx/design-system\";\nimport { STATUS_GROUP_MARK } from \"./newerKindValues\";\n\n/** A new Status column starts with Notion's three, one in each group. */\nexport const STATUS_STARTING_CHOICES: ReadonlyArray<{ words: string; group: StatusGroup }> = [\n { words: \"Not started\", group: \"todo\" },\n { words: \"In progress\", group: \"in_progress\" },\n { words: \"Done\", group: \"done\" },\n];\n\n/** The group a choice's words most plainly name; anything else starts as To do. */\nexport function guessStatusGroup(words: string): StatusGroup {\n const w = words.toLowerCase().replace(/[^a-z]/g, \"\");\n if ([\"done\", \"complete\", \"completed\", \"closed\", \"finished\", \"discharged\", \"cancelled\", \"canceled\"].includes(w)) return \"done\";\n if ([\"inprogress\", \"doing\", \"started\", \"active\", \"inreview\", \"review\"].includes(w)) return \"in_progress\";\n return \"todo\";\n}\n\n/** One choice's row in the groups question: how the store names it, its words, its group. */\nexport type StatusGroupRow = { ref: string; words: string; group: StatusGroup };\n\n/**\n * Each choice's group, for the choices this panel is showing (V8 #3). A choice the column already\n * keeps is named by its OPTION ID — the store keys groups by the choice's stored key, which a\n * rename never changes, and reads the group from there; a choice being added is named by its words.\n * `changed` holds only what the person picked here, by the same name.\n */\nexport function statusGroupRows(\n field: Field | undefined,\n rows: ReadonlyArray<{ id: string | null; words: string }>,\n keyOfId: Readonly<Record<string, string>>,\n changed: Readonly<Record<string, StatusGroup>>,\n): StatusGroupRow[] {\n const out: StatusGroupRow[] = [];\n for (const r of rows) {\n const words = r.words.trim();\n if (words === \"\") continue;\n const ref = r.id ?? words;\n const key = r.id ? keyOfId[r.id] : undefined;\n const held = field && key ? statusGroupOf(field, key) : undefined;\n out.push({ ref, words, group: changed[ref] ?? held ?? guessStatusGroup(words) });\n }\n return out;\n}\n\nexport function StatusGroupsQuestion({\n rows,\n onGroup,\n}: {\n rows: readonly StatusGroupRow[];\n onGroup: (ref: string, next: StatusGroup) => void;\n}) {\n if (rows.length === 0) return null;\n return (\n <div className=\"flex flex-col gap-1\" data-records-status-groups=\"\">\n <Label className=\"text-xs\">Groups</Label>\n {rows.map((r) => (\n <div key={r.ref} className=\"flex items-center gap-2\">\n <span className=\"min-w-0 flex-1 truncate text-sm\">{r.words}</span>\n <Select value={r.group} onValueChange={(next) => onGroup(r.ref, next as StatusGroup)}>\n <SelectTrigger size=\"sm\" className=\"w-36\" aria-label={`Group for ${r.words}`}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {STATUS_GROUPS.map((g) => (\n <SelectItem key={g} value={g}>\n {STATUS_GROUP_MARK[g]} {STATUS_GROUP_WORDS[g]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ))}\n </div>\n );\n}\n\n/** A rating's top star, 1 to 10. */\nexport function RatingMaxQuestion({ value, onChange }: { value: number; onChange: (next: number) => void }) {\n return (\n <label className=\"flex max-w-[16rem] flex-col gap-1\">\n <Label className=\"text-xs\">Out of</Label>\n <Select value={String(value)} onValueChange={(next) => onChange(Number(next))}>\n <SelectTrigger size=\"sm\" aria-label=\"Out of\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Array.from({ length: 10 }, (_, i) => i + 1).map((n) => (\n <SelectItem key={n} value={String(n)}>\n {n} {n === 1 ? \"star\" : \"stars\"}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n );\n}\n\n/** The rules with a rating's 0..max in place of whatever min and max they held. */\nexport function rulesWithRatingMax(rules: readonly FieldRule[], max: number): FieldRule[] {\n return [\n ...rules.filter((r) => r.kind !== \"min\" && r.kind !== \"max\"),\n { kind: \"min\", value: 0 } as FieldRule,\n { kind: \"max\", value: max } as FieldRule,\n ];\n}\n\nconst SYMBOLOGY_WORDS: Record<(typeof BARCODE_SYMBOLOGIES)[number], string> = {\n code128: \"Code 128\",\n code39: \"Code 39\",\n ean13: \"EAN-13\",\n ean8: \"EAN-8\",\n upc_a: \"UPC-A\",\n upc_e: \"UPC-E\",\n itf: \"ITF\",\n qr: \"QR code\",\n data_matrix: \"Data Matrix\",\n pdf417: \"PDF417\",\n};\n\n/** Which code a barcode holds; \"Any code\" takes whatever a scanner reads. */\nexport function BarcodeSymbologyQuestion({ value, onChange }: { value: string; onChange: (next: string) => void }) {\n return (\n <label className=\"flex max-w-[16rem] flex-col gap-1\">\n <Label className=\"text-xs\">Code type</Label>\n <Select value={value === \"\" ? \"any\" : value} onValueChange={(next) => onChange(next === \"any\" ? \"\" : next)}>\n <SelectTrigger size=\"sm\" aria-label=\"Code type\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"any\">Any code</SelectItem>\n {BARCODE_SYMBOLOGIES.map((s) => (\n <SelectItem key={s} value={s}>\n {SYMBOLOGY_WORDS[s]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </label>\n );\n}\n","\"use client\";\n\n// src/FieldFormatPicker.tsx — @ai-matrx/records-ui · merge tranche 6e (formats)\n//\n// \"SHOWS AS\" — THE WHOLE PLATFORM REGISTRY, GROUPED THE WAY THE OLDER /data GRID GROUPED IT\n// (`lib/field-formats/FieldFormatPicker.tsx`, rewritten onto `Field`). The formats that fit what\n// the column already stores come first, in the registry's own groups (Text, Numbers, Dates,\n// Choice, Structured); then \"Other kinds · changes what the column stores\" — every other kind of\n// data a person thinks in (a Time on a date column, Attachments on a text column), which retypes\n// the column and sets its look in the SAME `custom.field_update`. Never offered: the two raw\n// structural formats (JSON, a raw list) and the worked-out ones (a formula, a record number, the\n// stamps), which are made as columns of their own, not chosen as a look.\n//\n// Each format's own options follow it — currency, how a percent is kept (45 or 0.45: read from\n// the Field, never guessed), decimals, the unit of a duration, what a rating is out of, a date's\n// style, a prefix or suffix, thousands separators — and nothing else.\n//\n// Every pick is the package's own `PickOne` (never a native <select> — lane VIEWS-AND-FIELDS W1-B):\n// the long \"Shows as\" list is searchable, each format named with its group.\n\nimport type { ReactNode } from \"react\";\nimport type { Field } from \"@ai-matrx/records\";\nimport { Label } from \"@ai-matrx/design-system\";\nimport {\n FIELD_FORMAT_LIST,\n getFieldFormat,\n groupedFormatsForBase,\n type FieldFormatConfig,\n type FieldFormatDef,\n type FieldFormatOptions,\n} from \"@ai-matrx/design-system/field-formats\";\nimport { PickOne } from \"./PickOne\";\n\nimport { displayFormatOf } from \"./choiceLooks\";\nimport { editorKindFor } from \"./parity\";\n\n/** What the picker holds: the look, and — for an Other kind — the store's word for what the column becomes. */\nexport interface FormatChoice {\n format: FieldFormatConfig | null;\n /** `custom.field_update`'s `type` word when this choice retypes the column; null when it does not. */\n retype: string | null;\n}\n\n/** A format that makes a column a different KIND of thing in the store (a list, a link, a person, files). */\nconst KIND_WORD: Partial<Record<string, string>> = {\n choice: \"select\",\n multi_choice: \"multi_select\",\n tags: \"multi_select\",\n relation: \"relation\",\n person: \"member\",\n attachment: \"attachment\",\n};\n\n/** A plain column's storage → the store's plain kind word. */\nconst PLAIN_WORD: Partial<Record<string, string>> = {\n string: \"text\",\n number: \"number\",\n integer: \"number\",\n boolean: \"checkbox\",\n date: \"datetime\",\n datetime: \"datetime\",\n};\n\n/** What an Other kind makes the column hold, in a person's words. */\nfunction storesWord(def: FieldFormatDef): string {\n if (KIND_WORD[def.id]) return def.label;\n return BASE_WORDS[def.base] ?? def.base;\n}\n\nconst BASE_WORDS: Record<string, string> = {\n string: \"Text\",\n number: \"Number\",\n integer: \"Whole number\",\n boolean: \"Yes / no\",\n date: \"Date\",\n datetime: \"Date & time\",\n array: \"List\",\n};\n\n/** Never chosen as a look: made as a column of their own, or raw structure. */\nfunction neverALook(def: FieldFormatDef): boolean {\n return def.editor === \"computed\" || def.id === \"json\" || def.id === \"array\";\n}\n\n/**\n * THE STORAGE A COLUMN'S VALUES HAVE, for the list of formats that fit it — `formula` for a\n * worked-out column (its result can wear any plain look, and it is never retyped here), `null`\n * for a column whose value the record renderer draws itself (a list, a link, a person, files).\n */\nexport function storageOf(field: Field): string | null {\n switch (String(editorKindFor(field))) {\n case \"text\":\n case \"long_text\":\n case \"email\":\n case \"url\":\n case \"phone\":\n return \"string\";\n case \"number\":\n case \"currency\":\n case \"percent\":\n case \"rating\":\n return \"number\";\n case \"checkbox\":\n case \"boolean\":\n return \"boolean\";\n case \"datetime\":\n return String(field.config?.[\"kind\"] ?? \"\") === \"date\" ? \"date\" : \"datetime\";\n case \"formula\":\n return \"formula\";\n default:\n return null;\n }\n}\n\n/** The formats offered for this column: its own, grouped, and the Other kinds (each with its retype word). */\nexport function formatMenu(field: Field): {\n groups: Array<{ group: string; formats: FieldFormatDef[] }>;\n otherKinds: Array<{ def: FieldFormatDef; word: string }>;\n} {\n const base = storageOf(field);\n if (base === null) return { groups: [], otherKinds: [] };\n if (base === \"formula\") {\n const groups: Array<{ group: string; formats: FieldFormatDef[] }> = [];\n for (const def of FIELD_FORMAT_LIST) {\n if (neverALook(def) || KIND_WORD[def.id] || def.id === \"boolean\") continue;\n const bucket = groups.find((g) => g.group === def.group);\n if (bucket) bucket.formats.push(def);\n else groups.push({ group: def.group, formats: [def] });\n }\n return { groups, otherKinds: [] };\n }\n const groups = groupedFormatsForBase(base)\n .map((g) => ({ group: g.group as string, formats: g.formats.filter((d) => !neverALook(d) && !KIND_WORD[d.id]) }))\n .filter((g) => g.formats.length > 0);\n const own = new Set(groups.flatMap((g) => g.formats.map((d) => d.id as string)));\n const otherKinds: Array<{ def: FieldFormatDef; word: string }> = [];\n for (const def of FIELD_FORMAT_LIST) {\n if (own.has(def.id) || neverALook(def)) continue;\n const word = KIND_WORD[def.id] ?? PLAIN_WORD[def.base];\n if (word) otherKinds.push({ def, word });\n }\n return { groups, otherKinds };\n}\n\n/** What the picker opens on: the look the Field keeps. */\nexport function startingChoice(field: Field): FormatChoice {\n const held = displayFormatOf(field);\n if (!held || !getFieldFormat(held.id) || held.id === \"formula\") return { format: null, retype: null };\n return {\n format: Object.keys(held.options).length > 0 ? ({ id: held.id, options: held.options } as FieldFormatConfig) : ({ id: held.id } as FieldFormatConfig),\n retype: null,\n };\n}\n\nfunction sameLook(a: FieldFormatConfig | null, b: FieldFormatConfig | null): boolean {\n const norm = (c: FieldFormatConfig | null) =>\n c ? JSON.stringify([c.id, Object.entries(c.options ?? {}).sort(([x], [y]) => x.localeCompare(y))]) : \"\";\n return norm(a) === norm(b);\n}\n\n/**\n * THE KEYS A SAVE SENDS for this choice, or `undefined` when nothing changed. The look travels as\n * `display_format` (null clears it); an Other kind adds its `type` word beside it.\n */\nexport function formatPatch(field: Field, choice: FormatChoice): Record<string, unknown> | undefined {\n const before = startingChoice(field).format;\n if (!choice.retype && sameLook(before, choice.format)) return undefined;\n const display = choice.format\n ? { id: choice.format.id, ...(choice.format.options && Object.keys(choice.format.options).length > 0 ? { options: choice.format.options } : {}) }\n : null;\n return {\n ...(choice.retype ? { type: choice.retype } : {}),\n ...(choice.retype === \"multi_select\" && choice.format?.id === \"tags\" ? { allow_other: true } : {}),\n display_format: display,\n };\n}\n\nconst CURRENCIES = [\"USD\", \"EUR\", \"GBP\", \"CAD\", \"AUD\", \"JPY\", \"CHF\", \"CNY\", \"INR\", \"MXN\", \"BRL\"];\nconst SELECT = \"h-8 w-full\";\nconst BOX = \"h-8 w-full rounded border bg-background px-2 text-xs\";\n\n/** THE PICKER. `value` is controlled; the caller sends `formatPatch` with its save. */\nexport function FieldFormatPicker({\n field,\n value,\n onValue,\n}: {\n field: Field;\n value: FormatChoice;\n onValue: (next: FormatChoice) => void;\n}) {\n const { groups, otherKinds } = formatMenu(field);\n if (groups.length === 0 && otherKinds.length === 0) return null;\n const active = value.format ? getFieldFormat(value.format.id) : null;\n const options: FieldFormatOptions = value.format?.options ?? {};\n const optionKeys = active?.optionKeys ?? [];\n const retypedTo = value.retype ? otherKinds.find((k) => k.def.id === value.format?.id) : undefined;\n\n const setOption = <K extends keyof FieldFormatOptions>(key: K, next: FieldFormatOptions[K] | undefined) => {\n if (!value.format) return;\n const merged: FieldFormatOptions = { ...options };\n if (next === undefined || (next as unknown) === \"\" || (typeof next === \"number\" && !Number.isFinite(next))) delete merged[key];\n else merged[key] = next as FieldFormatOptions[K];\n onValue({ ...value, format: Object.keys(merged).length > 0 ? { id: value.format.id, options: merged } : { id: value.format.id } });\n };\n\n const option = (key: keyof FieldFormatOptions, label: string, control: ReactNode) =>\n optionKeys.includes(key) ? (\n <label key={key} className=\"flex min-w-[6rem] flex-col gap-0.5 text-[11px] text-muted-foreground\">\n {label}\n {control}\n </label>\n ) : null;\n\n return (\n <div className=\"flex flex-col gap-1\" data-records-format-picker=\"\">\n <Label className=\"text-xs\" htmlFor={`records-shows-as-${field.id}`}>\n Shows as\n </Label>\n <PickOne\n id={`records-shows-as-${field.id}`}\n label=\"Shows as\"\n className={SELECT}\n value={value.format?.id ?? \"\"}\n onChange={(id) => {\n if (id === \"\") {\n onValue({ format: null, retype: null });\n return;\n }\n const other = otherKinds.find((k) => k.def.id === id);\n onValue({ format: { id: id as FieldFormatConfig[\"id\"] }, retype: other ? other.word : null });\n }}\n options={[\n { value: \"\", label: \"As it is stored\" },\n ...groups.flatMap((g) => g.formats.map((d) => ({ value: d.id, label: d.label, group: g.group }))),\n ...otherKinds.map(({ def }) => ({\n value: def.id,\n label: `${def.label} · stores ${storesWord(def)}`,\n group: \"Other kinds · changes what the column stores\",\n })),\n ]}\n />\n <p className=\"text-[11px] text-muted-foreground\">\n {retypedTo\n ? `This changes what the column stores, to ${storesWord(retypedTo.def)}. The store converts each value it can, and says so before it keeps anything it cannot.`\n : active\n ? active.description\n : \"How every value in this column is written, wherever it appears.\"}\n </p>\n {optionKeys.length > 0 ? (\n <div className=\"flex flex-wrap items-end gap-2\">\n {option(\n \"currency\",\n \"Currency\",\n <PickOne\n label=\"Currency\"\n attrs={{ \"data-records-format-option\": \"currency\" }}\n className={SELECT}\n value={options.currency ?? \"USD\"}\n onChange={(picked) => setOption(\"currency\", picked)}\n options={CURRENCIES.map((c) => ({ value: c, label: c }))}\n />,\n )}\n {option(\n \"percentScale\",\n \"Stored as\",\n <PickOne\n label=\"Stored as\"\n attrs={{ \"data-records-format-option\": \"percentScale\" }}\n className={SELECT}\n value={options.percentScale ?? \"whole\"}\n onChange={(picked) => setOption(\"percentScale\", picked as \"whole\" | \"fraction\")}\n options={[\n { value: \"whole\", label: \"45 means 45%\" },\n { value: \"fraction\", label: \"0.45 means 45%\" },\n ]}\n />,\n )}\n {option(\n \"durationUnit\",\n \"Unit\",\n <PickOne\n label=\"Unit\"\n attrs={{ \"data-records-format-option\": \"durationUnit\" }}\n className={SELECT}\n value={options.durationUnit ?? \"seconds\"}\n onChange={(picked) => setOption(\"durationUnit\", picked as NonNullable<FieldFormatOptions[\"durationUnit\"]>)}\n options={[\n { value: \"milliseconds\", label: \"Milliseconds\" },\n { value: \"seconds\", label: \"Seconds\" },\n { value: \"minutes\", label: \"Minutes\" },\n { value: \"hours\", label: \"Hours\" },\n ]}\n />,\n )}\n {option(\n \"precision\",\n \"Decimals\",\n <input\n data-records-format-option=\"precision\"\n type=\"number\"\n min={0}\n max={10}\n placeholder=\"auto\"\n className={BOX}\n value={options.precision ?? \"\"}\n onChange={(e) => setOption(\"precision\", e.target.value === \"\" ? undefined : Number(e.target.value))}\n />,\n )}\n {option(\n \"ratingMax\",\n \"Out of\",\n <input\n data-records-format-option=\"ratingMax\"\n type=\"number\"\n min={1}\n max={10}\n className={BOX}\n value={options.ratingMax ?? 5}\n onChange={(e) => setOption(\"ratingMax\", e.target.value === \"\" ? undefined : Math.max(1, Math.min(10, Number(e.target.value))))}\n />,\n )}\n {option(\n \"dateStyle\",\n \"Style\",\n <PickOne\n label=\"Style\"\n attrs={{ \"data-records-format-option\": \"dateStyle\" }}\n className={SELECT}\n value={options.dateStyle ?? \"medium\"}\n onChange={(picked) => setOption(\"dateStyle\", picked as \"short\" | \"medium\" | \"long\")}\n options={[\n { value: \"short\", label: \"Short\" },\n { value: \"medium\", label: \"Medium\" },\n { value: \"long\", label: \"Long\" },\n ]}\n />,\n )}\n {option(\n \"prefix\",\n \"Prefix\",\n <input data-records-format-option=\"prefix\" className={BOX} value={options.prefix ?? \"\"} onChange={(e) => setOption(\"prefix\", e.target.value)} />,\n )}\n {option(\n \"suffix\",\n \"Suffix\",\n <input data-records-format-option=\"suffix\" className={BOX} placeholder=\"e.g. kg\" value={options.suffix ?? \"\"} onChange={(e) => setOption(\"suffix\", e.target.value)} />,\n )}\n {optionKeys.includes(\"useGrouping\") ? (\n <label className=\"flex items-center gap-1.5 pb-1 text-[11px] text-muted-foreground\">\n <input\n type=\"checkbox\"\n data-records-format-option=\"useGrouping\"\n checked={options.useGrouping !== false}\n onChange={(e) => setOption(\"useGrouping\", e.target.checked)}\n />\n Thousands separators\n </label>\n ) : null}\n </div>\n ) : null}\n </div>\n );\n}\n","// src/archiveWords.ts — @ai-matrx/records-ui · lane V25-UI-FIXES\n//\n// THE ONE ARCHIVE SENTENCE, in this package. Archived custom tables, records and saved views are\n// listed by personal and Organization Trash (lane TRASH-TABLES), so every confirm in front of an\n// archive says the same three facts the app's own confirms say: what happens (it is archived, not\n// destroyed), what the person will notice (it leaves this list), and where it comes back from\n// (the Archived view — platform ruling, 2026-10-03: a store surface never sends a person to \"Trash\").\n// The words are the app's `archiveConfirmSentence` (matrx-frontend\n// `features/trash/archiveCopy.ts`) exactly — one sentence across the platform; this package cannot\n// import the app, so it carries the same function and the test pins the words.\n//\n// Before: the table's confirm said \"The store keeps them for 365 days, so it can still be brought\n// back.\" without saying from where (VERIFIER-25, outside the list), and the record's said \"waits in\n// Archived items\" — true, and silent about Trash.\n\n/**\n * \"This archives the table \"Vendor contracts\". It leaves this list, and you can restore it from Trash.\"\n *\n * `what` is the thing as a person would say it — `the table \"Vendor contracts\"`, `\"Summit Janitorial\"`.\n */\nimport { formatCount } from \"@ai-matrx/kit/format\";\n\nexport function archiveConfirmSentence(what: string): string {\n const subject = what.trim() || \"it\";\n return `This archives ${subject}. It leaves this list, and you can restore it from the Archived view.`;\n}\n\n/** Where a table's archive run is, for {@link tableArchiveSentence}. */\nexport interface TableArchiveState {\n progress: { remaining: number; total: number; archived_total: number; in_progress?: boolean | undefined } | null;\n running: boolean;\n /** The last run ended with records still live (stopped, or a pass refused). */\n interrupted: boolean;\n /** The run ended on a refusal. */\n failed: boolean;\n slowedDown: boolean;\n /** Passes made on this screen since it opened (0 after a reload). */\n passesHere?: number;\n}\n\nconst recordsWord = (n: number) => `${formatCount(n)} record${n === 1 ? \"\" : \"s\"}`;\n\n/**\n * ONE SENTENCE FOR A TABLE'S ARCHIVE RUN (BREAKER-1 B-F13, lane DATA-V2-BASICS-2). The panel used to\n * stack the confirm's count, \"N of M put away so far\" and \"Stopped. …\"; and a reload in the middle of\n * a run showed a fresh button with no word that half the records were already put away. A run the\n * store says is still open (`in_progress`) reads as one to carry on. The rows it has already put\n * away are always named — it never says nothing happened.\n */\nexport function tableArchiveSentence(s: TableArchiveState): string {\n const p = s.progress;\n if (!p) return \"Every record in it goes with it.\";\n const done = p.total - p.remaining;\n const sofar = `${formatCount(done)} of ${recordsWord(p.total)} ${done === 1 ? \"is\" : \"are\"} put away`;\n if (s.running) {\n return `Archiving — ${formatCount(done)} of ${recordsWord(p.total)} put away.${s.slowedDown ? \" The store is busy, so it is taking smaller passes; it will still finish.\" : \"\"}`;\n }\n if (p.in_progress && !s.failed && !(s.passesHere ?? 0)) {\n return `Archiving this table was started and not finished: ${sofar}. Carry on and it picks up where it stopped.`;\n }\n if (s.interrupted && s.failed) return `That pass did not finish: ${sofar} and nothing was lost. Carry on and it picks up where it stopped.`;\n if (s.interrupted) return `Stopped: ${sofar}. Carry on whenever you like; it picks up where it stopped.`;\n return `Its ${recordsWord(p.remaining)} ${p.remaining === 1 ? \"goes\" : \"go\"} with it.`;\n}\n\n/**\n * \"2 rollups on Patients read through this.\" The ONE sentence both link-archive confirms use (the\n * back-link dialog and Column settings' Remove on a link column), so a person is told what else\n * goes \"Source archived\" before the click. Empty when nothing reads through it.\n */\nexport function readersSentence(count: number, tableName: string | null): string {\n if (count <= 0) return \"\";\n const rollups = count === 1 ? \"1 rollup\" : `${count} rollups`;\n return `${rollups} on ${tableName ?? \"this table\"} read through this.`;\n}\n","// src/gridMenus.ts — @ai-matrx/records-ui · merge tranches 6a + 6b\n//\n// THE OLDER /data GRID'S MENUS, REWRITTEN ONTO `Field`.\n//\n// Two menus a spreadsheet person reaches for without thinking: the column header's own menu\n// (rename, insert a column beside it, hide, delete, its settings, use it as the row label) and\n// the right-click menu, which is four menus decided by where the pointer was — the cell, its row,\n// its column, the table (`@ai-matrx/design-system/data-table` `menu-targets.ts`). The /data grid\n// had both (`components/user-generated-table-data/ColumnHeaderMenu.tsx`,\n// `features/data-tables/grid-context-menu.ts`); this is the same vocabulary — the same section\n// titles, the same verbs, a disabled item that SAYS WHY — built from the store's own Field records\n// and aimed at the grid's own data paths, never at a second write path.\n//\n// Pure: no React, no store. Every \"do\" is a function the grid hands in, so the builders can be\n// asserted item by item and the grid decides what each press reaches.\n\nimport type { Field } from \"@ai-matrx/records\";\nimport type { MatrxTableMenuItem, MatrxTableMenuSection } from \"@ai-matrx/design-system/data-table\";\nimport type { MatrxDataTableContextMenuConfig } from \"@ai-matrx/design-system/data-table/types\";\n\nimport { fieldName } from \"./names\";\nimport { REVERSE_COLUMN_PREFIX } from \"./reversePrefix\";\nimport { sortRefusal } from \"./gridPage\";\nimport { isNumericField } from \"./gridLook\";\nimport { editorKindFor } from \"./parity\";\nimport { retypeableFrom, whyNotRetypeable } from \"./FieldRetype\";\n\n/** Why a menu item whose handler this grid did not hand in does nothing here. */\nconst NOT_HERE = \"Not available here\";\n\n/**\n * WHAT A SORT IS CALLED ON THIS COLUMN (merged-grid review 2, C1: a number column read \"Sort A→Z\").\n * The words say what the order IS for the values the column holds, as Sheets and Airtable do:\n * numbers 1→9, dates oldest→newest, words A→Z. Pure.\n */\n/** Why a record cannot be renamed from the grid: its table names records by no typed column. */\nexport const NO_NAME_CELL = \"This table names records by no typed column\";\n\nexport function sortWords(field: Field | undefined): { asc: string; desc: string } {\n if (field) {\n const kind = String(editorKindFor(field));\n if (isNumericField(field) || kind === \"autonumber\") return { asc: \"1→9\", desc: \"9→1\" };\n if (kind === \"datetime\" || kind === \"date\") return { asc: \"oldest→newest\", desc: \"newest→oldest\" };\n }\n return { asc: \"A→Z\", desc: \"Z→A\" };\n}\n\n/** What the data table hands a `contextMenu.sections` resolver for the level that was clicked. */\nexport type MatrxTableMenuPayload = Parameters<NonNullable<MatrxDataTableContextMenuConfig<unknown>[\"sections\"]>>[0];\n\n/** Everything the menus may do, each through a path the grid already owns. */\nexport interface GridMenuActions {\n copyText: (text: string, what: string) => void;\n pasteInto: (rowId: string, columnId: string) => void;\n /** \"Paste over n cells\": the clipboard goes over the selected block through the grid's one paste door; absent, the item says why. */\n pasteOver?: (() => void) | undefined;\n clearCells: (cells: Array<{ rowId: string; columnId: string }>) => void;\n fillDown: (rowIds: string[], columnIds: string[]) => void;\n newRecord: () => void;\n /** Present only on a hand-ordered view, where a row HAS a place; absent, the items say why. */\n insertRow?: ((rowId: string, side: \"above\" | \"below\") => void) | undefined;\n duplicateRow: (rowId: string) => void;\n archiveRow: (rowId: string) => void;\n openRecord?: ((rowId: string) => void) | undefined;\n askWhoChanged?: ((columnId: string, rowId: string) => void) | undefined;\n sortBy: (columnId: string, direction: \"asc\" | \"desc\" | null) => void;\n filterBy: (columnId: string, value: unknown) => void;\n hideColumn: (columnId: string) => void;\n renameColumn: (columnId: string) => void;\n insertColumn: (columnId: string, side: \"left\" | \"right\") => void;\n columnSettings: (columnId: string) => void;\n deleteColumn: (columnId: string) => void;\n useAsRowLabel: (columnId: string) => void;\n addColumn?: (() => void) | undefined;\n /** Rename the record: its name cell opens in place (v7 TABLE-EXPERIENCE item 5); absent, the item says why. */\n renameRow?: ((rowId: string) => void) | undefined;\n /** Keep this row's values as a row template (\"New from template\"); absent, the item is not drawn. */\n saveAsTemplate?: ((rowId: string) => void) | undefined;\n /** Copy the link to the record's own page; absent, the item is not drawn. */\n copyRecordLink?: ((rowId: string) => void) | undefined;\n /** Merge another record of the table into this row (`MergeRecordDialog`); absent, the item says why. */\n mergeRow?: ((rowId: string) => void) | undefined;\n /** Open the host's one record picker pointed at this row (`RecordsUiHost.linkRecord`). */\n linkRow?: ((rowId: string) => void) | undefined;\n /** Change what the column holds (`FieldRetype`, with Undo); absent, the item says why. */\n changeType?: ((columnId: string) => void) | undefined;\n /** Tidy the column's text across every row (`ColumnCleanDialog`); absent, the item says why. */\n cleanColumn?: ((columnId: string) => void) | undefined;\n}\n\n/** What this person may do here, each with the sentence that says why not. */\nexport interface GridMenuContext {\n fields: readonly Field[];\n /** The table's row label column (`title_field`). */\n titleField: string | null;\n /** May this person change records here at all, and this row in particular. */\n mayWriteRow: (rowId: string) => boolean;\n whyNotWrite: (rowId?: string) => string;\n /** May this person archive (delete) this row: a higher rung than changing it (`remove` asks `editor`). */\n mayRemoveRow?: ((rowId: string) => boolean) | undefined;\n whyNotRemove?: ((rowId?: string) => string) | undefined;\n /** A row action the person's level refuses is left out of the menu instead of drawn disabled. */\n hideRefusedRowActions?: boolean | undefined;\n /** May this person add a record to the table. */\n mayAddRecord: boolean;\n whyNotAdd: string;\n /** May this person change the table's shape (columns, row label). */\n mayStructure: boolean;\n whyNotStructure: string;\n /** Whether a column holds plain text a clean can tidy (`isTextColumn`). */\n cleanable?: ((field: Field) => boolean) | undefined;\n /** Which columns take a typed value (a worked-out column never does). */\n typeable: (columnId: string) => boolean;\n /** The column's current sort, when it is the one the grid is sorted by. */\n sortedBy: { id: string; direction: \"asc\" | \"desc\" } | null;\n actions: GridMenuActions;\n /**\n * A READ-ONLY GRID (a picker's preview, `editable={false}`, a host whose `rights` port says\n * read): every item that writes is ABSENT — not disabled with a reason — because the grid is\n * not a place where writing happens at all (merged-grid leftovers, 2026-09-28). See `READS`.\n */\n readOnly?: boolean | undefined;\n /**\n * MORE ITEMS FROM THE MERGED GRID'S OTHER CONTROLS (tranches 6g, 6h, 6i) — colour, summary,\n * highlight, row label — each built where its data lives and slotted into the one vocabulary.\n */\n extras?: GridMenuExtras | undefined;\n}\n\n/** Items the grid's colour, summary and row-label controls add to the menus. */\nexport interface GridMenuExtras {\n header?: ((columnId: string) => MatrxTableMenuItem[]) | undefined;\n cell?: ((rowId: string, columnId: string) => MatrxTableMenuItem[]) | undefined;\n row?: ((rowId: string) => MatrxTableMenuItem[]) | undefined;\n table?: (() => MatrxTableMenuItem[]) | undefined;\n /** Items for a multi-cell selection (the colour door's \"Highlight n cells\"). */\n selection?: ((cells: Array<{ rowId: string; columnId: string }>) => MatrxTableMenuItem[]) | undefined;\n /** The row's own name (the table's row label), for the Row section's heading. */\n rowTitle?: ((rowId: string) => string | null) | undefined;\n}\n\nfunction fieldOf(ctx: GridMenuContext, columnId: string): Field | undefined {\n return ctx.fields.find((f) => f.key === columnId);\n}\n\nfunction columnWords(ctx: GridMenuContext, columnId: string): string {\n const field = fieldOf(ctx, columnId);\n return field ? fieldName(field) : columnId;\n}\n\n/** Only a column a person types can name a record: the store names records by stored words. */\nexport function rowLabelRefusal(field: Field | undefined): string | undefined {\n if (!field) return \"This column is not one of the table's own.\";\n const kind = String(field.type);\n if (kind === \"formula\" || kind === \"lookup\" || kind === \"rollup\") {\n return `${fieldName(field)} is worked out by the table, and a record is named by a column people fill in.`;\n }\n if (kind === \"relation\") return `${fieldName(field)} points at other records; a record is named by its own words.`;\n return undefined;\n}\n\n/**\n * WHAT A READ-ONLY GRID'S MENUS KEEP — THE ONE LIST (merged-grid leftovers, 2026-09-28: the\n * tables picker's preview offered Duplicate, Paste, Insert and Delete). An ALLOW-list on purpose:\n * an item added later is hidden from a read-only grid until someone decides it only reads, so a\n * new write item can never leak into a preview. Copying, opening, filtering, sorting and hiding a\n * column on your own screen read; everything else writes to the table, its records or its look.\n */\nexport const READS: ReadonlySet<string> = new Set([\n \"cell-copy\",\n \"cell-history\",\n \"cell-filter\",\n \"row-open\",\n \"row-history\",\n \"row-copy\",\n \"col-sort-asc\",\n \"col-sort-desc\",\n \"col-sort-clear\",\n \"col-hide\",\n \"sel-copy\",\n]);\n\n/** A read-only grid's items: only what reads (`READS`). */\nfunction readsOnly(items: MatrxTableMenuItem[], ctx: GridMenuContext): MatrxTableMenuItem[] {\n return ctx.readOnly ? items.filter((item) => READS.has(item.id)) : items;\n}\n\n/**\n * THE COLUMN HEADER'S OWN MENU — drawn by the data table under its built-in sort and filter\n * (`MatrxColumnDef.headerMenu`), so a column's actions live in the one place a person looks.\n */\n/** A back-link column's grid id starts here (`ReverseColumns.tsx` `REVERSE_COLUMN_PREFIX`). */\nconst BACK_LINK_COLUMN = \"linked:\";\n/** Why a back-link column is not renamed or retyped here: it mirrors a column of another table. */\nexport const BACK_LINK_COLUMN_MIRRORS = \"This column mirrors a link column on another table. Change it there.\";\n\nexport function headerMenuItems(columnId: string, ctx: GridMenuContext): MatrxTableMenuItem[] {\n // A BACK-LINK (REL-9, virtual) has no Field of its own: its settings say which link column it\n // mirrors, and removing it archives that column (CHAIR-UI-STORE item 2) — never a silent no-op.\n if (columnId.startsWith(BACK_LINK_COLUMN)) {\n const a = ctx.actions;\n return readsOnly([\n { id: \"col-settings\", label: \"Column settings…\", icon: \"settings\", onSelect: () => a.columnSettings(columnId) },\n { id: \"col-rename\", label: \"Rename column\", icon: \"pencil\", disabledReason: BACK_LINK_COLUMN_MIRRORS, onSelect: () => undefined },\n { id: \"col-hide\", label: \"Hide column\", icon: \"eye-off\", onSelect: () => a.hideColumn(columnId) },\n {\n id: \"col-delete\",\n label: \"Delete column…\",\n icon: \"trash\",\n destructive: true,\n separatorBefore: true,\n disabledReason: ctx.mayStructure ? undefined : ctx.whyNotStructure,\n onSelect: () => a.deleteColumn(columnId),\n },\n ], ctx);\n }\n const field = fieldOf(ctx, columnId);\n const shape = ctx.mayStructure ? undefined : ctx.whyNotStructure;\n const isLabel = ctx.titleField === columnId;\n const labelRefusal = shape ?? (isLabel ? \"Records are already named by this column.\" : rowLabelRefusal(field));\n const a = ctx.actions;\n return readsOnly([\n { id: \"col-rename\", label: \"Rename column\", icon: \"pencil\", disabledReason: shape, onSelect: () => a.renameColumn(columnId) },\n { id: \"col-settings\", label: \"Column settings…\", icon: \"settings\", disabledReason: shape, onSelect: () => a.columnSettings(columnId) },\n {\n id: \"col-retype\",\n label: \"Change type…\",\n disabledReason:\n shape ??\n (!a.changeType ? NOT_HERE : field && !retypeableFrom(field) ? whyNotRetypeable(field) : undefined),\n onSelect: () => a.changeType?.(columnId),\n },\n {\n id: \"col-clean\",\n label: \"Clean column…\",\n icon: \"paintbrush\",\n disabledReason:\n !a.cleanColumn\n ? NOT_HERE\n : !ctx.typeable(columnId)\n ? `${columnWords(ctx, columnId)} is worked out by the table; nobody types it.`\n : field && !ctx.cleanable?.(field)\n ? \"Only a text column can be cleaned.\"\n : undefined,\n onSelect: () => a.cleanColumn?.(columnId),\n },\n { id: \"col-insert-left\", label: \"Insert column left…\", icon: \"panel-left\", disabledReason: shape, onSelect: () => a.insertColumn(columnId, \"left\") },\n { id: \"col-insert-right\", label: \"Insert column right…\", icon: \"panel-right\", disabledReason: shape, onSelect: () => a.insertColumn(columnId, \"right\") },\n {\n id: \"col-row-label\",\n label: isLabel ? \"Names each record\" : \"Use as row label\",\n icon: \"tag\",\n disabledReason: labelRefusal,\n onSelect: () => a.useAsRowLabel(columnId),\n },\n ...(ctx.extras?.header?.(columnId) ?? []),\n { id: \"col-hide\", label: \"Hide column\", icon: \"eye-off\", onSelect: () => a.hideColumn(columnId) },\n {\n id: \"col-delete\",\n label: \"Delete column…\",\n icon: \"trash\",\n destructive: true,\n separatorBefore: true,\n disabledReason: shape ?? (isLabel ? \"Records are named by this column; pick another row label first.\" : undefined),\n onSelect: () => a.deleteColumn(columnId),\n },\n ], ctx);\n}\n\nfunction cellSection(\n payload: Extract<MatrxTableMenuPayload, { level: \"cell\" }>,\n ctx: GridMenuContext,\n): MatrxTableMenuSection {\n const a = ctx.actions;\n const { rowId, columnId } = payload;\n const mayWrite = ctx.mayWriteRow(rowId);\n const typeable = ctx.typeable(columnId);\n const why = !mayWrite\n ? ctx.whyNotWrite(rowId)\n : !typeable\n ? `${columnWords(ctx, columnId)} is worked out by the table; nobody types it.`\n : undefined;\n const items: MatrxTableMenuItem[] = [\n {\n id: \"cell-cut\",\n label: \"Cut cell\",\n icon: \"scissors\",\n shortcut: \"⌘X\",\n disabledReason: why,\n onSelect: () => {\n a.copyText(payload.text, \"The cell\");\n a.clearCells([{ rowId, columnId }]);\n },\n },\n { id: \"cell-copy\", label: \"Copy cell\", icon: \"copy\", shortcut: \"⌘C\", onSelect: () => a.copyText(payload.text, \"The cell\") },\n { id: \"cell-paste\", label: \"Paste\", icon: \"clipboard-paste\", shortcut: \"⌘V\", disabledReason: why, onSelect: () => a.pasteInto(rowId, columnId) },\n { id: \"cell-clear\", label: \"Clear cell\", icon: \"eraser\", destructive: true, disabledReason: why, onSelect: () => a.clearCells([{ rowId, columnId }]) },\n ];\n if (a.askWhoChanged) {\n items.push({ id: \"cell-history\", label: \"Who changed this?\", icon: \"history\", shortcut: \"⌥⇧H\", onSelect: () => a.askWhoChanged?.(columnId, rowId) });\n }\n const empty = payload.value === null || payload.value === undefined || payload.value === \"\";\n items.push({\n id: \"cell-filter\",\n label: empty ? \"Show rows where this is empty\" : \"Show rows with this value\",\n icon: \"filter\",\n onSelect: () => a.filterBy(columnId, payload.value),\n });\n items.push(...(ctx.extras?.cell?.(rowId, columnId) ?? []));\n return { id: \"cell\", title: payload.columnLabel || \"Cell\", items };\n}\n\nfunction rowSection(rowId: string, ctx: GridMenuContext, rowText: string | null): MatrxTableMenuSection {\n // THE RECORD'S MENU, NOTION'S ORDER (v7 TABLE-EXPERIENCE item 5): open, rename, duplicate, copy\n // link, then what reaches other records, then where a row goes, then Archive alone and last.\n const a = ctx.actions;\n const mayWrite = ctx.mayWriteRow(rowId);\n const items: MatrxTableMenuItem[] = [];\n if (a.openRecord) {\n items.push({ id: \"row-open\", label: \"Open record\", icon: \"panel-right\", shortcut: \"Space\", onSelect: () => a.openRecord?.(rowId) });\n }\n items.push({\n id: \"row-rename\",\n label: \"Rename\",\n icon: \"pencil\",\n disabledReason: !mayWrite ? ctx.whyNotWrite(rowId) : a.renameRow ? undefined : NO_NAME_CELL,\n onSelect: () => a.renameRow?.(rowId),\n });\n const noPlace =\n \"This view is sorted, so a new record lands where its sort puts it. Reorder places rows by hand; New record adds one.\";\n const insertWhy = !ctx.mayAddRecord ? ctx.whyNotAdd : a.insertRow ? undefined : noPlace;\n items.push({\n id: \"row-duplicate\",\n label: \"Duplicate\",\n icon: \"copy-plus\",\n disabledReason: ctx.mayAddRecord ? undefined : ctx.whyNotAdd,\n onSelect: () => a.duplicateRow(rowId),\n });\n if (a.copyRecordLink) {\n items.push({ id: \"row-copy-link\", label: \"Copy link\", icon: \"link\", onSelect: () => a.copyRecordLink?.(rowId) });\n }\n if (rowText !== null) {\n items.push({ id: \"row-copy\", label: \"Copy row\", icon: \"copy\", onSelect: () => a.copyText(rowText, \"The row\") });\n }\n if (a.saveAsTemplate) {\n items.push({ id: \"row-save-template\", label: \"Save as template\", icon: \"copy-plus\", onSelect: () => a.saveAsTemplate?.(rowId) });\n }\n items.push(\n {\n id: \"row-merge\",\n label: \"Merge with…\",\n separatorBefore: true,\n disabledReason: !mayWrite ? ctx.whyNotWrite(rowId) : a.mergeRow ? undefined : NOT_HERE,\n onSelect: () => a.mergeRow?.(rowId),\n },\n {\n id: \"row-link\",\n label: \"Link a record…\",\n icon: \"link\",\n disabledReason: a.linkRow ? undefined : NOT_HERE,\n onSelect: () => a.linkRow?.(rowId),\n },\n { id: \"row-insert-above\", label: \"Insert row above\", icon: \"plus\", separatorBefore: true, disabledReason: insertWhy, onSelect: () => a.insertRow?.(rowId, \"above\") },\n { id: \"row-insert-below\", label: \"Insert row below\", icon: \"plus\", disabledReason: insertWhy, onSelect: () => a.insertRow?.(rowId, \"below\") },\n );\n if (a.openRecord) {\n items.push({ id: \"row-history\", label: \"Row history\", icon: \"history\", onSelect: () => a.openRecord?.(rowId) });\n }\n items.push(...(ctx.extras?.row?.(rowId) ?? []));\n // ARCHIVE IN ITS OWN GROUP, LAST (DATA-V2-BASICS-2): one slip from Duplicate must not cost a row.\n // It asks `remove` (editor), not `write` (edit_content): a content editor changes rows but the door\n // refuses their archive, so the item says so — or, for a host that hides what the level refuses\n // (`hideRefusedRowActions`), is not drawn at all.\n const mayRemove = mayWrite && (ctx.mayRemoveRow ? ctx.mayRemoveRow(rowId) : true);\n if (mayRemove || !ctx.hideRefusedRowActions) {\n items.push({\n id: \"row-archive\",\n label: \"Archive record\",\n icon: \"trash\",\n destructive: true,\n separatorBefore: true,\n disabledReason: mayRemove ? undefined : !mayWrite ? ctx.whyNotWrite(rowId) : ctx.whyNotRemove?.(rowId) ?? ctx.whyNotWrite(rowId),\n onSelect: () => a.archiveRow(rowId),\n });\n }\n // THE ROW IS CALLED BY ITS NAME (tranche 6i): the table's row label, as the older grid's\n // right-click heading was.\n return { id: \"row\", title: ctx.extras?.rowTitle?.(rowId) || \"Row\", items };\n}\n\nfunction columnSection(columnId: string, columnLabel: string, ctx: GridMenuContext): MatrxTableMenuSection {\n const a = ctx.actions;\n const sorted = ctx.sortedBy?.id === columnId ? ctx.sortedBy.direction : null;\n // A sort the store would refuse is said, never offered (`sortRefusal`, merged-grid review 2026-09-26).\n const field = fieldOf(ctx, columnId);\n const refused = field ? sortRefusal(field) ?? undefined : undefined;\n const words = sortWords(field);\n return {\n id: \"column\",\n title: columnLabel || columnWords(ctx, columnId),\n items: [\n { id: \"col-sort-asc\", label: `Sort ${words.asc}`, icon: \"arrow-up-a-z\", disabledReason: refused ?? (sorted === \"asc\" ? `Already sorted ${words.asc}.` : undefined), onSelect: () => a.sortBy(columnId, \"asc\") },\n { id: \"col-sort-desc\", label: `Sort ${words.desc}`, icon: \"arrow-down-a-z\", disabledReason: refused ?? (sorted === \"desc\" ? `Already sorted ${words.desc}.` : undefined), onSelect: () => a.sortBy(columnId, \"desc\") },\n ...(sorted ? [{ id: \"col-sort-clear\", label: \"Clear sort\", icon: \"arrow-up-down\" as const, onSelect: () => a.sortBy(columnId, null) }] : []),\n ...headerMenuItems(columnId, ctx),\n ],\n };\n}\n\nfunction tableSection(ctx: GridMenuContext): MatrxTableMenuSection {\n const a = ctx.actions;\n const items: MatrxTableMenuItem[] = [\n { id: \"table-new-record\", label: \"New record\", icon: \"plus\", disabledReason: ctx.mayAddRecord ? undefined : ctx.whyNotAdd, onSelect: () => a.newRecord() },\n ];\n if (a.addColumn) {\n items.push({\n id: \"table-add-column\",\n label: \"Add column…\",\n icon: \"plus\",\n disabledReason: ctx.mayStructure ? undefined : ctx.whyNotStructure,\n onSelect: () => a.addColumn?.(),\n });\n }\n items.push(...(ctx.extras?.table?.() ?? []));\n return { id: \"table\", title: \"Table\", items };\n}\n\n/**\n * THE RIGHT-CLICK MENU — the section for what was aimed at first (`primary`), then the wider\n * things it sits in, exactly as the /data grid ordered them: a cell's menu also carries its row,\n * its column and the table.\n */\nexport function gridMenuSections(\n payload: MatrxTableMenuPayload,\n ctx: GridMenuContext,\n rowText: (rowId: string) => string | null = () => null,\n): MatrxTableMenuSection[] {\n const sections = allSections(payload, ctx, rowText);\n if (!ctx.readOnly) return sections;\n // A read-only grid: only what reads, and a section left with nothing is not drawn.\n const kept = sections\n .map((section) => ({ ...section, items: readsOnly(section.items, ctx) }))\n .filter((section) => section.items.length > 0);\n if (kept.length > 0 && !kept.some((section) => section.primary)) kept[0] = { ...kept[0]!, primary: true };\n return kept;\n}\n\nfunction allSections(\n payload: MatrxTableMenuPayload,\n ctx: GridMenuContext,\n rowText: (rowId: string) => string | null,\n): MatrxTableMenuSection[] {\n switch (payload.level) {\n case \"cell\":\n // A RIGHT-CLICK ON A CELL IS THE RECORD'S MENU FIRST (Airtable, Notion; v7 item 5): the cell's\n // own verbs (copy, paste, clear — all on the keyboard too) follow.\n return [\n { ...rowSection(payload.rowId, ctx, rowText(payload.rowId)), primary: true },\n cellSection(payload, ctx),\n columnSection(payload.columnId, payload.columnLabel, ctx),\n tableSection(ctx),\n ];\n case \"row\":\n return [{ ...rowSection(payload.rowId, ctx, rowText(payload.rowId)), primary: true }, tableSection(ctx)];\n case \"column\":\n return [{ ...columnSection(payload.columnId, payload.columnLabel, ctx), primary: true }, tableSection(ctx)];\n case \"selection\": {\n const n = payload.cellCount;\n const blocked = payload.rowIds.find((id) => !ctx.mayWriteRow(id));\n const untypeable = payload.columnIds.find((id) => !ctx.typeable(id));\n const why = blocked\n ? ctx.whyNotWrite(blocked)\n : untypeable\n ? `${columnWords(ctx, untypeable)} is worked out by the table; nobody types it.`\n : undefined;\n const cells = payload.rowIds.flatMap((rowId) => payload.columnIds.map((columnId) => ({ rowId, columnId })));\n return [\n {\n id: \"selection\",\n title: `${n} ${n === 1 ? \"cell\" : \"cells\"}`,\n primary: true,\n items: [\n {\n id: \"sel-cut\",\n label: `Cut ${n} cells`,\n icon: \"scissors\",\n shortcut: \"⌘X\",\n disabledReason: why,\n onSelect: () => {\n ctx.actions.copyText(payload.tsv, `${n} cells`);\n ctx.actions.clearCells(cells);\n },\n },\n { id: \"sel-copy\", label: `Copy ${n} cells`, icon: \"copy\", shortcut: \"⌘C\", onSelect: () => ctx.actions.copyText(payload.tsv, `${n} cells`) },\n {\n id: \"sel-paste\",\n label: `Paste over ${n} cells`,\n icon: \"clipboard-paste\",\n shortcut: \"⌘V\",\n disabledReason: why ?? (ctx.actions.pasteOver ? undefined : NOT_HERE),\n onSelect: () => ctx.actions.pasteOver?.(),\n },\n { id: \"sel-clear\", label: `Clear ${n} cells`, icon: \"eraser\", destructive: true, disabledReason: why, onSelect: () => ctx.actions.clearCells(cells) },\n {\n id: \"sel-fill-down\",\n label: \"Fill down\",\n icon: \"arrow-down-to-line\",\n shortcut: \"⌘D\",\n disabledReason: why ?? (payload.rowIds.length < 2 ? \"Select at least two rows to fill down.\" : undefined),\n onSelect: () => ctx.actions.fillDown(payload.rowIds, payload.columnIds),\n },\n ...(ctx.extras?.selection?.(cells) ?? []),\n ],\n },\n tableSection(ctx),\n ];\n }\n case \"table\":\n return [{ ...tableSection(ctx), primary: true }];\n }\n}\n\n/**\n * WHERE A NEW COLUMN GOES in the view's column order: beside the one it was inserted from.\n * Pure. `order` is the order on screen; the new key is taken out first so a repeat is a move.\n */\nexport function placeColumn(order: readonly string[], newKey: string, anchor: string, side: \"left\" | \"right\"): string[] {\n const rest = order.filter((k) => k !== newKey);\n const at = rest.indexOf(anchor);\n if (at < 0) return [...rest, newKey];\n const index = side === \"left\" ? at : at + 1;\n return [...rest.slice(0, index), newKey, ...rest.slice(index)];\n}\n\n/**\n * THE COLUMNS IN THE ORDER A PERSON LEFT THEM: the view's kept order first (keys whose Field is\n * gone are skipped), then every column it does not name, in the Fields' own order. Pure.\n */\nexport function columnsInKeptOrder(fieldKeys: readonly string[], kept: readonly string[] | undefined): string[] {\n if (!kept || kept.length === 0) return [...fieldKeys];\n const known = new Set(fieldKeys);\n // A kept back-link column (`linked:…`) keeps its place like a Field's (ReverseColumns.tsx).\n const named = kept.filter((k, i) => (known.has(k) || k.startsWith(REVERSE_COLUMN_PREFIX)) && kept.indexOf(k) === i);\n const namedSet = new Set(named);\n return [...named, ...fieldKeys.filter((k) => !namedSet.has(k))];\n}\n\n/**\n * THE ORDER THE COLUMNS TAKE WHEN NOBODY MOVED ONE (lane C, review 2026-09-26 C5): a Field's own\n * `sort`, then the order the columns were MADE in, and the key only as the last word. Ordering by\n * key put a new column in the alphabetical slot of its internal key (\"New columns land in\n * alphabetical order of their internal key\"). Pure.\n */\nexport function compareFieldOrder(\n a: Pick<Field, \"sort\" | \"key\"> & { created_at?: string | null },\n b: Pick<Field, \"sort\" | \"key\"> & { created_at?: string | null },\n): number {\n const bySort = (a.sort ?? 100) - (b.sort ?? 100);\n if (bySort !== 0) return bySort;\n const made = String(a.created_at ?? \"\").localeCompare(String(b.created_at ?? \"\"));\n if (made !== 0) return made;\n return a.key.localeCompare(b.key);\n}\n\n/**\n * THE `sort` A NEW COLUMN IS DECLARED WITH: one past the last column, so it lands at the END of\n * the table in every view and every client, never in the middle. Pure.\n */\nexport function nextFieldSort(fields: readonly Pick<Field, \"sort\">[] | null | undefined): number {\n let last = 0;\n for (const f of fields ?? []) last = Math.max(last, f.sort ?? 100);\n return last + 1;\n}\n","// src/ButtonSettings.tsx — @ai-matrx/records-ui\n//\n// A BUTTON COLUMN'S SETTINGS (lane NOTION-PROPS-3), drawn inside the column settings panel (`FieldEditor`):\n// its label, its colour, and what a press does — open a link (with the row's values in it), set fields\n// (one of the table's row actions) or run one of the table's automations. Saved through the column's one\n// save (`custom.field_declare` / `custom.field_update`'s `button`); the store judges it on the way in.\n\nimport { useEffect, useState } from \"react\";\nimport { BasicInput, Label } from \"@ai-matrx/design-system\";\nimport { STYLE_COLORS } from \"@ai-matrx/design-system/data-table\";\nimport { buttonUrlPlaceholders, type ButtonDoes, type ButtonSettings, type Field, type PortalAccent, type Uuid } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport { AccentSwatches } from \"./AccentSwatches\";\nimport { PickOne } from \"./PickOne\";\nimport { fieldName } from \"./names\";\n\nconst DOES_WORDS: Record<ButtonDoes | \"none\", string> = {\n none: \"Nothing yet\",\n open_url: \"Open a link\",\n run_action: \"Set fields\",\n run_automation: \"Run an automation\",\n};\n\n/** A link with each {{field id}} shown as the column's name, so the person reads what it will hold. */\nexport function buttonUrlInWords(url: string, fields: readonly Field[]): string {\n let out = url;\n for (const id of buttonUrlPlaceholders(url)) {\n const f = fields.find((x) => x.id === id || x.key === id);\n if (f) out = out.split(`{{${id}}}`).join(`{${fieldName(f)}}`);\n }\n return out;\n}\n\nexport function ButtonSettingsEditor({\n value,\n onChange,\n tableId,\n fields,\n}: {\n value: ButtonSettings;\n onChange: (next: ButtonSettings) => void;\n tableId: Uuid | null;\n fields: readonly Field[];\n}) {\n const client = useOptionalRecordsClient();\n const [actions, setActions] = useState<Array<{ id: string; name: string }> | null>(null);\n const [automations, setAutomations] = useState<Array<{ id: string; name: string }> | null>(null);\n useEffect(() => {\n if (!client || !tableId) return;\n let live = true;\n if (value.do === \"run_action\" && actions === null) {\n void client.rowActions({ table_id: tableId }).then((got) => {\n if (live) setActions(got.ok ? (got.data?.actions ?? []).filter((a) => a.id).map((a) => ({ id: a.id as string, name: a.name })) : []);\n });\n }\n if (value.do === \"run_automation\" && automations === null) {\n void client.automations({ table_id: tableId }).then((got) => {\n if (live) setAutomations(got.ok ? (got.data?.automations ?? []).filter((a) => !a.archived_at).map((a) => ({ id: a.id, name: a.name })) : []);\n });\n }\n return () => {\n live = false;\n };\n }, [client, tableId, value.do, actions, automations]);\n\n const set = (patch: Partial<ButtonSettings>) => onChange({ ...value, ...patch });\n const columns = fields.filter((f) => !(f.type === \"text\" && f.format === \"button\"));\n\n return (\n <div className=\"flex flex-col gap-2 rounded-md border p-2\" data-records-button-settings=\"\">\n <div className=\"grid gap-2 sm:grid-cols-2\">\n <label className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Button label</Label>\n <BasicInput className=\"h-8 text-xs\" value={value.label} data-records-button-label=\"\" onChange={(e) => set({ label: e.target.value })} />\n </label>\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Does</Label>\n <PickOne\n label=\"What a press does\"\n value={value.do ?? \"none\"}\n attrs={{ \"data-records-button-does\": \"\" }}\n onChange={(next) => set({ do: next === \"none\" ? undefined : (next as ButtonDoes) })}\n options={([\"none\", \"open_url\", \"run_action\", \"run_automation\"] as const).map((d) => ({ value: d, label: DOES_WORDS[d] }))}\n />\n </div>\n </div>\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Colour</Label>\n <AccentSwatches\n value={(value.color ?? \"\") as PortalAccent | \"\"}\n options={STYLE_COLORS as unknown as readonly PortalAccent[]}\n noneLabel=\"Plain\"\n onChange={(next) => set({ color: next === \"\" ? undefined : next })}\n />\n </div>\n {value.do === \"open_url\" ? (\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-xs\">Link</Label>\n <div className=\"flex gap-1\">\n <BasicInput\n className=\"h-8 flex-1 font-mono text-xs\"\n placeholder=\"https://\"\n data-records-button-url=\"\"\n value={value.url ?? \"\"}\n onChange={(e) => set({ url: e.target.value })}\n />\n {columns.length > 0 ? (\n <PickOne\n label=\"Add a column's value\"\n className=\"h-8 w-36 text-xs\"\n value=\"\"\n placeholder=\"Add value\"\n attrs={{ \"data-records-button-insert\": \"\" }}\n onChange={(id) => set({ url: `${value.url ?? \"\"}{{${id}}}` })}\n options={columns.map((f) => ({ value: f.id, label: fieldName(f) }))}\n />\n ) : null}\n </div>\n {value.url && buttonUrlPlaceholders(value.url).length > 0 ? (\n <p className=\"truncate text-[11px] text-muted-foreground\" data-records-button-url-words=\"\">\n {buttonUrlInWords(value.url, fields)}\n </p>\n ) : null}\n </div>\n ) : null}\n {value.do === \"run_action\" ? (\n actions && actions.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">No row actions yet. Add one in Table settings.</p>\n ) : (\n <PickOne\n label=\"Row action\"\n value={value.action_id ?? \"\"}\n placeholder={actions ? \"Choose a row action\" : \"Reading row actions…\"}\n onChange={(id) => set({ action_id: id as Uuid })}\n options={(actions ?? []).map((a) => ({ value: a.id, label: a.name }))}\n />\n )\n ) : null}\n {value.do === \"run_automation\" ? (\n automations && automations.length === 0 ? (\n <p className=\"text-xs text-muted-foreground\">No automations yet. Add one in Table settings.</p>\n ) : (\n <PickOne\n label=\"Automation\"\n value={value.automation_id ?? \"\"}\n placeholder={automations ? \"Choose an automation\" : \"Reading automations…\"}\n onChange={(id) => set({ automation_id: id as Uuid })}\n options={(automations ?? []).map((a) => ({ value: a.id, label: a.name }))}\n />\n )\n ) : null}\n </div>\n );\n}\n","\"use client\";\n\n// src/AccentSwatches.tsx — @ai-matrx/records-ui\n//\n// THE ONE COLOUR PICKER FOR A LOOK. A portal's look (`PortalLookEditor`) and a form's look\n// (`FormBuilder`, MAKE-HOME W5) choose their colour here, from the SAME seven names the table\n// highlights use (`custom.portal_accents()`), so an organization's portal and its forms can never\n// be offered two palettes. \"App colour\" is the empty choice: the look falls back to the\n// organization's (a form) or the app's (a portal).\n\nimport type { PortalAccent } from \"@ai-matrx/records\";\nimport { PORTAL_ACCENTS } from \"@ai-matrx/records\";\nimport { cn } from \"@ai-matrx/design-system\";\nimport { STYLE_COLOR_LABELS, SWATCH_CLASS } from \"@ai-matrx/design-system/data-table\";\n\nexport interface AccentSwatchesProps {\n value: PortalAccent | \"\";\n onChange: (accent: PortalAccent | \"\") => void;\n /** The colours the store accepts. Defaults to the shared seven. */\n options?: readonly PortalAccent[] | undefined;\n /** The words on the empty choice. */\n noneLabel?: string | undefined;\n}\n\nexport function AccentSwatches({ value, onChange, options = PORTAL_ACCENTS, noneLabel = \"App colour\" }: AccentSwatchesProps) {\n return (\n <div className=\"flex flex-wrap gap-1.5\" role=\"radiogroup\" aria-label=\"Colour\">\n <button\n type=\"button\"\n role=\"radio\"\n aria-checked={value === \"\"}\n onClick={() => onChange(\"\")}\n className={cn(\n \"h-7 rounded border px-2 text-xs\",\n value === \"\" ? \"border-foreground\" : \"border-border text-muted-foreground\",\n )}\n >\n {noneLabel}\n </button>\n {options.map((c) => (\n <button\n key={c}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === c}\n aria-label={STYLE_COLOR_LABELS[c]}\n title={STYLE_COLOR_LABELS[c]}\n onClick={() => onChange(c)}\n className={cn(\"h-7 w-7 rounded-full border-2\", SWATCH_CLASS[c], value === c ? \"border-foreground\" : \"border-transparent\")}\n />\n ))}\n </div>\n );\n}\n","\"use client\";\n\n// src/PersonPicker.tsx — @ai-matrx/records-ui · FLD-11 (`member`)\n//\n// PICKING A PERSON MEANS PICKING A PERSON.\n//\n// What it replaced, measured on the real screen (independent verdict, 19\n// September): the \"Owner\" field — which the settings panel itself calls a\n// Person field — offered \"Comments Home\", \"Saved views Home\" and \"V78 Home\".\n// Those are not people. They are the Home records this package writes into the\n// kernel Person Table so that its own Tables have somewhere to live (REC-1),\n// and the generic relation picker was listing the Table's contents, which is\n// exactly right for a relation and exactly wrong for a person.\n//\n// SO A PERSON FIELD ASKS A DIFFERENT QUESTION. The list is the ORGANIZATION'S\n// MEMBERS — who those are is the platform's answer and not the record store's,\n// so it arrives through the `members` port on the host, the same way saved\n// views and file uploads do. The record store has no door onto organization\n// membership and this package does not invent one.\n//\n// WHAT IS STORED IS STILL A RECORD ID, because a member field is a relation to\n// the kernel Person Table and the store's foreign key is real. So picking a\n// member resolves that member to their Person record — by the `user_id` the\n// record carries — and writes one when the organization has not got one yet.\n// That write is the same `record_write` everything else in this package uses;\n// there is no second storage path, and a Home (a Person record with no\n// `user_id`) is never offered and never picked.\n//\n// Unbound port: the control is ABSENT with its reason, never a dead box and\n// never a list of the wrong things.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { Field, ReadRow, RecordsError, Uuid } from \"@ai-matrx/records\";\nimport { rankTypedMatches } from \"@ai-matrx/records\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { cn } from \"@ai-matrx/design-system\";\n\nimport { PickOrAdd } from \"./PickOrAdd\";\nimport { PersonChip } from \"./personChip\";\nimport { useRecordsUi, type OrganizationMember } from \"./host\";\nimport { NO_MEMBERS_REASON } from \"./host\";\nimport { fieldName } from \"./names\";\nimport { RefusalLine } from \"./Refusal\";\n\nexport interface PersonPickerProps {\n field: Field;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id?: string | undefined;\n className?: string | undefined;\n /** A grid cell's picker opens at once (`FieldEditorControlProps.autoOpen`). */\n autoOpen?: boolean | undefined;\n /** The list closed: the cell commits who is picked. */\n onClose?: (() => void) | undefined;\n /** Escape in a grid cell's list: the cell's cancel — nothing is written (`PickOrAdd.onEscape`). */\n onCancel?: (() => void) | undefined;\n /** What was typed to open a grid cell's list: its first search (`FieldEditorControlProps.initialSearch`). */\n initialSearch?: string | undefined;\n}\n\n/** A Person record in the kernel Table, as this picker needs to read it. */\ninterface PersonRecord {\n id: Uuid;\n userId: string | null;\n name: string;\n}\n\nfunction personFromRow(row: ReadRow): PersonRecord {\n const data = (row.document ?? {}) as Record<string, unknown>;\n const userId = data[\"user_id\"];\n return {\n id: row.id,\n userId: typeof userId === \"string\" && userId !== \"\" ? userId : null,\n name: String(data[\"full_name\"] ?? data[\"name\"] ?? data[\"email\"] ?? \"\").trim(),\n };\n}\n\n/** The member's own name, as a person reads it. Never a uuid. */\nexport function memberName(member: OrganizationMember): string {\n const display = (member.name ?? \"\").trim();\n if (display !== \"\") return display;\n const email = (member.email ?? \"\").trim();\n if (email !== \"\") return email;\n return \"A member with no name set\";\n}\n\n/**\n * Find (or write) the kernel Person record for one member. Exported because\n * an agent filling a person field server-side needs exactly the same answer,\n * and two implementations of \"which record is this person\" is two answers.\n */\nexport async function personRecordForMember(\n client: RecordsClient,\n personTableId: Uuid,\n people: PersonRecord[],\n member: OrganizationMember,\n): Promise<{ ok: true; data: Uuid } | { ok: false; error: RecordsError }> {\n const held = people.find((p) => p.userId === member.userId);\n if (held) return { ok: true, data: held.id };\n const written = await client.recordWrite({\n table_id: personTableId,\n data: {\n user_id: member.userId,\n full_name: memberName(member),\n ...(member.email ? { email: member.email } : {}),\n },\n });\n return written;\n}\n\nexport function PersonPicker({ field, value, onChange, disabled, id, className, autoOpen, onClose, onCancel, initialSearch }: PersonPickerProps) {\n // NOT `useRecordsClient`. This control is drawn by `FieldControl`, and\n // `FieldControl` is drawn by the PUBLIC arm of `FormRunner`, which mounts no\n // store client at all — the hook that throws turned a stranger's form into an\n // HTTP 500 (VERIFIER-10, F1). With no client there is nobody to offer, which\n // is the same answer this control already gives an unbound `members` port.\n const client = useOptionalRecordsClient();\n const host = useRecordsUi();\n const [members, setMembers] = useState<OrganizationMember[] | null>(null);\n const [people, setPeople] = useState<PersonRecord[]>([]);\n const [error, setError] = useState<RecordsError | null>(null);\n const [search, setSearch] = useState(initialSearch ?? \"\");\n const [open, setOpenState] = useState(autoOpen === true);\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n // Closing the list — a pick, Escape, a click away — is what a grid cell commits on.\n const setOpen = useCallback((next: boolean) => {\n setOpenState(next);\n if (!next) onCloseRef.current?.();\n }, []);\n const [busy, setBusy] = useState(false);\n\n const membersPort = host.members;\n const personTable = field.relation_target;\n\n const picked = useMemo<string[]>(\n () => (Array.isArray(value) ? value.map(String) : value === null || value === undefined ? [] : [String(value)]),\n [value],\n );\n\n const load = useCallback(async () => {\n if (!membersPort || !client) return;\n const [roster, records] = await Promise.all([\n membersPort(),\n personTable ? client.list({ table_id: personTable, limit: 500 }) : Promise.resolve(null),\n ]);\n setMembers(roster);\n if (records && !records.ok) {\n setError(records.error);\n return;\n }\n setPeople(records ? records.data.rows.map(personFromRow).filter((p) => p.userId !== null) : []);\n }, [membersPort, client, personTable]);\n\n useEffect(() => {\n if (!open) return;\n void load();\n }, [open, load]);\n\n // The names of the records that are already picked, whether or not the list\n // has been opened — a chip that read `8f2c1b0a` is the defect this closes.\n useEffect(() => {\n if (picked.length === 0 || !personTable || people.length > 0 || !client) return;\n let cancelled = false;\n void client.list({ table_id: personTable, limit: 500 }).then((result) => {\n if (cancelled || !result.ok) return;\n setPeople(result.data.rows.map(personFromRow).filter((p) => p.userId !== null));\n });\n return () => {\n cancelled = true;\n };\n }, [client, personTable, picked.length, people.length]);\n\n // THE ONE RANKING (`rankTypedMatches`, grids review 3): exact, starts with, a word starts with, contains.\n const listed = rankTypedMatches(members ?? [], search, memberName);\n\n if (!membersPort || !client) {\n // ABSENT AND HONEST. A person question with nobody to offer is not a box\n // that silently does nothing — it names the port that fills it.\n return <p className={cn(\"text-xs text-muted-foreground\", className)}>{NO_MEMBERS_REASON}</p>;\n }\n\n if (!personTable) {\n return (\n <p className={cn(\"text-xs text-muted-foreground\", className)}>\n {fieldName(field)} is a person field, but it does not say which Table the people are\n records of yet, so there is nothing to pick from. A table admin sets its target in the field\n editor.\n </p>\n );\n }\n\n // ONE PERSON, ONE NAME (lane CELL-EDITORS, 2026-10-06): the chip read \"admin\" (the Person record)\n // while the list read \"admin@admin.com\" (a member with no display name). The display name is the\n // member's own, else the Person record's; the email is shown beside it, and alone only when there is\n // no name at all.\n const displayNameOf = (userId: string | null, recordName?: string): string | null => {\n const member = userId ? (members ?? []).find((m) => m.userId === userId) : undefined;\n const own = (member?.name ?? \"\").trim();\n if (own !== \"\") return own;\n const kept = (recordName ?? people.find((p) => p.userId === userId)?.name ?? \"\").trim();\n const email = (member?.email ?? \"\").trim();\n return kept !== \"\" && kept !== email ? kept : null;\n };\n const nameOfRecord = (recordId: string) => {\n const person = people.find((p) => p.id === recordId);\n if (!person) return \"Loading…\";\n const member = (members ?? []).find((m) => m.userId === person.userId);\n return displayNameOf(person.userId, person.name) ?? (member ? memberName(member) : person.name || \"A member with no name set\");\n };\n\n const pick = async (member: OrganizationMember) => {\n setBusy(true);\n setError(null);\n const resolved = await personRecordForMember(client, personTable, people, member);\n setBusy(false);\n if (!resolved.ok) {\n setError(resolved.error);\n return;\n }\n // Keep the newly written record so the chip can be named at once.\n if (!people.some((p) => p.id === resolved.data)) {\n setPeople((held) => [...held, { id: resolved.data, userId: member.userId, name: memberName(member) }]);\n }\n if (!field.multi) {\n onChange(picked[0] === resolved.data ? null : resolved.data);\n setOpen(false);\n return;\n }\n const next = new Set(picked);\n if (next.has(resolved.data)) next.delete(resolved.data);\n else next.add(resolved.data);\n onChange(next.size === 0 ? null : [...next]);\n };\n\n const drop = (recordId: string) => {\n const next = picked.filter((id) => id !== recordId);\n onChange(next.length === 0 ? null : field.multi ? next : (next[0] ?? null));\n };\n\n const visible = listed;\n const pickedUserIds = new Set(\n picked.map((recordId) => people.find((p) => p.id === recordId)?.userId).filter(Boolean),\n );\n\n const anchored = autoOpen === true;\n const cellChips = picked.map((recordId) => (\n <PersonChip key={recordId} name={nameOfRecord(recordId)} {...(disabled || anchored ? {} : { onRemove: () => drop(recordId) })} />\n ));\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-1\", className)}>\n {anchored && !disabled ? null : cellChips}\n {disabled ? null : (\n // THE ONE \"PICK OR ADD\" BUILDER (lane CELL-EDITORS, 2026-10-06): the person list used to carry\n // its own copy of the list's layout and keys; it now draws the same rows, ticks, highlight and\n // head chips as every other picker, and in a grid cell hangs from the cell.\n <PickOrAdd\n {...(anchored && onCancel ? { onEscape: onCancel } : {})}\n anchored={anchored}\n multi={field.multi}\n triggerId={id}\n triggerLabel={`Pick a person for ${fieldName(field)}`}\n triggerText={picked.length === 0 ? \"Pick a person\" : \"Change\"}\n open={open}\n onOpenChange={setOpen}\n search={search}\n onSearch={setSearch}\n chips={picked.map((recordId) => ({ id: recordId, label: nameOfRecord(recordId), person: true, onRemove: () => drop(recordId) }))}\n items={visible.map((member) => ({\n id: member.userId,\n label: displayNameOf(member.userId) ?? memberName(member),\n // A name and an email with nothing between them read as one run-on string (verdict,\n // 19 September). They are two facts, so they are drawn as two.\n detail: displayNameOf(member.userId) !== null && member.email ? member.email : null,\n picked: pickedUserIds.has(member.userId),\n person: true,\n disabled: busy,\n }))}\n onPick={(userId) => {\n const member = visible.find((m) => m.userId === userId);\n if (member && !busy) void pick(member);\n }}\n notice={\n <>\n {error ? <RefusalLine error={error} className=\"p-2\" /> : null}\n {members === null ? <p className=\"p-2 text-xs text-muted-foreground\">Reading the members…</p> : null}\n </>\n }\n empty={\n members !== null ? (\n <p className=\"p-2 text-xs text-muted-foreground\">\n {members.length === 0\n ? \"This organization has no other members yet, so there is nobody to assign.\"\n : \"Nobody in this organization matches.\"}\n </p>\n ) : null\n }\n >\n {anchored ? cellChips : null}\n </PickOrAdd>\n )}\n </div>\n );\n}\n","/**\n * A TYPED VALUE'S REFUSAL FLOATS WHERE IT CAN BE READ (walk 4, 2026-10-07).\n *\n * \"Enter a valid phone number\" was in the DOM but clipped inside a 114 px grid cell (the cell, the\n * sticky header and the scroller all clip what an absolutely placed note tries to draw past them),\n * and on the record page the same note covered the Email value under Phone. The note is now drawn\n * in a layer on <body>, anchored to the open editor, so nothing clips it and it moves nothing:\n * · in a grid cell — directly above the cell, left-aligned with it (below it when there is no\n * room above), the way every other note an open cell says floats;\n * · in a record's field — inside the field's own box, at its right end, so it covers no other field.\n * The anchor is the open editor (`data-matrx-cell-editor`), else the note's own parent.\n */\nimport { useLayoutEffect, useRef, useState, type CSSProperties } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nconst GAP = 4;\n\nfunction placeFor(anchor: Element, note: HTMLElement | null): CSSProperties {\n const a = anchor.getBoundingClientRect();\n const inGrid = anchor.closest(\"td\") !== null;\n const height = note?.offsetHeight ?? 20;\n const width = note?.offsetWidth ?? 0;\n if (inGrid) {\n const above = a.top - GAP - height;\n const top = above >= 0 ? above : a.bottom + GAP;\n const left = Math.max(GAP, Math.min(a.left, window.innerWidth - width - GAP));\n return { position: \"fixed\", top, left };\n }\n // A record's field: inside its own box, right end, vertically centred.\n return { position: \"fixed\", top: a.top + (a.height - height) / 2, left: Math.max(a.left, a.right - width - 8) };\n}\n\nexport function FloatingRefusal({ text, why }: { text: string; why?: string | undefined }) {\n const spot = useRef<HTMLSpanElement | null>(null);\n const note = useRef<HTMLSpanElement | null>(null);\n const [style, setStyle] = useState<CSSProperties | null>(null);\n // Only an OPEN CELL'S editor (a grid cell, a record's field in place) floats its note; a form's\n // box keeps it in flow under the box, as it always did.\n const [floating, setFloating] = useState(false);\n useLayoutEffect(() => {\n const here = spot.current;\n if (!here) return;\n const anchor = here.closest(\"[data-matrx-cell-editor]\");\n setFloating(anchor !== null);\n if (!anchor) return;\n const place = () => setStyle(placeFor(anchor, note.current));\n place();\n // Measured once more after the note has its own size, then on every scroll or resize.\n const frame = requestAnimationFrame(place);\n window.addEventListener(\"scroll\", place, true);\n window.addEventListener(\"resize\", place);\n return () => {\n cancelAnimationFrame(frame);\n window.removeEventListener(\"scroll\", place, true);\n window.removeEventListener(\"resize\", place);\n };\n }, [text]);\n if (!floating) {\n return (\n <span ref={spot} data-records-typed-refusal=\"\" role=\"status\" title={why} className=\"text-[11px] leading-snug text-amber-700 dark:text-amber-400\">\n {text}\n </span>\n );\n }\n return (\n <>\n <span ref={spot} data-records-refusal-anchor=\"\" hidden />\n {typeof document === \"undefined\"\n ? null\n : createPortal(\n <span\n ref={note}\n data-records-typed-refusal=\"\"\n data-records-floating-refusal=\"\"\n role=\"status\"\n title={why}\n style={{ ...(style ?? { position: \"fixed\", top: -9999, left: -9999 }), zIndex: 60 }}\n className=\"pointer-events-none w-max max-w-[24rem] rounded-md border bg-popover px-1.5 py-0.5 text-[11px] leading-snug text-amber-700 shadow-md dark:text-amber-400\"\n >\n {text}\n </span>,\n document.body,\n )}\n </>\n );\n}\n","\"use client\";\n\n// src/formatControls.tsx — @ai-matrx/records-ui · merge tranche 6e (formats)\n//\n// THE FORMAT-AWARE EDITOR — the older /data grid's `FormatAwareInput` and `RatingInput`,\n// rewritten onto the platform registry. A column that shows as money takes \"$1,250.50\"; a percent\n// kept as a fraction is typed as the percent a person reads (45, or \"45%\") and kept as 0.45; a\n// rating is its stars; a time of day, a colour, an email, a link, a phone number get the input\n// that fits them. Parsing is the registry's own (`parseFieldInput`), so what the cell shows and\n// what the editor reads are one vocabulary.\n//\n// `formatControl` answers `null` for a format with no opinion about its input — the caller keeps\n// the kind's own control (THE FALLBACK LAW applied to editing: a format may add a better input,\n// never take a working one away).\n\nimport { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { BasicInput, BasicTextarea } from \"@ai-matrx/design-system\";\nimport { getFieldFormat, parseFieldInput, type FieldFormatConfig } from \"@ai-matrx/design-system/field-formats\";\n\nimport { RatingStars } from \"./formattedValue\";\n\ninterface FormatControlArgs {\n format: FieldFormatConfig;\n value: unknown;\n onChange: (value: unknown) => void;\n disabled?: boolean | undefined;\n id: string;\n label: string;\n /** A page nobody is signed into: the browser may offer the person's own email and phone. */\n ownDetails?: boolean | undefined;\n}\n\n/** Number formats typed as text, so a symbol, a comma or a percent sign is read, never refused by the browser. */\nconst TYPED_NUMBERS = new Set([\"currency\", \"percent\", \"progress\", \"decimal\", \"duration\", \"file_size\", \"integer\"]);\n\n/** A percent kept as a fraction is shown and typed ×100. */\nfunction scaled(format: FieldFormatConfig): boolean {\n return (format.id === \"percent\" || format.id === \"progress\") && format.options?.percentScale === \"fraction\";\n}\n\n/** What the box starts holding for a stored value. */\nexport function typedText(format: FieldFormatConfig, value: unknown): string {\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" && scaled(format)) return String(Math.round(value * 100 * 1e6) / 1e6);\n return String(value);\n}\n\n/** What a typed text is kept as, in this format. Null for an empty box. */\nexport function keptValue(format: FieldFormatConfig, raw: string): unknown {\n if (raw.trim() === \"\") return null;\n const parsed = parseFieldInput(raw, format);\n if (typeof parsed === \"number\" && scaled(format)) return Math.round((parsed / 100) * 1e9) / 1e9;\n return parsed;\n}\n\nfunction NumberInFormat({ format, value, onChange, disabled, id }: FormatControlArgs) {\n const [text, setText] = useState(() => typedText(format, value));\n // A value that moves under the box (a reload, a seed) is shown — unless it is what was just typed.\n const lastSent = useRef<unknown>(undefined);\n useEffect(() => {\n if (value === lastSent.current) return;\n setText(typedText(format, value));\n }, [value, format]);\n return (\n <BasicInput\n id={id}\n inputMode=\"decimal\"\n className=\"tabular-nums\"\n value={text}\n disabled={disabled}\n placeholder={format.id === \"currency\" ? \"$0.00\" : format.id === \"percent\" || format.id === \"progress\" ? \"45%\" : undefined}\n onChange={(e) => {\n setText(e.target.value);\n const next = keptValue(format, e.target.value);\n lastSent.current = next;\n onChange(next);\n }}\n />\n );\n}\n\n/** The input a format supplies, or null when the kind's own control is the right one. */\nexport function formatControl(args: FormatControlArgs): ReactNode | null {\n const def = getFieldFormat(args.format.id);\n if (!def) return null;\n const { format, value, onChange, disabled, id, label, ownDetails } = args;\n const text = value === null || value === undefined ? \"\" : String(value);\n const commit = (raw: string) => onChange(raw === \"\" ? null : parseFieldInput(raw, format));\n\n if (def.id === \"rating\") {\n return disabled ? (\n <RatingStars value={value} max={format.options?.ratingMax ?? 5} label={label} />\n ) : (\n <span id={id} className=\"inline-flex\">\n <RatingStars value={value} max={format.options?.ratingMax ?? 5} label={label} onRate={(n) => onChange(n)} />\n </span>\n );\n }\n if (TYPED_NUMBERS.has(def.id)) return <NumberInFormat {...args} />;\n switch (def.editor) {\n // A TIME OF DAY is not this file's: `FieldControl` draws the typed box and its helper\n // (`TypedWordsControl`), never the browser's time control (grids review 3, 2026-09-30).\n case \"email\":\n case \"url\":\n case \"tel\":\n return (\n <BasicInput\n id={id}\n type={def.editor}\n // THE RIGHT KEYBOARD (TYPEFORM-2): @ for an email, the dial pad for a phone, .com for a link.\n inputMode={def.editor}\n {...(ownDetails ? { autoComplete: def.editor } : {})}\n value={text}\n disabled={disabled}\n onChange={(e) => commit(e.target.value)}\n />\n );\n case \"color\":\n return (\n <span className=\"flex items-center gap-2\">\n <BasicInput\n id={`${id}-swatch`}\n type=\"color\"\n aria-label={`${label} — pick a colour`}\n className=\"h-8 w-12 p-1\"\n value={/^#[0-9a-fA-F]{6}$/.test(text) ? text : \"#000000\"}\n disabled={disabled}\n onChange={(e) => commit(e.target.value)}\n />\n <BasicInput id={id} value={text} placeholder=\"#3b82f6\" disabled={disabled} onChange={(e) => commit(e.target.value)} />\n </span>\n );\n case \"textarea\":\n return <BasicTextarea id={id} rows={4} value={text} disabled={disabled} onChange={(e) => commit(e.target.value)} />;\n default:\n return null;\n }\n}\n","\"use client\";\n\n// src/typedDateHelper.tsx — @ai-matrx/records-ui\n//\n// THE SMALL CALENDAR AND CLOCK BESIDE A TYPED DATE — A HELPER THAT NEVER OWNS THE KEYS.\n//\n// 🚨 WHY (grids review 3, 2026-09-30, a BLOCKER). Double-click, Enter or F2 on a date & time cell\n// opened the BROWSER'S OWN picker (`<input type=\"datetime-local\">`): Space dropped its calendar,\n// typing `10/03/2026 1200PM` landed in its segments one at a time and the time was lost, and Enter\n// saved the moment it was pressed — Sep 30, 1:36 AM. A cell opened by typing already worked.\n//\n// THE RULE (Google Sheets and Airtable): every way into a date, a time or a date-and-time editor is\n// ONE plain text box, read ONCE on commit by the one reader (`@ai-matrx/records` `readTypedDate` /\n// `readTypedTime`). Beside it sits this: a calendar (and, for a moment, a list of times) for the\n// person who would rather point. It is a mouse helper only — it takes no focus, it is not in the Tab\n// order, a press in it never blurs the box (so it never commits the cell), and a pick writes WORDS\n// into the box, the same words a person could have typed; the reader still decides.\n\nimport { useState } from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, cn } from \"@ai-matrx/design-system\";\nimport { readTypedDate, readTypedTime, typedDateText, typedTimeText } from \"@ai-matrx/records\";\nimport { personWallNow, usePersonTimeZone } from \"./personTime\";\n\n/** What the helper offers: a calendar, a list of times, or both. */\nexport type DateHelperKind = \"date\" | \"datetime\" | \"time\";\n\nconst WEEK = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\nconst MONTHS = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\n\nfunction pad(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/** The day and the time the box's words read as right now, when they read at all. */\nfunction readBox(text: string, kind: DateHelperKind): { day: string | null; time: { h: number; m: number } | null } {\n if (kind === \"time\") {\n const t = readTypedTime(text);\n if (!t.ok) return { day: null, time: null };\n const [h, m] = t.value.split(\":\").map(Number);\n return { day: null, time: { h: h!, m: m! } };\n }\n const read = readTypedDate(text, { withTime: kind === \"datetime\" });\n if (!read.ok) return { day: null, time: null };\n if (kind === \"datetime\" && read.instant) {\n const at = new Date(read.instant);\n return { day: read.day, time: { h: at.getHours(), m: at.getMinutes() } };\n }\n return { day: read.day, time: null };\n}\n\n/** The words the box takes for a day and a time, in the reader's own order. */\nfunction wordsFor(kind: DateHelperKind, day: string | null, time: { h: number; m: number } | null): string {\n if (kind === \"time\") return time ? typedTimeText(time.h, time.m) : \"\";\n if (!day) return \"\";\n const dayText = typedDateText(day);\n return kind === \"datetime\" && time ? `${dayText} ${typedTimeText(time.h, time.m)}` : dayText;\n}\n\n/** Keeps the pointer from ever taking focus off the text box — the helper never owns the keys. */\nconst keepFocus = { onMouseDown: (e: { preventDefault: () => void }) => e.preventDefault(), tabIndex: -1 } as const;\n\nfunction CalendarGlyph() {\n return (\n <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <rect x=\"3\" y=\"4\" width=\"18\" height=\"18\" rx=\"2\" />\n <path d=\"M16 2v4M8 2v4M3 10h18\" />\n </svg>\n );\n}\nfunction ClockGlyph() {\n return (\n <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 6v6l4 2\" />\n </svg>\n );\n}\n\n/**\n * `onPicked`: a pick that completes the value (a day for a date, a time for a time or a moment) is\n * a finished edit, as in Notion — the host saves and closes. Typing in the box is untouched.\n */\nexport function TypedDateHelper({\n kind,\n text,\n onText,\n label,\n onPicked,\n startOpen = false,\n}: {\n kind: DateHelperKind;\n text: string;\n onText: (text: string) => void;\n label: string;\n onPicked?: (() => void) | undefined;\n /**\n * OPEN FROM THE FIRST FRAME (Arman 2026-10-08: a date took three clicks to reach its calendar).\n * A cell opened by a click, Enter or F2 shows its calendar at once beside the box (Notion,\n * Airtable); the box still holds the keyboard, so typing a date needs no further click. A cell\n * opened by typing keeps it closed — that person is already typing.\n */\n startOpen?: boolean | undefined;\n}) {\n const [open, setOpen] = useState(startOpen);\n const held = readBox(text, kind);\n usePersonTimeZone();\n const today = personWallNow();\n const start = held.day ? new Date(Number(held.day.slice(0, 4)), Number(held.day.slice(5, 7)) - 1, 1) : new Date(today.getFullYear(), today.getMonth(), 1);\n const [month, setMonth] = useState<{ y: number; m: number } | null>(null);\n const shown = month ?? { y: start.getFullYear(), m: start.getMonth() };\n const first = new Date(shown.y, shown.m, 1).getDay();\n const days = new Date(shown.y, shown.m + 1, 0).getDate();\n const cells: Array<number | null> = [...Array.from({ length: first }, () => null), ...Array.from({ length: days }, (_, i) => i + 1)];\n const todayKey = `${today.getFullYear()}-${pad(today.getMonth() + 1)}-${pad(today.getDate())}`;\n const times = Array.from({ length: 48 }, (_, i) => ({ h: Math.floor(i / 2), m: (i % 2) * 30 }));\n const pickDay = (d: number) => {\n const day = `${shown.y}-${pad(shown.m + 1)}-${pad(d)}`;\n onText(wordsFor(kind, day, held.time));\n if (kind === \"date\") {\n setOpen(false);\n onPicked?.();\n }\n };\n const pickTime = (t: { h: number; m: number }) => {\n const day = kind === \"datetime\" ? (held.day ?? todayKey) : null;\n onText(wordsFor(kind, day, t));\n setOpen(false);\n onPicked?.();\n };\n const turn = (by: number) => {\n const at = new Date(shown.y, shown.m + by, 1);\n setMonth({ y: at.getFullYear(), m: at.getMonth() });\n };\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n {...keepFocus}\n data-records-date-helper=\"\"\n aria-label={kind === \"time\" ? `Pick a time for ${label}` : `Pick a date for ${label}`}\n title={kind === \"time\" ? \"Pick a time\" : \"Pick a date\"}\n className=\"inline-flex h-7 w-7 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n {kind === \"time\" ? <ClockGlyph /> : <CalendarGlyph />}\n </button>\n </PopoverTrigger>\n <PopoverContent\n sizing=\"content\"\n align=\"start\"\n className=\"p-2\"\n data-matrx-cell-editor=\"\"\n data-records-date-helper-panel=\"\"\n // THE BOX KEEPS THE KEYBOARD: the helper opens without taking focus and never hands it back\n // somewhere else when it closes.\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex gap-2\">\n {kind === \"time\" ? null : (\n <div className=\"flex flex-col gap-1\" role=\"grid\" aria-label={`${MONTHS[shown.m]} ${shown.y}`}>\n <div className=\"flex items-center justify-between text-xs font-medium\">\n <button type=\"button\" {...keepFocus} aria-label=\"Previous month\" className=\"rounded px-1.5 hover:bg-muted\" onClick={() => turn(-1)}>\n ‹\n </button>\n <span>\n {MONTHS[shown.m]} {shown.y}\n </span>\n <button type=\"button\" {...keepFocus} aria-label=\"Next month\" className=\"rounded px-1.5 hover:bg-muted\" onClick={() => turn(1)}>\n ›\n </button>\n </div>\n <div className=\"grid grid-cols-7 gap-0.5 text-center text-[11px]\">\n {WEEK.map((w) => (\n <span key={w} className=\"text-muted-foreground\">\n {w}\n </span>\n ))}\n {cells.map((d, i) => {\n if (d === null) return <span key={`blank-${i}`} />;\n const key = `${shown.y}-${pad(shown.m + 1)}-${pad(d)}`;\n return (\n <button\n key={key}\n type=\"button\"\n {...keepFocus}\n data-records-date-helper-day={key}\n className={cn(\n \"h-6 w-6 rounded tabular-nums hover:bg-muted\",\n key === held.day ? \"bg-primary text-primary-foreground hover:bg-primary\" : \"\",\n key === todayKey && key !== held.day ? \"ring-1 ring-ring\" : \"\",\n )}\n onClick={() => pickDay(d)}\n >\n {d}\n </button>\n );\n })}\n </div>\n </div>\n )}\n {kind === \"date\" ? null : (\n <div className=\"flex max-h-48 flex-col overflow-y-auto pr-1 text-[11px]\" aria-label=\"Times\">\n {times.map((t) => (\n <button\n key={`${t.h}:${t.m}`}\n type=\"button\"\n {...keepFocus}\n data-records-date-helper-time={`${pad(t.h)}:${pad(t.m)}`}\n className={cn(\n \"whitespace-nowrap rounded px-2 py-0.5 text-left tabular-nums hover:bg-muted\",\n held.time && held.time.h === t.h && held.time.m === t.m ? \"bg-primary text-primary-foreground\" : \"\",\n )}\n onClick={() => pickTime(t)}\n >\n {typedTimeText(t.h, t.m)}\n </button>\n ))}\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","// src/choiceNudge.ts — @ai-matrx/records-ui\n//\n// THE CHOICE NUDGE, READ ONCE PER CLIENT (lane CHOICE-COLUMN-EDIT, 2026-09-27).\n//\n// What a choice cell does with typed words that are not a choice is the Feature Knob\n// `custom/choice_nudge` (`client.choiceNudge()`): ask (the default), always add, or never add.\n// It is the same answer for every cell a client draws, so it is asked ONCE per client — one\n// client is one organization — and every cell after the first reads the cached answer. A door\n// that refuses or is absent answers the knob's own default, `ask`, which is the safe one: the\n// person is asked rather than something being added or refused on their behalf.\n\nimport { useEffect, useState } from \"react\";\nimport type { ChoiceNudge } from \"@ai-matrx/records\";\nimport type { RecordsClient } from \"@ai-matrx/records/core\";\nimport { useOptionalRecordsClient } from \"@ai-matrx/records/react\";\n\nconst asked = new WeakMap<object, Promise<ChoiceNudge>>();\n\n/** The knob for this client, asked once and cached for the life of the client. */\nexport function choiceNudgeOf(client: RecordsClient): Promise<ChoiceNudge> {\n let answer = asked.get(client);\n if (!answer) {\n answer = Promise.resolve()\n .then(() => client.choiceNudge())\n .then(\n (result) => (result.ok ? result.data : \"ask\"),\n () => \"ask\" as const,\n );\n asked.set(client, answer);\n }\n return answer;\n}\n\n/**\n * The knob, for a control that needs it. `null` while it is asked (a control waits rather than\n * deciding on a guess); `ask` when there is no client at all (a public page), since no door can\n * add a choice there anyway.\n */\nexport function useChoiceNudge(enabled = true): ChoiceNudge | null {\n const client = useOptionalRecordsClient();\n const [nudge, setNudge] = useState<ChoiceNudge | null>(null);\n useEffect(() => {\n if (!enabled || !client) return;\n let live = true;\n void choiceNudgeOf(client).then((answer) => {\n if (live) setNudge(answer);\n });\n return () => {\n live = false;\n };\n }, [client, enabled]);\n if (!client) return \"ask\";\n return nudge;\n}\n","\"use client\";\n\n// src/RecordsMount.tsx — @ai-matrx/records-ui\n//\n// THE ONE LINE A HOST ROUTE WRITES. `<RecordsProvider>` from @ai-matrx/records\n// and `<RecordsUiProvider>` from this package are two providers that must be\n// nested in one order, every time — so a route that got the order wrong would\n// fail with \"useRecordsClient was called outside <RecordsProvider>\" at the\n// bottom of a screen nobody was looking at. This mounts both, in the one order\n// that is correct, so a route file stays a mount and nothing more.\n//\n// THE RIGHTS QUESTION — AND THE ANSWER THAT USED TO BE HERE.\n//\n// `storeDecidesRights` returned `{admin: true, comment: true, write: true}` for\n// every non-kernel table, for everybody, on the reasoning that the doors are\n// the authority and a refusal would be shown verbatim when it came. The\n// sixth-pass verdict measured the cost of that reasoning: a colleague at viewer\n// double-clicked a cell, got a live editor, typed a value, pressed Enter, and\n// was told only then that she may not write. \"The permission is right; the\n// screen told her she could.\"\n//\n// It is not a guess any more. The read door has always answered the reader's\n// level on the table and the client now carries it (`Table.your_level`), so\n// this function ASKS instead of assuming, `letTheStoreDecideRights` still means\n// what it says, and a host that binds nothing gets the same honest answer\n// rather than every control absent. Kernel Tables (REC-27) keep their own\n// exclusion: the nine Tables the platform ships are not administered from a\n// person's screen at any level.\n\nimport { useRef, type ReactNode } from \"react\";\nimport type { RecordsActor, RecordsConfig, RecordsDataSource, Table, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider } from \"@ai-matrx/records/react\";\nimport { RecordLabelProvider } from \"./labels\";\n\nimport { NO_RIGHTS, RecordsUiProvider, type RecordsUiHost, type TableRights } from \"./host\";\n\nexport const STORE_DECIDES_REASON =\n \"This host offers exactly what the record store says this person may do: the level comes back with \" +\n \"the table on the read door, so a control they cannot use is never drawn in the first place.\";\n\nexport { KERNEL_REASON } from \"./rights\";\n\n/**\n * DEPRECATED, and kept only so a host that imported it still compiles.\n *\n * It used to answer yes to everything for every non-kernel table. It cannot\n * answer honestly at all, because the honest answer needs a door call and this\n * signature is synchronous — which is exactly why the guess was here. Binding\n * it now would be binding a port that OVERRIDES the store's real answer, so it\n * returns the not-yet-answered set and every caller should simply stop passing\n * a `rights` port: unbound is the honest path (`useTableRights`).\n */\nexport function storeDecidesRights(_table: Table): TableRights {\n return NO_RIGHTS;\n}\n\nexport interface RecordsMountProps {\n /** The store config: the host's session-carrying client, the actor, the organization. */\n config: RecordsConfig;\n /** What this host binds on top — links, toasts, uploads, rights. */\n host?: RecordsUiHost | undefined;\n /**\n * Use `storeDecidesRights` when the host binds no `rights` of its own. Left\n * off, an unbound host gets `NO_RIGHTS` and every administering control is\n * absent with its reason.\n */\n letTheStoreDecideRights?: boolean | undefined;\n children: ReactNode;\n}\n\nexport function RecordsMount({\n config,\n host,\n letTheStoreDecideRights,\n children,\n}: RecordsMountProps) {\n // `letTheStoreDecideRights` means what it says and now needs no port at all:\n // with nothing bound, `useTableRights` asks `custom.my_levels` and draws what\n // the answer allows. A port bound here would OVERRIDE that answer.\n const bound = useShallowStableHost(host);\n void letTheStoreDecideRights;\n return (\n <RecordsProvider config={config}>\n <RecordsUiProvider value={bound}>\n {/* WHAT AN ID IS CALLED. A choice and a relation are stored as the id of\n another record, so every read-only surface needs the same answer to\n \"what is that record called\" — resolved once here rather than once\n per cell, and never drawn as the id itself. */}\n <RecordLabelProvider>{children}</RecordLabelProvider>\n </RecordsUiProvider>\n </RecordsProvider>\n );\n}\n\n/**\n * The actor a signed-in person is. `user` is the store's own word (the closed\n * ACTOR_VOCABULARY is `user` · `agent` · `system`), and AGT-N-4 means an agent\n * acting for this person carries exactly this authority and no other.\n */\n/**\n * THE HOST, AS ONE IDENTITY FOR AS LONG AS ITS PARTS ARE THE SAME (lane RENDER-AUDIT, 2026-09-26).\n *\n * This used to be `{ ...(host ?? {}) }` — a NEW object on every render of the mount — and it is the\n * value of the host context every screen of this package reads (`useRecordsUi`: the table page,\n * the grid, the view bar, every rail). So any render of whatever sits above the mount (a search\n * parameter moving, the organization list arriving, a toast) re-rendered the whole table page and\n * every cell in it, with nothing on the table having changed. Measured on /data with the React\n * profiler hook: 11 host-context renders of `TablePage` during one page load.\n *\n * The host a caller builds is a bag of ports and values; it is the SAME host when every part is the\n * same part. So the previous object is kept until a part changes identity, and a host that builds\n * the bag inline on every render (the common case) costs nothing.\n */\nfunction useShallowStableHost(host: RecordsUiHost | undefined): RecordsUiHost {\n const held = useRef<RecordsUiHost | null>(null);\n const next = host ?? {};\n const previous = held.current;\n if (previous !== null && sameParts(previous, next)) return previous;\n const bound: RecordsUiHost = { ...next };\n held.current = bound;\n return bound;\n}\n\nfunction sameParts(a: RecordsUiHost, b: RecordsUiHost): boolean {\n const aKeys = Object.keys(a) as (keyof RecordsUiHost)[];\n const bKeys = Object.keys(b) as (keyof RecordsUiHost)[];\n if (aKeys.length !== bKeys.length) return false;\n for (const key of aKeys) if (a[key] !== b[key]) return false;\n return true;\n}\n\nexport function personActor(userId: Uuid | null | undefined): RecordsActor {\n return userId ? { actor: \"user\", user_id: userId } : { actor: \"user\" };\n}\n\n/**\n * A supabase-js client AS this package's data seam.\n *\n * `RecordsDataSource` is deliberately a small structural subset of\n * `SupabaseClient` — the package holds no key and opens no connection, the host\n * hands it a client that already carries the person's session.\n *\n * IT IS NOT AN IDENTITY CAST, and it cost a live screen to learn why\n * (2026-09-19, /data's first load): the port's `rpc(fn, args, { schema })`\n * says the schema OUT LOUD, because every door of this store is `custom.<name>`\n * and every door of the trust layer is `iam.<name>`. supabase-js's own\n * `rpc(fn, args, options)` has no `schema` option at all — its third argument is\n * `{ head, get, count }` — so a client passed straight through silently asked\n * its default PostgREST profile and the store answered, correctly and uselessly,\n * \"Could not find the function public.table_kernel_id ... PGRST202\". The schema\n * is chosen the one way supabase-js offers: `client.schema(name).rpc(...)`.\n *\n * `schema(name).from(table)` already agrees structurally and is passed through.\n *\n * `fallbackSchema` is the profile a call that says NOTHING is sent to. No caller\n * in `@ai-matrx/records` omits the option — `callDoor` always says `custom` and\n * `trustDoor` always says `iam` — so it never fires today; it exists so that a\n * call which one day forgets lands on the store rather than silently on\n * `public`. It is a FALLBACK and not the answer: a version of this adapter that\n * sent EVERY door to one fixed schema would route the `iam` trust doors (the\n * external principal, the publish binding) into `custom` and get a PGRST202\n * naming the wrong schema.\n *\n * The cast itself stays HERE, once, where it is explained: a generated\n * `Database` type makes `schema().from().select()` enormous, and a host app that\n * passes its client straight into `config` gets `TS2589: Type instantiation is\n * excessively deep and possibly infinite` in its own build (matrx-frontend,\n * 2026-09-18, on all three campaign routes at once).\n */\n/*\n * ONE DATA SOURCE PER SUPABASE CLIENT (owner, 2026-10-02). The record store's data layer keys its\n * cache by the data source object, so a host that builds this adapter again on every mount (a\n * board tile woken or brought back by Undo) must get the SAME object back for the same client —\n * otherwise every remount is a stranger to the answers the last mount read.\n */\nconst dataSources = new WeakMap<object, Map<string, RecordsDataSource>>();\n\nexport function recordsDataSource(client: object, fallbackSchema = \"custom\"): RecordsDataSource {\n let bySchema = dataSources.get(client);\n if (!bySchema) {\n bySchema = new Map();\n dataSources.set(client, bySchema);\n }\n const held = bySchema.get(fallbackSchema);\n if (held) return held;\n const made = makeRecordsDataSource(client, fallbackSchema);\n bySchema.set(fallbackSchema, made);\n return made;\n}\n\nfunction makeRecordsDataSource(client: object, fallbackSchema: string): RecordsDataSource {\n const supabase = client as unknown as {\n rpc: (fn: string, args: Record<string, unknown>) => PromiseLike<unknown>;\n schema: (name: string) => {\n rpc: (fn: string, args: Record<string, unknown>) => PromiseLike<unknown>;\n from: (table: string) => unknown;\n };\n auth?: { getSession?: () => Promise<{ data?: { session?: unknown } | null }> };\n };\n return {\n // PAGE-BUNDLE: the real adapter opens a table page with one `custom.table_page_bundle` call.\n opensInOneCall: true,\n async rpc(fn, args, options) {\n const schema = options?.schema ?? fallbackSchema;\n // 🚨 NO STORE DOOR LEAVES WITHOUT A PERSON (lane MONITOR-TRIAGE, 2026-10-01). `anon` holds\n // no USAGE on schema `custom`, so a door called with no session can only come back\n // \"42501 permission denied for schema custom\" (HTTP 401) — seven of them per signed-out\n // /data load (inbox, counts, home, portals…), every one a red row in ops.system_error.\n // A `custom` door with no session is answered HERE, with the store's own signed-out\n // sentence and no network call. Other schemas (`iam`, `platform`) serve guests by design\n // and are never short-circuited. A client without `auth` (a server or test seam) is\n // passed straight through.\n if (schema === \"custom\" && supabase.auth?.getSession && !(await hasSession(supabase.auth.getSession))) {\n return { data: null, error: SIGNED_OUT } as Awaited<ReturnType<RecordsDataSource[\"rpc\"]>>;\n }\n const on = supabase.schema(schema);\n return (await on.rpc(fn, args)) as Awaited<ReturnType<RecordsDataSource[\"rpc\"]>>;\n },\n schema(name) {\n return supabase.schema(name) as ReturnType<RecordsDataSource[\"schema\"]>;\n },\n };\n}\n\n/** The read door's own sentence for a call with nobody signed in (`custom.read_records_page`, DOOR-1). */\nconst SIGNED_OUT = {\n code: \"42501\",\n message: \"Nobody is signed in, so there is nothing to read.\",\n hint: \"Sign in, then try again.\",\n details: null,\n} as const;\n\nasync function hasSession(getSession: () => Promise<{ data?: { session?: unknown } | null }>): Promise<boolean> {\n try {\n const answer = await getSession();\n return Boolean(answer?.data?.session);\n } catch {\n // Auth could not say: let the request go and the database's answer stand.\n return true;\n }\n}\n","\"use client\";\n\n// src/DataBindingPicker.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// \"FROM MY DATA\" — ONE PICKER FOR EVERY BINDING. A value that is filled from a person's own table\n// when something runs: an agent variable (matrx-frontend's CustomDataBindingPicker, the first\n// author of this shape and these words) and a workflow input (the studio's Collect Inputs field)\n// bind through the SAME declaration, resolved server-side by the SAME merge-field resolver\n// (aidream `conversation_context.merge_field_bindings`). This file is that picker's portable\n// half: table (every Table the person can open, in every organization), shape (whole table /\n// one record / one field of a record), the record, the field, the row template with clickable\n// placeholders, the row limit and what happens when nothing is found — all by NAME.\n//\n// THE SHAPE IS THE MERGE-FIELD DECLARATION, verbatim (`DataBinding` mirrors @ai-matrx/chat's\n// `CustomDataBinding`): `{kind: \"merge_field\", source: \"record\", semantic_type, table_id,\n// record_id?, field_key?, limit?, transform?: {name: \"list\", template, join?, max?}, missing,\n// override_policy: \"shown_locked\"}`.\n\nimport { useEffect, useMemo } from \"react\";\nimport type { Field, RecordsDataSource, Table, Uuid } from \"@ai-matrx/records\";\nimport { isEntityReferenceConfig } from \"@ai-matrx/records\";\nimport { useFields, useTable } from \"@ai-matrx/records/react\";\nimport { BasicInput, Button, CreatablePicker, cn, type CreatableOption } from \"@ai-matrx/design-system\";\nimport { fieldName } from \"./names\";\nimport { RecordPicker, TablePicker, TableScope, useTablesAnywhere } from \"./TablePickers\";\n\nexport interface DataBinding {\n kind: \"merge_field\";\n source: \"record\";\n semantic_type: \"collection\" | \"reference\" | \"value\";\n table_id: string;\n record_id?: string;\n field_key?: string;\n match?: Record<string, string | number | boolean | null>;\n limit?: number;\n transform?: { name: \"list\"; template: string; join?: string; max?: number };\n missing: \"absent\" | \"block\";\n override_policy: \"shown_locked\";\n}\n\nexport type DataBindingShape = DataBinding[\"semantic_type\"];\n\nexport const DATA_BINDING_SHAPES: { value: DataBindingShape; label: string }[] = [\n { value: \"collection\", label: \"The whole table\" },\n { value: \"reference\", label: \"One record\" },\n { value: \"value\", label: \"One field of a record\" },\n];\n\nexport const DATA_BINDING_MISSING: { value: DataBinding[\"missing\"]; label: string }[] = [\n { value: \"absent\", label: \"Say it's missing\" },\n { value: \"block\", label: \"Stop the run\" },\n];\n\n/** A fresh, empty whole-table binding. */\nexport function emptyDataBinding(): DataBinding {\n return {\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: \"collection\",\n table_id: \"\",\n missing: \"absent\",\n override_policy: \"shown_locked\",\n };\n}\n\n/** True when a value is a merge-field binding (the one shape this picker reads and writes). */\nexport function isDataBinding(value: unknown): value is DataBinding {\n return Boolean(value) && typeof value === \"object\" && (value as { kind?: unknown }).kind === \"merge_field\";\n}\n\n/** Ready to run only when the shape has everything it needs. */\nexport function isCompleteDataBinding(binding: DataBinding): boolean {\n if (!binding.table_id) return false;\n if (binding.semantic_type === \"collection\") return true;\n if (!binding.record_id) return false;\n return binding.semantic_type === \"value\" ? Boolean(binding.field_key) : true;\n}\n\n/** The placeholders one column offers; an entity reference offers its words and its id apart. */\nexport function bindingPlaceholdersFor(field: Field): { token: string; label: string }[] {\n const label = fieldName(field);\n if (isEntityReferenceConfig(field.config)) {\n return [\n { token: `{${field.key}.name}`, label: `${label} · name` },\n { token: `{${field.key}.id}`, label: `${label} · id` },\n ];\n }\n return [{ token: `{${field.key}}`, label }];\n}\n\nconst NAME_LIKE = /(^|_)(name|title|label)$/;\nconst DESCRIPTIVE = /(desc|description|summary|notes?|details?|about|why|purpose|role|category|type|group|status)/;\n\n/** The starting row template: the table's name column, then one or two describing columns. */\nexport function defaultBindingTemplate(table: Pick<Table, \"title_field\"> | null, fields: readonly Field[]): string {\n const first = fields[0];\n if (!first) return \"- {name}\";\n const declared = table?.title_field;\n const title =\n (declared ? fields.find((f) => f.key === declared || f.id === declared) : undefined) ??\n fields.find((f) => NAME_LIKE.test(f.key)) ??\n first;\n const token = (f: Field) => bindingPlaceholdersFor(f)[0]?.token ?? `{${f.key}}`;\n const rest = fields.filter((f) => f.id !== title.id);\n const [a, b] = [...rest.filter((f) => DESCRIPTIVE.test(f.key)), ...rest.filter((f) => !DESCRIPTIVE.test(f.key))];\n if (!a) return `- ${token(title)}`;\n return b ? `- ${token(title)}: ${token(a)} (${token(b)})` : `- ${token(title)}: ${token(a)}`;\n}\n\nexport interface DataBindingPickerProps {\n dataSource: RecordsDataSource;\n /** The signed-in person — every read runs as them. */\n userId: Uuid | null;\n binding: DataBinding;\n onChange: (binding: DataBinding) => void;\n disabled?: boolean;\n /** The host's starting row cap for a whole-table read (a knob the host reads), if any. */\n defaultRowLimit?: number | null;\n}\n\n/** \"From my data\": table → shape → record / field → template → when it's missing. */\nexport function DataBindingPicker({ dataSource, userId, binding, onChange, disabled, defaultRowLimit = null }: DataBindingPickerProps) {\n const tables = useTablesAnywhere(dataSource);\n const tableId = binding.table_id || null;\n const selectTable = (id: string) => {\n if (id === binding.table_id) return;\n onChange({\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: binding.semantic_type,\n table_id: id,\n missing: binding.missing,\n override_policy: \"shown_locked\",\n ...(binding.semantic_type === \"collection\" && defaultRowLimit ? { limit: defaultRowLimit } : {}),\n });\n };\n return (\n <div className=\"flex flex-col gap-2\">\n <TablePicker dataSource={dataSource} value={tableId} onChange={selectTable} disabled={Boolean(disabled)} tables={tables} />\n <TableScope dataSource={dataSource} userId={userId} tableId={tableId} tables={tables}>\n {tableId && (\n <BindingDetails\n tableId={tableId}\n binding={binding}\n onChange={onChange}\n disabled={disabled}\n defaultRowLimit={defaultRowLimit}\n />\n )}\n </TableScope>\n </div>\n );\n}\n\nfunction BindingDetails({\n tableId,\n binding,\n onChange,\n disabled,\n defaultRowLimit,\n}: {\n tableId: string;\n binding: DataBinding;\n onChange: (binding: DataBinding) => void;\n disabled?: boolean | undefined;\n defaultRowLimit: number | null;\n}) {\n const table = useTable(tableId);\n const fields = useFields(tableId);\n const fieldList = useMemo(() => fields.data ?? [], [fields.data]);\n const shape = binding.semantic_type;\n\n // PREFILL: a table or record read starts from the table's own name column + its next ones.\n useEffect(() => {\n if (disabled || shape === \"value\" || binding.transform || fields.loading || fieldList.length === 0) return;\n onChange({\n ...binding,\n transform: {\n name: \"list\",\n template: defaultBindingTemplate(table.data ?? null, fieldList),\n join: \"\\n\",\n ...(shape === \"collection\" && binding.limit !== undefined ? { max: binding.limit } : {}),\n },\n });\n }, [disabled, shape, binding, fields.loading, fieldList, table.data, onChange]);\n\n const selectShape = (next: DataBindingShape) => {\n if (next === shape) return;\n const base: DataBinding = {\n kind: \"merge_field\",\n source: \"record\",\n semantic_type: next,\n table_id: binding.table_id,\n missing: binding.missing,\n override_policy: \"shown_locked\",\n };\n if (next !== \"collection\" && binding.record_id) base.record_id = binding.record_id;\n if (next === \"value\" && binding.field_key) base.field_key = binding.field_key;\n if (next === \"collection\") {\n const limit = binding.limit ?? defaultRowLimit;\n if (limit) base.limit = limit;\n }\n if (next !== \"value\" && binding.transform) {\n base.transform = {\n name: \"list\",\n template: binding.transform.template,\n ...(binding.transform.join !== undefined ? { join: binding.transform.join } : {}),\n ...(next === \"collection\" && base.limit !== undefined ? { max: base.limit } : {}),\n };\n }\n onChange(base);\n };\n\n const fieldOptions: CreatableOption[] = fieldList.map((f) => ({ value: f.key, label: fieldName(f) }));\n const template = binding.transform?.template ?? \"\";\n const setTemplate = (next: string) =>\n onChange({ ...binding, transform: { join: \"\\n\", ...binding.transform, name: \"list\", template: next } });\n\n return (\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap gap-1\" role=\"radiogroup\" aria-label=\"What to read\">\n {DATA_BINDING_SHAPES.map((s) => (\n <Button\n key={s.value}\n type=\"button\"\n size=\"sm\"\n variant={s.value === shape ? \"default\" : \"outline\"}\n role=\"radio\"\n aria-checked={s.value === shape}\n disabled={disabled}\n onClick={() => selectShape(s.value)}\n >\n {s.label}\n </Button>\n ))}\n </div>\n {shape !== \"collection\" && (\n <RecordPicker\n tableId={tableId}\n value={binding.record_id ?? null}\n onChange={(id) => onChange({ ...binding, record_id: id })}\n disabled={Boolean(disabled)}\n />\n )}\n {shape === \"value\" && (\n <CreatablePicker\n value={binding.field_key ?? null}\n options={fieldOptions}\n onSelect={(key) => onChange({ ...binding, field_key: key })}\n placeholder=\"Choose a column\"\n searchPlaceholder=\"Search columns\"\n noun=\"column\"\n loading={fields.loading}\n {...(disabled ? { disabled: true } : {})}\n ariaLabel=\"Column\"\n />\n )}\n {shape !== \"value\" && (\n <div className=\"flex flex-col gap-1\">\n <textarea\n className={cn(\n \"min-h-[3.5rem] w-full rounded-md border border-border bg-background px-2 py-1.5 font-mono text-xs\",\n )}\n aria-label=\"Each row reads as\"\n value={template}\n disabled={disabled}\n onChange={(e) => setTemplate(e.target.value)}\n />\n {!disabled && (\n <div className=\"flex flex-wrap gap-1\">\n {fieldList.flatMap(bindingPlaceholdersFor).map((p) => (\n <Button\n key={p.token}\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n className=\"h-6 px-1.5 text-[11px]\"\n onClick={() => setTemplate(template + p.token)}\n >\n {p.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n )}\n {shape === \"collection\" && (\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n Up to\n <BasicInput\n type=\"number\"\n min={1}\n className=\"h-7 w-20 text-xs\"\n value={binding.limit ?? \"\"}\n disabled={disabled}\n onChange={(e) => {\n const n = Number.parseInt(e.target.value, 10);\n if (!Number.isFinite(n) || n < 1) return;\n onChange({ ...binding, limit: n, ...(binding.transform ? { transform: { ...binding.transform, max: n } } : {}) });\n }}\n />\n rows\n </label>\n )}\n <div className=\"flex flex-wrap items-center gap-1\" role=\"radiogroup\" aria-label=\"If nothing is found\">\n <span className=\"text-xs text-muted-foreground\">If nothing is found</span>\n {DATA_BINDING_MISSING.map((m) => (\n <Button\n key={m.value}\n type=\"button\"\n size=\"sm\"\n variant={m.value === binding.missing ? \"default\" : \"outline\"}\n role=\"radio\"\n aria-checked={m.value === binding.missing}\n disabled={disabled}\n onClick={() => onChange({ ...binding, missing: m.value })}\n >\n {m.label}\n </Button>\n ))}\n </div>\n </div>\n );\n}\n","\"use client\";\n\n// src/PickedSummaries.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// WHAT A PICKER CHOSE, READ BACK IN WORDS. A host that stores a table id, a record id or\n// `{column key: value}` (the workflow studio's step cards first) shows it as the table's name and\n// \"Stock status is Backordered\" — never the id, the key or the JSON. Each one reads through the\n// same doors the pickers use (`TablePickers.tsx`), and a value reads through the store's own\n// `renderValue`, so a choice shows its words, a relation its record's name.\n\nimport type { ReactNode } from \"react\";\nimport type { RecordsDataSource, Uuid } from \"@ai-matrx/records\";\nimport { useFields, useRecord, useTable } from \"@ai-matrx/records/react\";\nimport { RecordLabelProvider, useRecordLabels } from \"./labels\";\nimport { fieldName, recordName } from \"./names\";\nimport { TableScope, useTablesAnywhere } from \"./TablePickers\";\nimport { renderValue } from \"./values\";\n\n/** The chosen table's name, or `—` when it is not one this person can open. */\nexport function TableNameText({ dataSource, tableId }: { dataSource: RecordsDataSource; tableId: string | null }) {\n const tables = useTablesAnywhere(dataSource);\n if (!tableId) return <>—</>;\n if (tables.loading) return <>…</>;\n // A failed read says it failed — never \"—\", which reads as \"no table\".\n if (tables.error) return <>Couldn't load the table's name</>;\n return <>{tables.rows.find((t) => t.table_id === tableId)?.table_name ?? \"—\"}</>;\n}\n\n/** `{column key: value}` as \"Column is value, Other is value\" for one table. */\nexport function ColumnValuesText({\n dataSource,\n userId,\n tableId,\n value,\n}: {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n tableId: string | null;\n value: Record<string, unknown>;\n}) {\n if (!tableId) return <>—</>;\n return (\n <TableScope\n dataSource={dataSource}\n userId={userId}\n tableId={tableId}\n fallback={<>…</>}\n unavailable={<>Couldn't load this table's columns</>}\n >\n <RecordLabelProvider>\n <ColumnValuesWords tableId={tableId} value={value} />\n </RecordLabelProvider>\n </TableScope>\n );\n}\n\nfunction ColumnValuesWords({ tableId, value }: { tableId: string; value: Record<string, unknown> }) {\n const fields = useFields(tableId);\n // A choice is stored by its key; the label resolver reads it back as its words.\n const labels = useRecordLabels(fields.data ?? undefined);\n if (fields.loading) return <>…</>;\n // A failed read says it failed — never \"A removed column is —\", which lies about the table.\n if (fields.error) return <>Couldn't load this table's columns</>;\n const parts: ReactNode[] = [];\n for (const [key, stored] of Object.entries(value)) {\n // The store's own envelope keys (`_source`, `_values`, `_choices`…) ride on a record's\n // document; they are bookkeeping, never a column a person named.\n if (key.startsWith(\"_\")) continue;\n const field = (fields.data ?? []).find((f) => f.key === key);\n if (parts.length) parts.push(<span key={`${key}-sep`}>, </span>);\n parts.push(\n <span key={key}>\n {field ? fieldName(field) : \"A removed column\"} is {field ? renderValue(field, stored, undefined, labels) : \"—\"}\n </span>,\n );\n }\n return parts.length ? <>{parts}</> : <>—</>;\n}\n\n/** One record of a table, read back as its name. */\nexport function RecordNameText({\n dataSource,\n userId,\n tableId,\n recordId,\n}: {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n tableId: string | null;\n recordId: string | null;\n}) {\n if (!tableId || !recordId) return <>—</>;\n return (\n <TableScope\n dataSource={dataSource}\n userId={userId}\n tableId={tableId}\n fallback={<>…</>}\n unavailable={<>Couldn't load this record</>}\n >\n <RecordNameWords tableId={tableId} recordId={recordId} />\n </TableScope>\n );\n}\n\nfunction RecordNameWords({ tableId, recordId }: { tableId: string; recordId: string }) {\n const table = useTable(tableId);\n const record = useRecord(recordId);\n if (record.loading || table.loading) return <>…</>;\n if (record.error) return <>Couldn't load this record</>;\n if (!record.data) return <>A record you cannot open</>;\n return <>{recordName(record.data.document, table.data?.title_field ?? null)}</>;\n}\n","\"use client\";\n\n// src/HeldChangeDecision.tsx — @ai-matrx/records-ui · lane 3 INTEGRATION W1.1 (2026-10-02)\n//\n// APPROVE OR REFUSE A HELD CHANGE — for any host that is not the record pages. A workflow step\n// whose write the organization holds for a person PAUSES its run with the store's wait\n// (`matrx_records.held.held_interrupt_payload`: `held_write` + the `matrx_held_write` marker).\n// The server resumes such a run ONLY once the queue row is decided (`resolve_held_resume`\n// refuses a still-pending one with \"Approve or refuse it on the card first\"), so a host that\n// shows the pause as an ordinary question — a text box — leaves the person with no way through:\n// the W1.1 verifier typed \"Approve\", got a 409, and the run stayed stuck.\n//\n// This is the decision itself: `custom.work_approval_may_decide` decides whether the buttons are\n// drawn at all (a person who may not decide is told so, never shown a dead button), and\n// `custom.work_approval_decide` approves (APPLYING the change, as the person) or refuses. One\n// decision on the one queue row the chat, the table's page and the run page decide too.\n\nimport { useEffect, useState } from \"react\";\nimport type { RecordsDataSource, RecordsError, Uuid } from \"@ai-matrx/records\";\nimport { RecordsProvider, useRecordsClient } from \"@ai-matrx/records/react\";\nimport { Button } from \"@ai-matrx/design-system\";\nimport { personActor } from \"./RecordsMount\";\nimport { RefusalLine } from \"./Refusal\";\n\nexport interface HeldChangeDecisionProps {\n dataSource: RecordsDataSource;\n userId: Uuid | null;\n /** The organization the held change lives in (the marker's `organization_id`). */\n organizationId: Uuid;\n approvalId: Uuid;\n /** Told once the store took the decision; `approved` says which way. */\n onDecided: (approved: boolean) => void;\n}\n\nexport function HeldChangeDecision({ dataSource, userId, organizationId, approvalId, onDecided }: HeldChangeDecisionProps) {\n return (\n <RecordsProvider config={{ dataSource, actor: personActor(userId), organizationId }}>\n <Decision approvalId={approvalId} onDecided={onDecided} />\n </RecordsProvider>\n );\n}\n\nfunction Decision({ approvalId, onDecided }: { approvalId: Uuid; onDecided: (approved: boolean) => void }) {\n const client = useRecordsClient();\n const [may, setMay] = useState<boolean | null>(null);\n const [busy, setBusy] = useState<\"approve\" | \"refuse\" | null>(null);\n const [error, setError] = useState<RecordsError | null>(null);\n\n useEffect(() => {\n let live = true;\n void client.workApprovalMayDecide({ approval_id: approvalId }).then((res) => {\n if (!live) return;\n if (res.ok) setMay(res.data);\n else {\n setMay(false);\n setError(res.error);\n }\n });\n return () => {\n live = false;\n };\n }, [client, approvalId]);\n\n const decide = async (approve: boolean) => {\n setBusy(approve ? \"approve\" : \"refuse\");\n setError(null);\n const res = await client.workApprovalDecide({ approval_id: approvalId, approve });\n setBusy(null);\n if (res.ok) onDecided(approve);\n else setError(res.error);\n };\n\n if (may === null) return <p className=\"text-xs text-muted-foreground\">Checking who can decide…</p>;\n return (\n <div className=\"flex flex-col gap-1.5\">\n {may ? (\n <div className=\"flex gap-2\">\n <Button type=\"button\" size=\"sm\" disabled={busy !== null} onClick={() => void decide(true)}>\n {busy === \"approve\" ? \"Approving…\" : \"Approve\"}\n </Button>\n <Button type=\"button\" size=\"sm\" variant=\"outline\" disabled={busy !== null} onClick={() => void decide(false)}>\n {busy === \"refuse\" ? \"Refusing…\" : \"Refuse\"}\n </Button>\n </div>\n ) : (\n !error && <p className=\"text-xs text-muted-foreground\">An owner or admin of this organization decides this.</p>\n )}\n {error ? <RefusalLine error={error} /> : null}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_design_system","held","import_react","import_records","import_design_system","document","said","import_records","import_records","import_records","import_text_case","document","import_react","import_records","import_design_system","import_react","import_design_system","import_jsx_runtime","import_design_system","import_jsx_runtime","import_design_system","said","import_jsx_runtime","said","nameOf","import_jsx_runtime","refusal","target","id","said","import_react","import_design_system","import_data_table","import_records","import_react","import_core","import_design_system","import_react","import_core","import_core","import_react","import_records","import_design_system","import_jsx_runtime","import_design_system","import_jsx_runtime","document","import_react","import_design_system","import_react","import_records","import_jsx_runtime","asked","import_jsx_runtime","KIT_FORMULA_FUNCTIONS","asked","import_react","import_design_system","import_jsx_runtime","import_react","import_design_system","import_data_table","import_field_formats","import_design_system","import_react","import_react","import_records","import_uuid","import_react","import_design_system","import_jsx_runtime","document","asked","import_jsx_runtime","asked","import_react","import_data_table","import_field_formats","import_records","import_react","import_records","import_design_system","import_react","import_design_system","import_jsx_runtime","shown","import_jsx_runtime","own","import_core","import_react","import_core","import_design_system","import_jsx_runtime","import_field_formats","import_react","import_data_table","import_field_formats","import_design_system","import_jsx_runtime","own","shown","said","import_react","import_design_system","import_react","import_design_system","import_jsx_runtime","import_jsx_runtime","import_records","import_design_system","import_text_case","import_jsx_runtime","own","import_records","i","document","import_records","import_jsx_runtime","document","said","import_jsx_runtime","import_react","import_design_system","import_records","import_react","import_jsx_runtime","shown","said","inner","import_react","import_records","import_design_system","import_jsx_runtime","refusal","said","import_react","import_records","import_jsx_runtime","PREVIEW_GROUPS","refusal","import_react","import_records","import_design_system","import_data_table","import_jsx_runtime","import_records","import_design_system","import_jsx_runtime","import_design_system","import_field_formats","import_jsx_runtime","groups","own","import_text_case","tableName","import_records","import_react","import_design_system","import_data_table","import_records","import_records","import_design_system","import_data_table","import_jsx_runtime","import_jsx_runtime","import_records","import_jsx_runtime","tableRights","written","import_jsx_runtime","said","import_react","import_records","import_design_system","import_jsx_runtime","recordName","own","id","import_react","import_jsx_runtime","import_react","import_design_system","import_field_formats","import_jsx_runtime","import_react","import_design_system","import_records","import_jsx_runtime","shown","import_react","asked","import_jsx_runtime","read","shown","own","refusal","add","import_react","import_jsx_runtime","import_jsx_runtime","own","shown","import_react","import_records","import_design_system","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_design_system","import_jsx_runtime"]}
|