@ai-matrx/records-ui 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -188,6 +188,41 @@ interface RecordsUiHost {
188
188
  * queue that silently died with the tab is the failure this exists to avoid.
189
189
  */
190
190
  captureQueue?: CaptureQueuePort;
191
+ /**
192
+ * OPTIONAL. THE HOST'S OWN SHARE DIALOG (SCR-N-5).
193
+ *
194
+ * This package ships no share dialog, ON PURPOSE, and for the same reason it
195
+ * ships no chat: AI Matrx has exactly ONE sharing surface — matrx-frontend's
196
+ * `features/sharing` ShareModal, with its people picker, its level picker, its
197
+ * grant list and its "who can see this, and why" panel — and a second one here
198
+ * would be a parallel sharing UI within a month. Sharing is the access model's
199
+ * front door, and two front doors is how a platform ends up with two answers
200
+ * to "who can see this".
201
+ *
202
+ * So `ShareControl` draws the BUTTON (which belongs on the record and table
203
+ * screens, beside everything else a person does to a thing) and hands the
204
+ * subject to this port, which returns the host's own dialog.
205
+ *
206
+ * Unbound, the button is ABSENT and `NO_SHARE_REASON` says which port to bind.
207
+ * Never a Share button that opens nothing.
208
+ */
209
+ share?: (subject: ShareSubject) => ReactNode;
210
+ }
211
+ /**
212
+ * What a host's share dialog is being opened ON. A Table is a record in this
213
+ * store (a `custom.record` row whose table is the Table kernel), so ONE subject
214
+ * shape covers both screens and `kind` is what the sentences say, not what the
215
+ * store looks up.
216
+ */
217
+ interface ShareSubject {
218
+ kind: "record" | "table";
219
+ /** The store is keyed (organization_id, id); this package never guesses one. */
220
+ organizationId: Uuid$1;
221
+ subjectId: Uuid$1;
222
+ /** What to call it on screen. Never empty — the id's first eight characters at worst. */
223
+ name: string;
224
+ /** Close the dialog. The control owns the open/closed state, the host owns the dialog. */
225
+ onClose: () => void;
191
226
  }
192
227
  /** One member of the organization, in the words a person reads. */
193
228
  interface OrganizationMember {
@@ -223,6 +258,8 @@ interface PendingCapture {
223
258
  declare const NO_SAVED_VIEWS_REASON: string;
224
259
  /** The sentence a person question shows when no membership port is bound. */
225
260
  declare const NO_MEMBERS_REASON: string;
261
+ /** The sentence shown when no share dialog is bound. */
262
+ declare const NO_SHARE_REASON: string;
226
263
  /** The sentence an attachment question shows when no file store is bound. */
227
264
  declare const NO_UPLOAD_REASON: string;
228
265
  declare function RecordsUiProvider({ value, children }: {
@@ -431,15 +468,19 @@ interface CustomFieldsSectionProps {
431
468
  }
432
469
  declare function CustomFieldsSection({ tableId, entityToken, recordId, title, className, }: CustomFieldsSectionProps): react.JSX.Element | null;
433
470
 
471
+ /** `Day rate` → `day_rate`. Shown, so nothing about it is a surprise. */
472
+ declare function keyFor(label: string): string;
434
473
  interface FieldEditorProps {
435
474
  tableId: Uuid$1;
436
475
  /** The Field being edited. Absent means a new one. */
437
476
  field?: Field | undefined;
438
477
  onSaved?: (() => void) | undefined;
439
478
  onCancel?: (() => void) | undefined;
479
+ /** Called after the store has accepted the removal, so the list can re-read. */
480
+ onRemoved?: (() => void) | undefined;
440
481
  className?: string | undefined;
441
482
  }
442
- declare function FieldEditor({ tableId, field, onSaved, onCancel, className }: FieldEditorProps): react.JSX.Element;
483
+ declare function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }: FieldEditorProps): react.JSX.Element;
443
484
 
444
485
  interface FieldProposalRow {
445
486
  id: string;
@@ -463,9 +504,14 @@ interface TableSettingsProps {
463
504
  proposals?: FieldProposalRow[] | undefined;
464
505
  onAcceptProposal?: ((proposal: FieldProposalRow) => void) | undefined;
465
506
  onRejectProposal?: ((proposal: FieldProposalRow) => void) | undefined;
507
+ /**
508
+ * SCR-3's fourth verb. Called after the store has accepted the delete, so the
509
+ * host can leave a page that is now about a table nobody can open.
510
+ */
511
+ onDeleted?: (() => void) | undefined;
466
512
  className?: string | undefined;
467
513
  }
468
- declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, className, }: TableSettingsProps): react.JSX.Element;
514
+ declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, onDeleted, className, }: TableSettingsProps): react.JSX.Element;
469
515
 
470
516
  interface PeekProps {
471
517
  tableId: Uuid;
@@ -518,16 +564,57 @@ declare function RecordChip({ title, onRemove, className, }: {
518
564
  className?: string | undefined;
519
565
  }): react.JSX.Element;
520
566
 
567
+ /** Answers "what is the record with this id called", for one Field's values. */
568
+ type LabelLookup = (field: Field$1, id: string) => string | null;
569
+ /** Which ids a Field's stored value refers to. */
570
+ declare function idsOf(value: unknown): string[];
571
+ declare function isId(value: unknown): boolean;
572
+ /** True when this Field's values are ids of other records rather than values. */
573
+ declare function pointsAtRecords(field: Field$1): boolean;
574
+ declare function RecordLabelProvider({ children }: {
575
+ children: ReactNode;
576
+ }): react.JSX.Element;
577
+ /**
578
+ * The hook a surface uses: it declares the Fields it is about to draw, and gets
579
+ * back the lookup. Declaring is what makes one request per Field instead of one
580
+ * per cell, and it is why a grid of 200 rows asks the store twice.
581
+ */
582
+ declare function useRecordLabels(fields: readonly Field$1[] | undefined): LabelLookup;
583
+
521
584
  /** The envelope for one key, when the document carries one. */
522
585
  declare function envelopeFor(document: RecordDocument | undefined, key: string): ValueEnvelope | undefined;
523
- declare function renderValue(field: Field, value: unknown, document?: RecordDocument): react.JSX.Element;
524
- /** The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1 says both change the MEANING. */
525
- declare function scalarText(field: Field, value: unknown): string;
586
+ declare function renderValue(field: Field, value: unknown, document?: RecordDocument, labels?: LabelLookup): react.JSX.Element;
587
+ /**
588
+ * The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1
589
+ * says both change the MEANING — and with an id resolved to the NAME of the
590
+ * record it points at.
591
+ *
592
+ * `labels` is the resolver from `RecordLabelProvider`. Without it, an id is
593
+ * drawn as "Loading…" and never as itself: a 36-character identifier in a cell
594
+ * reads like a value, and the 19 September verdict found it in choice cells,
595
+ * relation cells and as every Kanban column heading.
596
+ */
597
+ declare function scalarText(field: Field, value: unknown, labels?: LabelLookup): string;
526
598
  /** The provenance badge a value carries when the store interned a source for it (SCR-27). */
527
599
  declare function ProvenanceBadge({ document, fieldKey }: {
528
600
  document: RecordDocument | undefined;
529
601
  fieldKey: string;
530
602
  }): react.JSX.Element | null;
603
+ /**
604
+ * THE VALUE, AS A COMPONENT, so a cell can resolve the ids it holds.
605
+ *
606
+ * `renderValue` is a plain function called from inside a column's `cell`
607
+ * callback and from a dozen other places; a function cannot ask the resolver
608
+ * for a name, because asking is a hook. Every read-only surface therefore draws
609
+ * through this instead, and the one that needs the raw function (a plain-text
610
+ * export, a chat line) keeps calling `renderValue` with no resolver and says
611
+ * "Loading…" rather than printing an id.
612
+ */
613
+ declare function RecordValue({ field, value, document, }: {
614
+ field: Field;
615
+ value: unknown;
616
+ document?: RecordDocument | undefined;
617
+ }): react.JSX.Element;
531
618
 
532
619
  declare const PARITY_LABEL: Record<ParityFieldType, string>;
533
620
  /** The "made of" sentence the store itself publishes, for the field editor's help text. */
@@ -541,9 +628,40 @@ type EditorKind = ParityFieldType | "relation" | "text" | "number" | "boolean" |
541
628
  * value would draw a different editor for an empty record.
542
629
  */
543
630
  declare function editorKindFor(field: Field): EditorKind;
544
- /** The type word a person sees in a header or a settings row. */
631
+ /**
632
+ * The type word a person sees in a header or a settings row — and it is the
633
+ * SAME word the field panel offers, read from `FIELD_TYPE_CHOICES`, so a column
634
+ * added as "Money" is never described anywhere else as "Currency".
635
+ */
545
636
  declare function fieldTypeLabel(field: Field): string;
546
637
 
638
+ /** The three behaviours that carry no parity type of their own. */
639
+ type PlainFieldType = "text" | "long_text" | "number";
640
+ /** What a person picks in the panel: one of the thirteen, or one of the three. */
641
+ type PickableFieldType = ParityFieldType | PlainFieldType;
642
+ interface FieldTypeChoice {
643
+ id: PickableFieldType;
644
+ /** The word on the menu. */
645
+ label: string;
646
+ /** One line, under the word, saying what it is FOR. Never what it is made of. */
647
+ explanation: string;
648
+ /** The heading it sits under, so sixteen choices read as four short lists. */
649
+ group: "Words" | "Numbers and dates" | "Choices and people" | "Worked out";
650
+ }
651
+ declare const FIELD_TYPE_CHOICES: FieldTypeChoice[];
652
+ declare const FIELD_TYPE_GROUPS: FieldTypeChoice["group"][];
653
+ declare function fieldTypeChoice(id: string): FieldTypeChoice | undefined;
654
+ /** The three that are a plain behaviour rather than one of the thirteen. */
655
+ declare function isPlainFieldType(id: string): id is PlainFieldType;
656
+ /**
657
+ * THE GUARD THIS FILE NEEDS, because the list it explains is generated.
658
+ *
659
+ * Returns the parity types the store ships that nothing here explains. The
660
+ * suite asserts it is empty; a fourteenth type would otherwise reach the menu
661
+ * with a blank line under it and nobody would notice until a person did.
662
+ */
663
+ declare function parityTypesWithNoExplanation(): string[];
664
+
547
665
  /** One Field of a package-owned Table, in the store's own words. */
548
666
  interface SystemFieldSpec {
549
667
  key: string;
@@ -579,6 +697,31 @@ interface UseSystemTableState {
579
697
  }
580
698
  /** The hook every package-owned component opens with. */
581
699
  declare function useSystemTable(spec: SystemTableSpec): UseSystemTableState;
700
+ /**
701
+ * THE VERSION OF THE ONE RECORD BEING EDITED.
702
+ *
703
+ * The read door (`custom.read_records`) answers documents, never versions —
704
+ * deliberately, because a version is a fact about the row and not about what
705
+ * this reader may see. A screen that saves optimistically still needs the
706
+ * version it LOADED, so it reads it here, for the one record it is editing and
707
+ * never for a list, through `custom.io_revisions`.
708
+ *
709
+ * `null` is an honest answer: the save then carries no expected version and is
710
+ * the store's ordinary last-writer-wins write. It is never a guess.
711
+ */
712
+ /** What `useRecordVersion` hands a screen that writes the record more than once. */
713
+ interface TrackedVersion {
714
+ /** The version this screen is writing against, or `null` when none was read. */
715
+ version: number | null;
716
+ /**
717
+ * TELL IT THE STORE MOVED. Every successful write answers the record's NEW
718
+ * version; a screen that does not hand it back here will write against the
719
+ * old one next time and the store will — correctly — refuse it as a conflict
720
+ * with somebody who turns out to be the same person. Measured 2026-09-19:
721
+ * switching a saved view's layout twice in a row did exactly that.
722
+ */
723
+ note: (version: number) => void;
724
+ }
582
725
 
583
726
  /** The four ways one saved view can be looked at (SCR-6). */
584
727
  declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
@@ -1369,6 +1512,18 @@ type DeclareResult = {
1369
1512
  /** `My Sales Pipeline` → `my_sales_pipeline`. A token, never a sentence. */
1370
1513
  declare function tokenFor(name: string): string;
1371
1514
  /** The one Field a Table cannot be declared without: something to call a record. */
1515
+ /**
1516
+ * WHY THE FIRST FIELD IS NOT REQUIRED.
1517
+ *
1518
+ * It was, and the cost showed up the moment the grid could add a row: "New
1519
+ * record" writes an empty record and puts you in the first cell, and the store
1520
+ * correctly refused every one of them — `REC-51: Title is required` — so the
1521
+ * one gesture that makes a grid feel like a grid never worked on a table a
1522
+ * person had just made. A title is what makes a record a CHIP (REC-2), which is
1523
+ * a fact about how it is shown, not a promise it can never be written without;
1524
+ * an organization that wants it demanded says so in the field editor, and the
1525
+ * store then enforces it for everyone.
1526
+ */
1372
1527
  declare const DEFAULT_FIELDS: NewFieldSpec[];
1373
1528
  declare function declareTable(client: RecordsClient, spec: NewTableSpec): Promise<DeclareResult>;
1374
1529
  /** Write Field records for an existing Table. Used by the create path and by import. */
@@ -1380,4 +1535,20 @@ declare function addFields(client: RecordsClient, tableId: Uuid$1, fields: NewFi
1380
1535
  error: RecordsError;
1381
1536
  }>;
1382
1537
 
1383
- export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
1538
+ interface ShareControlProps {
1539
+ kind: ShareSubject["kind"];
1540
+ organizationId: Uuid$1;
1541
+ subjectId: Uuid$1;
1542
+ /** What to call it in the dialog's title. */
1543
+ name?: string | undefined;
1544
+ size?: "sm" | "default" | undefined;
1545
+ variant?: "ghost" | "outline" | "default" | undefined;
1546
+ className?: string | undefined;
1547
+ }
1548
+ /** True when a host has bound a share dialog — so a caller can lay out its row. */
1549
+ declare function useCanShare(): boolean;
1550
+ /** Why there is no Share button here, for anything that asks. */
1551
+ declare function shareUnavailableReason(): string;
1552
+ declare function ShareControl({ kind, organizationId, subjectId, name, size, variant, className, }: ShareControlProps): ReactNode;
1553
+
1554
+ export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, type LabelLookup, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordLabelProvider, RecordValue, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, ShareControl, type ShareControlProps, type ShareSubject, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type TrackedVersion, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, idsOf, isId, isPlainFieldType, isSignatureField, keyFor, laneFor, memberName, parityTypesWithNoExplanation, personActor, personRecordForMember, pointsAtRecords, recordName, recordsDataSource, renderValue, rowName, scalarText, shareUnavailableReason, storeDecidesRights, submissionStamp, tableName, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useRecordLabels, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
package/dist/index.d.ts CHANGED
@@ -188,6 +188,41 @@ interface RecordsUiHost {
188
188
  * queue that silently died with the tab is the failure this exists to avoid.
189
189
  */
190
190
  captureQueue?: CaptureQueuePort;
191
+ /**
192
+ * OPTIONAL. THE HOST'S OWN SHARE DIALOG (SCR-N-5).
193
+ *
194
+ * This package ships no share dialog, ON PURPOSE, and for the same reason it
195
+ * ships no chat: AI Matrx has exactly ONE sharing surface — matrx-frontend's
196
+ * `features/sharing` ShareModal, with its people picker, its level picker, its
197
+ * grant list and its "who can see this, and why" panel — and a second one here
198
+ * would be a parallel sharing UI within a month. Sharing is the access model's
199
+ * front door, and two front doors is how a platform ends up with two answers
200
+ * to "who can see this".
201
+ *
202
+ * So `ShareControl` draws the BUTTON (which belongs on the record and table
203
+ * screens, beside everything else a person does to a thing) and hands the
204
+ * subject to this port, which returns the host's own dialog.
205
+ *
206
+ * Unbound, the button is ABSENT and `NO_SHARE_REASON` says which port to bind.
207
+ * Never a Share button that opens nothing.
208
+ */
209
+ share?: (subject: ShareSubject) => ReactNode;
210
+ }
211
+ /**
212
+ * What a host's share dialog is being opened ON. A Table is a record in this
213
+ * store (a `custom.record` row whose table is the Table kernel), so ONE subject
214
+ * shape covers both screens and `kind` is what the sentences say, not what the
215
+ * store looks up.
216
+ */
217
+ interface ShareSubject {
218
+ kind: "record" | "table";
219
+ /** The store is keyed (organization_id, id); this package never guesses one. */
220
+ organizationId: Uuid$1;
221
+ subjectId: Uuid$1;
222
+ /** What to call it on screen. Never empty — the id's first eight characters at worst. */
223
+ name: string;
224
+ /** Close the dialog. The control owns the open/closed state, the host owns the dialog. */
225
+ onClose: () => void;
191
226
  }
192
227
  /** One member of the organization, in the words a person reads. */
193
228
  interface OrganizationMember {
@@ -223,6 +258,8 @@ interface PendingCapture {
223
258
  declare const NO_SAVED_VIEWS_REASON: string;
224
259
  /** The sentence a person question shows when no membership port is bound. */
225
260
  declare const NO_MEMBERS_REASON: string;
261
+ /** The sentence shown when no share dialog is bound. */
262
+ declare const NO_SHARE_REASON: string;
226
263
  /** The sentence an attachment question shows when no file store is bound. */
227
264
  declare const NO_UPLOAD_REASON: string;
228
265
  declare function RecordsUiProvider({ value, children }: {
@@ -431,15 +468,19 @@ interface CustomFieldsSectionProps {
431
468
  }
432
469
  declare function CustomFieldsSection({ tableId, entityToken, recordId, title, className, }: CustomFieldsSectionProps): react.JSX.Element | null;
433
470
 
471
+ /** `Day rate` → `day_rate`. Shown, so nothing about it is a surprise. */
472
+ declare function keyFor(label: string): string;
434
473
  interface FieldEditorProps {
435
474
  tableId: Uuid$1;
436
475
  /** The Field being edited. Absent means a new one. */
437
476
  field?: Field | undefined;
438
477
  onSaved?: (() => void) | undefined;
439
478
  onCancel?: (() => void) | undefined;
479
+ /** Called after the store has accepted the removal, so the list can re-read. */
480
+ onRemoved?: (() => void) | undefined;
440
481
  className?: string | undefined;
441
482
  }
442
- declare function FieldEditor({ tableId, field, onSaved, onCancel, className }: FieldEditorProps): react.JSX.Element;
483
+ declare function FieldEditor({ tableId, field, onSaved, onCancel, onRemoved, className }: FieldEditorProps): react.JSX.Element;
443
484
 
444
485
  interface FieldProposalRow {
445
486
  id: string;
@@ -463,9 +504,14 @@ interface TableSettingsProps {
463
504
  proposals?: FieldProposalRow[] | undefined;
464
505
  onAcceptProposal?: ((proposal: FieldProposalRow) => void) | undefined;
465
506
  onRejectProposal?: ((proposal: FieldProposalRow) => void) | undefined;
507
+ /**
508
+ * SCR-3's fourth verb. Called after the store has accepted the delete, so the
509
+ * host can leave a page that is now about a table nobody can open.
510
+ */
511
+ onDeleted?: (() => void) | undefined;
466
512
  className?: string | undefined;
467
513
  }
468
- declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, className, }: TableSettingsProps): react.JSX.Element;
514
+ declare function TableSettings({ tableId, proposals, onAcceptProposal, onRejectProposal, onDeleted, className, }: TableSettingsProps): react.JSX.Element;
469
515
 
470
516
  interface PeekProps {
471
517
  tableId: Uuid;
@@ -518,16 +564,57 @@ declare function RecordChip({ title, onRemove, className, }: {
518
564
  className?: string | undefined;
519
565
  }): react.JSX.Element;
520
566
 
567
+ /** Answers "what is the record with this id called", for one Field's values. */
568
+ type LabelLookup = (field: Field$1, id: string) => string | null;
569
+ /** Which ids a Field's stored value refers to. */
570
+ declare function idsOf(value: unknown): string[];
571
+ declare function isId(value: unknown): boolean;
572
+ /** True when this Field's values are ids of other records rather than values. */
573
+ declare function pointsAtRecords(field: Field$1): boolean;
574
+ declare function RecordLabelProvider({ children }: {
575
+ children: ReactNode;
576
+ }): react.JSX.Element;
577
+ /**
578
+ * The hook a surface uses: it declares the Fields it is about to draw, and gets
579
+ * back the lookup. Declaring is what makes one request per Field instead of one
580
+ * per cell, and it is why a grid of 200 rows asks the store twice.
581
+ */
582
+ declare function useRecordLabels(fields: readonly Field$1[] | undefined): LabelLookup;
583
+
521
584
  /** The envelope for one key, when the document carries one. */
522
585
  declare function envelopeFor(document: RecordDocument | undefined, key: string): ValueEnvelope | undefined;
523
- declare function renderValue(field: Field, value: unknown, document?: RecordDocument): react.JSX.Element;
524
- /** The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1 says both change the MEANING. */
525
- declare function scalarText(field: Field, value: unknown): string;
586
+ declare function renderValue(field: Field, value: unknown, document?: RecordDocument, labels?: LabelLookup): react.JSX.Element;
587
+ /**
588
+ * The text of one scalar, with the Field's UNIT and FORMAT applied — FLD-N-1
589
+ * says both change the MEANING — and with an id resolved to the NAME of the
590
+ * record it points at.
591
+ *
592
+ * `labels` is the resolver from `RecordLabelProvider`. Without it, an id is
593
+ * drawn as "Loading…" and never as itself: a 36-character identifier in a cell
594
+ * reads like a value, and the 19 September verdict found it in choice cells,
595
+ * relation cells and as every Kanban column heading.
596
+ */
597
+ declare function scalarText(field: Field, value: unknown, labels?: LabelLookup): string;
526
598
  /** The provenance badge a value carries when the store interned a source for it (SCR-27). */
527
599
  declare function ProvenanceBadge({ document, fieldKey }: {
528
600
  document: RecordDocument | undefined;
529
601
  fieldKey: string;
530
602
  }): react.JSX.Element | null;
603
+ /**
604
+ * THE VALUE, AS A COMPONENT, so a cell can resolve the ids it holds.
605
+ *
606
+ * `renderValue` is a plain function called from inside a column's `cell`
607
+ * callback and from a dozen other places; a function cannot ask the resolver
608
+ * for a name, because asking is a hook. Every read-only surface therefore draws
609
+ * through this instead, and the one that needs the raw function (a plain-text
610
+ * export, a chat line) keeps calling `renderValue` with no resolver and says
611
+ * "Loading…" rather than printing an id.
612
+ */
613
+ declare function RecordValue({ field, value, document, }: {
614
+ field: Field;
615
+ value: unknown;
616
+ document?: RecordDocument | undefined;
617
+ }): react.JSX.Element;
531
618
 
532
619
  declare const PARITY_LABEL: Record<ParityFieldType, string>;
533
620
  /** The "made of" sentence the store itself publishes, for the field editor's help text. */
@@ -541,9 +628,40 @@ type EditorKind = ParityFieldType | "relation" | "text" | "number" | "boolean" |
541
628
  * value would draw a different editor for an empty record.
542
629
  */
543
630
  declare function editorKindFor(field: Field): EditorKind;
544
- /** The type word a person sees in a header or a settings row. */
631
+ /**
632
+ * The type word a person sees in a header or a settings row — and it is the
633
+ * SAME word the field panel offers, read from `FIELD_TYPE_CHOICES`, so a column
634
+ * added as "Money" is never described anywhere else as "Currency".
635
+ */
545
636
  declare function fieldTypeLabel(field: Field): string;
546
637
 
638
+ /** The three behaviours that carry no parity type of their own. */
639
+ type PlainFieldType = "text" | "long_text" | "number";
640
+ /** What a person picks in the panel: one of the thirteen, or one of the three. */
641
+ type PickableFieldType = ParityFieldType | PlainFieldType;
642
+ interface FieldTypeChoice {
643
+ id: PickableFieldType;
644
+ /** The word on the menu. */
645
+ label: string;
646
+ /** One line, under the word, saying what it is FOR. Never what it is made of. */
647
+ explanation: string;
648
+ /** The heading it sits under, so sixteen choices read as four short lists. */
649
+ group: "Words" | "Numbers and dates" | "Choices and people" | "Worked out";
650
+ }
651
+ declare const FIELD_TYPE_CHOICES: FieldTypeChoice[];
652
+ declare const FIELD_TYPE_GROUPS: FieldTypeChoice["group"][];
653
+ declare function fieldTypeChoice(id: string): FieldTypeChoice | undefined;
654
+ /** The three that are a plain behaviour rather than one of the thirteen. */
655
+ declare function isPlainFieldType(id: string): id is PlainFieldType;
656
+ /**
657
+ * THE GUARD THIS FILE NEEDS, because the list it explains is generated.
658
+ *
659
+ * Returns the parity types the store ships that nothing here explains. The
660
+ * suite asserts it is empty; a fourteenth type would otherwise reach the menu
661
+ * with a blank line under it and nobody would notice until a person did.
662
+ */
663
+ declare function parityTypesWithNoExplanation(): string[];
664
+
547
665
  /** One Field of a package-owned Table, in the store's own words. */
548
666
  interface SystemFieldSpec {
549
667
  key: string;
@@ -579,6 +697,31 @@ interface UseSystemTableState {
579
697
  }
580
698
  /** The hook every package-owned component opens with. */
581
699
  declare function useSystemTable(spec: SystemTableSpec): UseSystemTableState;
700
+ /**
701
+ * THE VERSION OF THE ONE RECORD BEING EDITED.
702
+ *
703
+ * The read door (`custom.read_records`) answers documents, never versions —
704
+ * deliberately, because a version is a fact about the row and not about what
705
+ * this reader may see. A screen that saves optimistically still needs the
706
+ * version it LOADED, so it reads it here, for the one record it is editing and
707
+ * never for a list, through `custom.io_revisions`.
708
+ *
709
+ * `null` is an honest answer: the save then carries no expected version and is
710
+ * the store's ordinary last-writer-wins write. It is never a guess.
711
+ */
712
+ /** What `useRecordVersion` hands a screen that writes the record more than once. */
713
+ interface TrackedVersion {
714
+ /** The version this screen is writing against, or `null` when none was read. */
715
+ version: number | null;
716
+ /**
717
+ * TELL IT THE STORE MOVED. Every successful write answers the record's NEW
718
+ * version; a screen that does not hand it back here will write against the
719
+ * old one next time and the store will — correctly — refuse it as a conflict
720
+ * with somebody who turns out to be the same person. Measured 2026-09-19:
721
+ * switching a saved view's layout twice in a row did exactly that.
722
+ */
723
+ note: (version: number) => void;
724
+ }
582
725
 
583
726
  /** The four ways one saved view can be looked at (SCR-6). */
584
727
  declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
@@ -1369,6 +1512,18 @@ type DeclareResult = {
1369
1512
  /** `My Sales Pipeline` → `my_sales_pipeline`. A token, never a sentence. */
1370
1513
  declare function tokenFor(name: string): string;
1371
1514
  /** The one Field a Table cannot be declared without: something to call a record. */
1515
+ /**
1516
+ * WHY THE FIRST FIELD IS NOT REQUIRED.
1517
+ *
1518
+ * It was, and the cost showed up the moment the grid could add a row: "New
1519
+ * record" writes an empty record and puts you in the first cell, and the store
1520
+ * correctly refused every one of them — `REC-51: Title is required` — so the
1521
+ * one gesture that makes a grid feel like a grid never worked on a table a
1522
+ * person had just made. A title is what makes a record a CHIP (REC-2), which is
1523
+ * a fact about how it is shown, not a promise it can never be written without;
1524
+ * an organization that wants it demanded says so in the field editor, and the
1525
+ * store then enforces it for everyone.
1526
+ */
1372
1527
  declare const DEFAULT_FIELDS: NewFieldSpec[];
1373
1528
  declare function declareTable(client: RecordsClient, spec: NewTableSpec): Promise<DeclareResult>;
1374
1529
  /** Write Field records for an existing Table. Used by the create path and by import. */
@@ -1380,4 +1535,20 @@ declare function addFields(client: RecordsClient, tableId: Uuid$1, fields: NewFi
1380
1535
  error: RecordsError;
1381
1536
  }>;
1382
1537
 
1383
- export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, isSignatureField, laneFor, memberName, personActor, personRecordForMember, recordName, recordsDataSource, renderValue, rowName, scalarText, storeDecidesRights, submissionStamp, tableName, tokenFor, useEmbedHandshake, useGridEditing, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };
1538
+ interface ShareControlProps {
1539
+ kind: ShareSubject["kind"];
1540
+ organizationId: Uuid$1;
1541
+ subjectId: Uuid$1;
1542
+ /** What to call it in the dialog's title. */
1543
+ name?: string | undefined;
1544
+ size?: "sm" | "default" | undefined;
1545
+ variant?: "ghost" | "outline" | "default" | undefined;
1546
+ className?: string | undefined;
1547
+ }
1548
+ /** True when a host has bound a share dialog — so a caller can lay out its row. */
1549
+ declare function useCanShare(): boolean;
1550
+ /** Why there is no Share button here, for anything that asks. */
1551
+ declare function shareUnavailableReason(): string;
1552
+ declare function ShareControl({ kind, organizationId, subjectId, name, size, variant, className, }: ShareControlProps): ReactNode;
1553
+
1554
+ export { ACTION_KINDS, ACTION_TABLE, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartKind, type ChartSpec, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DASHBOARD_TABLE, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DashboardSpec, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FORM_TABLE, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormTheme, Grid, GridCell, type GridEditing, type GridProps, HistoryPanel, type HistoryPanelProps, IN_MEMORY_QUEUE_REASON, ImportWizard, type ImportWizardProps, KERNEL_REASON, LANE_EMPTY, LANE_TITLE, LAYOUT_FIELD_KIND, LAYOUT_LABEL, LAYOUT_NEEDS, LAYOUT_NO_FIELD, type LabelLookup, NO_CHAT_REASON, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, PortalShell, type PortalShellProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type QueuedAction, type QueuedActionSpec, RecordChat, type RecordChatContext, type RecordChatEntry, type RecordChatProps, type RecordChatWithheld, RecordChip, RecordForm, type RecordFormProps, RecordLabelProvider, RecordValue, RecordsMount, type RecordsMountProps, type RecordsUiHost, RecordsUiProvider, RefusalLine, RefusalNotice, RelationPicker, type RelationPickerProps, SERIES_COLORS, STORE_DECIDES_REASON, type SavedDashboard, type SavedForm, type SavedView, type SavedViewSpec, ShareControl, type ShareControlProps, type ShareSubject, SignBlock, type SignBlockProps, type SystemFieldSpec, type SystemTableSpec, TABLE_LANES, TABLE_NOT_REACHABLE, type TableLane, TablePage, type TablePageProps, type TableRights, TableSettings, type TableSettingsProps, TablesHome, type TablesHomeProps, type TrackedVersion, type UseSystemTableState, VIEW_LAYOUTS, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, actionDocument, addFields, bodyForReading, bodyFromKeys, columnForField, dashboardDocument, dashboardFromRecord, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDocument, formFromRecord, groupLabel, humanize, idsOf, isId, isPlainFieldType, isSignatureField, keyFor, laneFor, memberName, parityTypesWithNoExplanation, personActor, personRecordForMember, pointsAtRecords, recordName, recordsDataSource, renderValue, rowName, scalarText, shareUnavailableReason, storeDecidesRights, submissionStamp, tableName, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useRecordLabels, useRecordsUi, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument };