@ai-matrx/records-ui 0.103.7 → 0.103.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../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/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":["\"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 type { RecordsClient } from \"@ai-matrx/records/core\";\n\ntype Answer = { ok: boolean };\n\nconst asked = new WeakMap<object, Map<string, { at: number; answer: Promise<unknown> }>>();\n\nexport function askOnce<T extends Answer>(client: object, key: string, ask: () => Promise<T>, freshMs: number): Promise<T> {\n let held = asked.get(client);\n if (!held) {\n held = new Map();\n asked.set(client, held);\n }\n const now = Date.now();\n const kept = held.get(key);\n if (kept && 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, answer });\n return answer;\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 = asked.get(client);\n if (!held) return;\n for (const key of [...held.keys()]) if (key.startsWith(prefix)) held.delete(key);\n}\n\n/** How long a column's choices are shared between askers: the moment of one table open, never longer. */\nexport const FIELD_OPTIONS_FRESH_MS = 2_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","\"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}\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} />\n </span>\n ) : (\n box\n )}\n {judged === null ? (\n <span data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">Reading {fieldName(field)}&apos;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 }: 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 {...(ownDetails && kind !== \"url\" ? { autoComplete: kind === \"email\" ? \"email\" : \"tel\" } : {})}\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} />;\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 }: 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} />;\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&apos;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 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}: {\n field: Field;\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 onChange(on(choice) ? null : choice.key);\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 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 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 (!lettered || disabled || event.metaKey || event.ctrlKey || event.altKey) return;\n if ((event.target as HTMLElement).tagName === \"INPUT\") 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 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/** 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 undefined;\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, StoreFilter, Table, Uuid } from \"@ai-matrx/records\";\nimport { useMyLevel, useMyLevels } from \"@ai-matrx/records/react\";\nimport type { ReversibleAnnouncement } from \"@ai-matrx/kit/reversible\";\n\nimport { NOT_ANSWERED_YET, whatYouMayDo, whatYouMayDoWithTable, type WhatYouMayDo } from \"./rights\";\nimport type { RecordChatContext } from \"./RecordChat\";\nimport type { EnrichAsk, EnrichOutcome } from \"./Enrich\";\nimport type { FooterPlacement } from \"./presentation\";\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 * A LAYOUT THE HOST DRAWS, beside the package's own four (Grid, Kanban, Calendar,\n * Gallery) in the SAME layout row of every table page. The host owns what it\n * draws; the package owns where it sits, its button, and its address (`?view=<id>`).\n *\n * WHY A PORT: an app with a richer surface for one kind of looking at a table —\n * AI Matrx's spreadsheet-feel Sheet, the older /data grid ported onto the record\n * store — must be a layout of the one table page, never a second page for the\n * same table. It is page-level, not saved onto the view record: the store's\n * layout words are the four the package draws.\n */\nexport interface HostLayout {\n /** The address word (`?view=sheet`). Lowercase; must not be one of the package's own. */\n id: string;\n /** The button's words. */\n label: string;\n /** Draw it for this table, with the question the address asked when there is one. */\n render: (args: {\n tableId: Uuid;\n filter?: StoreFilter | undefined;\n /**\n * Opens the page's own export (CSV, XLSX, copy and transform) — the one export a table has,\n * so a host layout's \"Export this table…\" never needs a second one or a hunt for a button.\n * Absent on a page that draws no export.\n */\n openExport?: (() => void) | undefined;\n /**\n * Where the view's footer sits (lane TABLE-PAGE-CHROME): `sticky` — fill the height given and\n * keep the counts and pages on the bottom edge; `inline` — after the last row.\n */\n footer?: FooterPlacement | undefined;\n /**\n * THE PAGE'S ONE TOOLBAR ROW (lane TABLE-PAGE-CHROME). A host layout with controls of its own\n * (search, columns, sort) draws them INTO this element — never a second bar under the page's.\n * `null`: the row is mounting (draw nothing yet). Absent: no page row, draw in place.\n */\n toolbarSlot?: HTMLElement | null | undefined;\n }) => ReactNode;\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 /** Layouts the host draws beside the package's own. See `HostLayout`. */\n layouts?: HostLayout[];\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 /** 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 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\" | \"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 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 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\n write: \"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 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 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\nimport {\n COLOR_ROTATION,\n STYLE_COLORS,\n parseTableStyle,\n tableStyleIsEmpty,\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 {...(ownDetails && def.editor !== \"url\" ? { autoComplete: def.editor === \"email\" ? \"email\" : \"tel\" } : {})}\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\";\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}: {\n kind: DateHelperKind;\n text: string;\n onText: (text: string) => void;\n label: string;\n onPicked?: (() => void) | undefined;\n}) {\n const [open, setOpen] = useState(false);\n const held = readBox(text, kind);\n const today = new Date();\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 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 APP_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(APP_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 (the cell's own `sm:align-top` is\n * set aside), and thin 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.\n */\nexport const EMBEDDED_PAGE_SIZE = 50;\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":["useEffect","useMemo","useState","RecordsProvider","Button","useCallback","useEffect","useLayoutEffect","useRef","useState","newerKindOf","optionKey","rankTypedMatches","readTypedTime","typedDateText","typedTimeText","useOptionalRecordsClient","BasicInput","BasicTextarea","Badge","Button","Popover","PopoverContent","PopoverTrigger","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","cn","document","newerKindOf","humanizeIdentifier","document","useEffect","useRef","useState","BasicInput","Button","cn","useEffect","useRef","useState","cn","jsx","jsxs","BasicInput","cn","jsx","jsxs","useState","useEffect","useRef","cn","jsx","jsxs","jsxs","jsx","cn","nameOf","Fragment","jsx","jsxs","useState","refusal","useRef","useEffect","target","id","cn","BasicInput","Button","useEffect","useRef","useState","useOptionalRecordsClient","Button","useMemo","jsx","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","isUuidShape","useEffect","useRef","useState","Button","ErrorBox","cn","useOptionalRecordsClient","jsx","jsxs","document","asked","jsx","cn","useOptionalRecordsClient","useState","useEffect","useRef","jsxs","Button","ErrorBox","jsx","createContext","isUuidShape","useState","asked","useRef","useCallback","useEffect","useMemo","jsx","useContext","useCallback","useRef","useState","Button","cn","jsx","jsxs","jsx","jsxs","useOptionalRecordsClient","useState","useEffect","useRef","Button","useMemo","useState","useOptionalRecordsClient","Badge","Button","cn","useState","cn","jsx","jsxs","useState","shown","cn","Fragment","jsx","jsxs","useOptionalRecordsClient","useMemo","useState","Button","own","cn","Badge","useCallback","useEffect","useMemo","useRef","useState","rankTypedMatches","useOptionalRecordsClient","cn","Fragment","jsx","jsxs","useOptionalRecordsClient","useState","useRef","useCallback","useMemo","useEffect","rankTypedMatches","cn","recordName","own","id","useRef","useState","Fragment","jsx","jsxs","newerKindOf","newerKindOf","useEffect","useRef","useState","BasicInput","getFieldFormat","useRef","formatFieldValue","getFieldFormat","cn","jsx","jsxs","own","shown","jsx","jsxs","useState","useRef","useEffect","BasicInput","getFieldFormat","useState","Popover","PopoverContent","PopoverTrigger","cn","jsx","jsxs","shown","useEffect","useState","useOptionalRecordsClient","asked","Fragment","jsx","jsxs","Button","read","readTypedTime","typedTimeText","typedDateText","useRef","useState","useLayoutEffect","jsx","useOptionalRecordsClient","useEffect","BasicInput","jsxs","Fragment","Button","optionKey","shown","own","BasicTextarea","refusal","typedDateText","Popover","PopoverTrigger","PopoverContent","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","useCallback","rankTypedMatches","add","Badge","cn","useRef","jsx","useCallback","useEffect","useMemo","useState","useRecordsClient","Checkbox","cn","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","own","RecordsProvider","useMemo","Button","shown","useEffect","useMemo","useFields","useTable","BasicInput","Button","CreatablePicker","cn","jsx","jsxs","useTable","useFields","useMemo","useEffect","Button","CreatablePicker","cn","BasicInput","useFields","useTable","formatFieldValue","Badge","cn","createContext","useContext","createContext","useContext","useEffect","useState","BasicTextarea","jsx","jsxs","formatPhone","entityRefsOf","Badge","cn","humanizeIdentifier","jsx","jsxs","own","entityRefsOf","cn","Badge","document","sourceArchivedOf","Fragment","jsx","jsxs","document","sourceArchivedOf","Badge","cn","formatPhone","formatFieldValue","Fragment","jsx","jsxs","useFields","useTable","useEffect","useState","RecordsProvider","useRecordsClient","Button","jsx","jsxs","RecordsProvider","useRecordsClient","useState","useEffect","Button"]}
1
+ {"version":3,"sources":["../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/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":["\"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 type { RecordsClient } from \"@ai-matrx/records/core\";\n\ntype Answer = { ok: boolean };\n\nconst asked = new WeakMap<object, Map<string, { at: number; answer: Promise<unknown> }>>();\n\nexport function askOnce<T extends Answer>(client: object, key: string, ask: () => Promise<T>, freshMs: number): Promise<T> {\n let held = asked.get(client);\n if (!held) {\n held = new Map();\n asked.set(client, held);\n }\n const now = Date.now();\n const kept = held.get(key);\n if (kept && 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, answer });\n return answer;\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 = asked.get(client);\n if (!held) return;\n for (const key of [...held.keys()]) if (key.startsWith(prefix)) held.delete(key);\n}\n\n/** How long a column's choices are shared between askers: the moment of one table open, never longer. */\nexport const FIELD_OPTIONS_FRESH_MS = 2_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","\"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}\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} />\n </span>\n ) : (\n box\n )}\n {judged === null ? (\n <span data-records-cell-note=\"\" className=\"text-[10px] text-muted-foreground\">Reading {fieldName(field)}&apos;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 }: 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 {...(ownDetails && kind !== \"url\" ? { autoComplete: kind === \"email\" ? \"email\" : \"tel\" } : {})}\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} />;\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 }: 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} />;\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&apos;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 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}: {\n field: Field;\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 onChange(on(choice) ? null : choice.key);\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 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 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 (!lettered || disabled || event.metaKey || event.ctrlKey || event.altKey) return;\n if ((event.target as HTMLElement).tagName === \"INPUT\") 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 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/** 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 undefined;\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, StoreFilter, 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 { FooterPlacement } from \"./presentation\";\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 * A LAYOUT THE HOST DRAWS, beside the package's own four (Grid, Kanban, Calendar,\n * Gallery) in the SAME layout row of every table page. The host owns what it\n * draws; the package owns where it sits, its button, and its address (`?view=<id>`).\n *\n * WHY A PORT: an app with a richer surface for one kind of looking at a table —\n * AI Matrx's spreadsheet-feel Sheet, the older /data grid ported onto the record\n * store — must be a layout of the one table page, never a second page for the\n * same table. It is page-level, not saved onto the view record: the store's\n * layout words are the four the package draws.\n */\nexport interface HostLayout {\n /** The address word (`?view=sheet`). Lowercase; must not be one of the package's own. */\n id: string;\n /** The button's words. */\n label: string;\n /** Draw it for this table, with the question the address asked when there is one. */\n render: (args: {\n tableId: Uuid;\n filter?: StoreFilter | undefined;\n /**\n * Opens the page's own export (CSV, XLSX, copy and transform) — the one export a table has,\n * so a host layout's \"Export this table…\" never needs a second one or a hunt for a button.\n * Absent on a page that draws no export.\n */\n openExport?: (() => void) | undefined;\n /**\n * Where the view's footer sits (lane TABLE-PAGE-CHROME): `sticky` — fill the height given and\n * keep the counts and pages on the bottom edge; `inline` — after the last row.\n */\n footer?: FooterPlacement | undefined;\n /**\n * THE PAGE'S ONE TOOLBAR ROW (lane TABLE-PAGE-CHROME). A host layout with controls of its own\n * (search, columns, sort) draws them INTO this element — never a second bar under the page's.\n * `null`: the row is mounting (draw nothing yet). Absent: no page row, draw in place.\n */\n toolbarSlot?: HTMLElement | null | undefined;\n }) => ReactNode;\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 /** Layouts the host draws beside the package's own. See `HostLayout`. */\n layouts?: HostLayout[];\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\" | \"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 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 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\n write: \"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 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 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\nimport {\n COLOR_ROTATION,\n STYLE_COLORS,\n parseTableStyle,\n tableStyleIsEmpty,\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 {...(ownDetails && def.editor !== \"url\" ? { autoComplete: def.editor === \"email\" ? \"email\" : \"tel\" } : {})}\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\";\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}: {\n kind: DateHelperKind;\n text: string;\n onText: (text: string) => void;\n label: string;\n onPicked?: (() => void) | undefined;\n}) {\n const [open, setOpen] = useState(false);\n const held = readBox(text, kind);\n const today = new Date();\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 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 APP_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(APP_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 (the cell's own `sm:align-top` is\n * set aside), and thin 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.\n */\nexport const EMBEDDED_PAGE_SIZE = 50;\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":["useEffect","useMemo","useState","RecordsProvider","Button","useCallback","useEffect","useLayoutEffect","useRef","useState","newerKindOf","optionKey","rankTypedMatches","readTypedTime","typedDateText","typedTimeText","useOptionalRecordsClient","BasicInput","BasicTextarea","Badge","Button","Popover","PopoverContent","PopoverTrigger","Select","SelectContent","SelectItem","SelectTrigger","SelectValue","cn","document","newerKindOf","humanizeIdentifier","document","useEffect","useRef","useState","BasicInput","Button","cn","useEffect","useRef","useState","cn","jsx","jsxs","BasicInput","cn","jsx","jsxs","useState","useEffect","useRef","cn","jsx","jsxs","jsxs","jsx","cn","nameOf","Fragment","jsx","jsxs","useState","refusal","useRef","useEffect","target","id","cn","BasicInput","Button","useEffect","useRef","useState","useOptionalRecordsClient","Button","useMemo","jsx","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","isUuidShape","useEffect","useRef","useState","Button","ErrorBox","cn","useOptionalRecordsClient","jsx","jsxs","document","asked","jsx","cn","useOptionalRecordsClient","useState","useEffect","useRef","jsxs","Button","ErrorBox","jsx","createContext","isUuidShape","useState","asked","useRef","useCallback","useEffect","useMemo","jsx","useContext","useCallback","useRef","useState","Button","cn","jsx","jsxs","jsx","jsxs","useOptionalRecordsClient","useState","useEffect","useRef","Button","useMemo","useState","useOptionalRecordsClient","Badge","Button","cn","useState","cn","jsx","jsxs","useState","shown","cn","Fragment","jsx","jsxs","useOptionalRecordsClient","useMemo","useState","Button","own","cn","Badge","useCallback","useEffect","useMemo","useRef","useState","rankTypedMatches","useOptionalRecordsClient","cn","Fragment","jsx","jsxs","useOptionalRecordsClient","useState","useRef","useCallback","useMemo","useEffect","rankTypedMatches","cn","recordName","own","id","useRef","useState","Fragment","jsx","jsxs","newerKindOf","newerKindOf","useEffect","useRef","useState","BasicInput","getFieldFormat","useRef","formatFieldValue","getFieldFormat","cn","jsx","jsxs","own","shown","jsx","jsxs","useState","useRef","useEffect","BasicInput","getFieldFormat","useState","Popover","PopoverContent","PopoverTrigger","cn","jsx","jsxs","shown","useEffect","useState","useOptionalRecordsClient","asked","Fragment","jsx","jsxs","Button","read","readTypedTime","typedTimeText","typedDateText","useRef","useState","useLayoutEffect","jsx","useOptionalRecordsClient","useEffect","BasicInput","jsxs","Fragment","Button","optionKey","shown","own","BasicTextarea","refusal","typedDateText","Popover","PopoverTrigger","PopoverContent","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","useCallback","rankTypedMatches","add","Badge","cn","useRef","jsx","useCallback","useEffect","useMemo","useState","useRecordsClient","Checkbox","cn","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","own","RecordsProvider","useMemo","Button","shown","useEffect","useMemo","useFields","useTable","BasicInput","Button","CreatablePicker","cn","jsx","jsxs","useTable","useFields","useMemo","useEffect","Button","CreatablePicker","cn","BasicInput","useFields","useTable","formatFieldValue","Badge","cn","createContext","useContext","createContext","useContext","useEffect","useState","BasicTextarea","jsx","jsxs","formatPhone","entityRefsOf","Badge","cn","humanizeIdentifier","jsx","jsxs","own","entityRefsOf","cn","Badge","document","sourceArchivedOf","Fragment","jsx","jsxs","document","sourceArchivedOf","Badge","cn","formatPhone","formatFieldValue","Fragment","jsx","jsxs","useFields","useTable","useEffect","useState","RecordsProvider","useRecordsClient","Button","jsx","jsxs","RecordsProvider","useRecordsClient","useState","useEffect","Button"]}