@ai-matrx/records-ui 0.28.0 → 0.30.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
@@ -5,7 +5,7 @@ import { Uuid, Field as Field$1, ReadRow as ReadRow$1 } from '@ai-matrx/records/
5
5
  import { RecordsClient } from '@ai-matrx/records/core';
6
6
  import { FieldFormatConfig } from '@ai-matrx/design-system/field-formats';
7
7
  import { MatrxColumnDef } from '@ai-matrx/design-system/data-table/types';
8
- import { TableStyle, ChoiceColorLookup } from '@ai-matrx/design-system/data-table';
8
+ import { TableStyle, GroupAggregateSpec, GroupOrder, ChoiceColorLookup } from '@ai-matrx/design-system/data-table';
9
9
 
10
10
  /** The six things a person does to a record or a table, as the screens offer them. */
11
11
  type Capability = "read" | "comment" | "write" | "remove" | "share" | "structure";
@@ -649,6 +649,33 @@ declare function RefusalLine({ error, className }: {
649
649
  * has ever styled still shows `$1,250.50` and `45%`.
650
650
  */
651
651
 
652
+ /**
653
+ * SECTIONS BY A FIELD — the view's own grouping.
654
+ *
655
+ * `field` is a Field KEY, exactly like `frozen` and the keys of `formats`,
656
+ * because a view is written against the Table's declaration and never against
657
+ * whatever id a screen happened to build its columns with.
658
+ *
659
+ * `aggregates` is keyed by Field key too, and `collapsed` holds the data
660
+ * table's own group keys (`s:Blocked`, `n:3`, `empty`), which is what the
661
+ * primitive emits and the only thing that survives a value rendering the same
662
+ * text as another.
663
+ *
664
+ * NOTHING HERE IS EVER CALLED `valueOf`, `toString` or `hasOwnProperty`: every
665
+ * object in JavaScript already has all three, so an optional field by one of
666
+ * those names is NEVER absent and a `config.valueOf ? … : …` check silently
667
+ * reads `Object.prototype`. It cost the primitive a whole grouping once.
668
+ */
669
+ type GridGrouping = {
670
+ /** The Field key whose value makes the sections. */
671
+ field: string;
672
+ /** Per-Field-key subtotal on every section header. */
673
+ aggregates?: Record<string, GroupAggregateSpec>;
674
+ /** Section order. The primitive's default is `value-asc`; blanks sort last. */
675
+ order?: GroupOrder;
676
+ /** The sections this view keeps shut, by the primitive's own group key. */
677
+ collapsed?: string[];
678
+ };
652
679
  /** Everything a view says about how its table LOOKS. */
653
680
  type GridPresentation = {
654
681
  /** Color-by-a-column, rules and manual highlights. */
@@ -662,10 +689,29 @@ type GridPresentation = {
662
689
  * guessed offset.
663
690
  */
664
691
  frozen?: string[];
692
+ /** Collapsible sections by one Field, with subtotals on each header. */
693
+ grouping?: GridGrouping;
694
+ /**
695
+ * The width a person dragged a column to, by Field key. SPARSE on purpose —
696
+ * a view saved before widths existed carries none and still parses, and a
697
+ * column nobody resized is left to the table's own measurement.
698
+ */
699
+ widths?: Record<string, number>;
700
+ /** The body row height this view remembers, in px. */
701
+ rowHeight?: number;
665
702
  };
666
703
  declare const EMPTY_PRESENTATION: GridPresentation;
667
704
  /** A frozen column needs a known width, or the table declines to freeze at all. */
668
705
  declare const FROZEN_COLUMN_WIDTH = 200;
706
+ /**
707
+ * WHAT A ROW HEIGHT IS ALLOWED TO BE. Below the floor the text is clipped and
708
+ * no editor fits; above the ceiling one record fills the screen. A view asking
709
+ * for anything outside it is DROPPED rather than obeyed, because a saved look
710
+ * must not be able to make a table unreadable — and the Fields' own heights
711
+ * still draw, which is the tolerant half.
712
+ */
713
+ declare const MIN_ROW_HEIGHT = 24;
714
+ declare const MAX_ROW_HEIGHT = 96;
669
715
  /**
670
716
  * Read a presentation out of whatever the view record holds — an object, or the
671
717
  * JSON string a text field stores.
@@ -737,9 +783,26 @@ interface GridProps {
737
783
  * override, never the only thing that makes a column readable.
738
784
  */
739
785
  presentation?: GridPresentation | undefined;
786
+ /**
787
+ * THE LOOK, WRITTEN BACK. Called with the WHOLE next look when the person
788
+ * changes one on the table itself — picks a column to group by, shuts a
789
+ * section, drags a column wider.
790
+ *
791
+ * It is the same door every other view change already uses: `ViewSwitcher`
792
+ * folds it into its `onViewChange` patch and `TablePage` writes that patch
793
+ * onto the view record with `client.recordUpdate`, carrying the version it
794
+ * read. The Grid has no view id and must not grow one — a component that
795
+ * wrote to a record it was never told about would be a second, parallel way
796
+ * to save a view.
797
+ *
798
+ * UNBOUND, NOTHING IS DEAD. A host that binds no door still gets grouping,
799
+ * collapsing and resizing for this visit — they are held in the grid's own
800
+ * state — they are simply not remembered.
801
+ */
802
+ onPresentationChange?: ((next: GridPresentation) => void) | undefined;
740
803
  className?: string | undefined;
741
804
  }
742
- declare function Grid({ tableId, pageSize, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, className, }: GridProps): react.JSX.Element;
805
+ declare function Grid({ tableId, pageSize, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, onPresentationChange, className, }: GridProps): react.JSX.Element;
743
806
  /**
744
807
  * One Field becomes one column. The header is the Field's own NAME — never its
745
808
  * key (`names.ts`) — and the cell is the value, rendered by its parity type and
@@ -2165,4 +2228,4 @@ declare function useCanShare(): boolean;
2165
2228
  declare function shareUnavailableReason(): string;
2166
2229
  declare function ShareControl({ kind, organizationId, subjectId, name, may, size, variant, className, }: ShareControlProps): ReactNode;
2167
2230
 
2168
- export { ACTION_KINDS, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type Capability, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartConfig, ChartFrame, type ChartKind, ChartLegendContent, type ChartSpec, ChartTooltipContent, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, EMPTY_PRESENTATION, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FROZEN_COLUMN_WIDTH, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormSubmitOutcome, type FormTheme, FormsPanel, type FormsPanelProps, Grid, GridCell, type GridEditing, type GridPresentation, 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, LEVEL_WORD, type LabelLookup, MACHINE_IDENTITY, NOT_ANSWERED_YET, NO_CHAT_REASON, NO_COLUMNS_WHY, NO_COLUMNS_YET, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_OPEN_RECORDS_REASON, NO_REASK_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OpenRecordsAsk, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, type PlainRefusal, type PortalAnswer, PortalCardView, type PortalCardViewProps, PortalShell, type PortalShellProps, PortalsPanel, type PortalsPanelProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type ReaskContext, 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, SubscriptionsPanel, type SubscriptionsPanelProps, 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_NOT_SAVED_YET, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, type WhatYouMayDo, addFields, blockFromSpec, bodyForReading, bodyFromKeys, colorFromTheValue, columnForField, currencyCodeFor, dashboardDeclareArgs, dashboardFromSummary, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldDeclarationFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDeclareArgs, formFromSummary, formPresentation, formatForField, groupLabel, hintForAPerson, hintIsMachineIdentity, humanize, idsOf, isId, isMachineIdentity, isPlainFieldType, isSignatureField, keyFor, laneFor, machineIdentityIn, memberName, parityTypesWithNoExplanation, parseGridPresentation, personActor, personRecordForMember, pointsAtRecords, presentationDocument, presentationIsEmpty, previewLine, recordName, recordsDataSource, refusalForAPerson, refusalLineForAPerson, renderValue, revokeConsequence, rowName, scalarText, shareUnavailableReason, specFromBlock, storeDecidesRights, submissionStamp, tableName, tableRightsAt, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useMeasuredWidth, useRecordLabels, useRecordRights, useRecordsUi, useRowRights, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument, whatIsMissing, whatYouMayDo, whatYouMayDoWithTable };
2231
+ export { ACTION_KINDS, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type Capability, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartConfig, ChartFrame, type ChartKind, ChartLegendContent, type ChartSpec, ChartTooltipContent, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, EMPTY_PRESENTATION, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FROZEN_COLUMN_WIDTH, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormSubmitOutcome, type FormTheme, FormsPanel, type FormsPanelProps, Grid, GridCell, type GridEditing, type GridGrouping, type GridPresentation, 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, LEVEL_WORD, type LabelLookup, MACHINE_IDENTITY, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT, NOT_ANSWERED_YET, NO_CHAT_REASON, NO_COLUMNS_WHY, NO_COLUMNS_YET, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_OPEN_RECORDS_REASON, NO_REASK_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OpenRecordsAsk, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, type PlainRefusal, type PortalAnswer, PortalCardView, type PortalCardViewProps, PortalShell, type PortalShellProps, PortalsPanel, type PortalsPanelProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type ReaskContext, 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, SubscriptionsPanel, type SubscriptionsPanelProps, 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_NOT_SAVED_YET, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, type WhatYouMayDo, addFields, blockFromSpec, bodyForReading, bodyFromKeys, colorFromTheValue, columnForField, currencyCodeFor, dashboardDeclareArgs, dashboardFromSummary, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldDeclarationFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDeclareArgs, formFromSummary, formPresentation, formatForField, groupLabel, hintForAPerson, hintIsMachineIdentity, humanize, idsOf, isId, isMachineIdentity, isPlainFieldType, isSignatureField, keyFor, laneFor, machineIdentityIn, memberName, parityTypesWithNoExplanation, parseGridPresentation, personActor, personRecordForMember, pointsAtRecords, presentationDocument, presentationIsEmpty, previewLine, recordName, recordsDataSource, refusalForAPerson, refusalLineForAPerson, renderValue, revokeConsequence, rowName, scalarText, shareUnavailableReason, specFromBlock, storeDecidesRights, submissionStamp, tableName, tableRightsAt, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useMeasuredWidth, useRecordLabels, useRecordRights, useRecordsUi, useRowRights, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument, whatIsMissing, whatYouMayDo, whatYouMayDoWithTable };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import { Uuid, Field as Field$1, ReadRow as ReadRow$1 } from '@ai-matrx/records/
5
5
  import { RecordsClient } from '@ai-matrx/records/core';
6
6
  import { FieldFormatConfig } from '@ai-matrx/design-system/field-formats';
7
7
  import { MatrxColumnDef } from '@ai-matrx/design-system/data-table/types';
8
- import { TableStyle, ChoiceColorLookup } from '@ai-matrx/design-system/data-table';
8
+ import { TableStyle, GroupAggregateSpec, GroupOrder, ChoiceColorLookup } from '@ai-matrx/design-system/data-table';
9
9
 
10
10
  /** The six things a person does to a record or a table, as the screens offer them. */
11
11
  type Capability = "read" | "comment" | "write" | "remove" | "share" | "structure";
@@ -649,6 +649,33 @@ declare function RefusalLine({ error, className }: {
649
649
  * has ever styled still shows `$1,250.50` and `45%`.
650
650
  */
651
651
 
652
+ /**
653
+ * SECTIONS BY A FIELD — the view's own grouping.
654
+ *
655
+ * `field` is a Field KEY, exactly like `frozen` and the keys of `formats`,
656
+ * because a view is written against the Table's declaration and never against
657
+ * whatever id a screen happened to build its columns with.
658
+ *
659
+ * `aggregates` is keyed by Field key too, and `collapsed` holds the data
660
+ * table's own group keys (`s:Blocked`, `n:3`, `empty`), which is what the
661
+ * primitive emits and the only thing that survives a value rendering the same
662
+ * text as another.
663
+ *
664
+ * NOTHING HERE IS EVER CALLED `valueOf`, `toString` or `hasOwnProperty`: every
665
+ * object in JavaScript already has all three, so an optional field by one of
666
+ * those names is NEVER absent and a `config.valueOf ? … : …` check silently
667
+ * reads `Object.prototype`. It cost the primitive a whole grouping once.
668
+ */
669
+ type GridGrouping = {
670
+ /** The Field key whose value makes the sections. */
671
+ field: string;
672
+ /** Per-Field-key subtotal on every section header. */
673
+ aggregates?: Record<string, GroupAggregateSpec>;
674
+ /** Section order. The primitive's default is `value-asc`; blanks sort last. */
675
+ order?: GroupOrder;
676
+ /** The sections this view keeps shut, by the primitive's own group key. */
677
+ collapsed?: string[];
678
+ };
652
679
  /** Everything a view says about how its table LOOKS. */
653
680
  type GridPresentation = {
654
681
  /** Color-by-a-column, rules and manual highlights. */
@@ -662,10 +689,29 @@ type GridPresentation = {
662
689
  * guessed offset.
663
690
  */
664
691
  frozen?: string[];
692
+ /** Collapsible sections by one Field, with subtotals on each header. */
693
+ grouping?: GridGrouping;
694
+ /**
695
+ * The width a person dragged a column to, by Field key. SPARSE on purpose —
696
+ * a view saved before widths existed carries none and still parses, and a
697
+ * column nobody resized is left to the table's own measurement.
698
+ */
699
+ widths?: Record<string, number>;
700
+ /** The body row height this view remembers, in px. */
701
+ rowHeight?: number;
665
702
  };
666
703
  declare const EMPTY_PRESENTATION: GridPresentation;
667
704
  /** A frozen column needs a known width, or the table declines to freeze at all. */
668
705
  declare const FROZEN_COLUMN_WIDTH = 200;
706
+ /**
707
+ * WHAT A ROW HEIGHT IS ALLOWED TO BE. Below the floor the text is clipped and
708
+ * no editor fits; above the ceiling one record fills the screen. A view asking
709
+ * for anything outside it is DROPPED rather than obeyed, because a saved look
710
+ * must not be able to make a table unreadable — and the Fields' own heights
711
+ * still draw, which is the tolerant half.
712
+ */
713
+ declare const MIN_ROW_HEIGHT = 24;
714
+ declare const MAX_ROW_HEIGHT = 96;
669
715
  /**
670
716
  * Read a presentation out of whatever the view record holds — an object, or the
671
717
  * JSON string a text field stores.
@@ -737,9 +783,26 @@ interface GridProps {
737
783
  * override, never the only thing that makes a column readable.
738
784
  */
739
785
  presentation?: GridPresentation | undefined;
786
+ /**
787
+ * THE LOOK, WRITTEN BACK. Called with the WHOLE next look when the person
788
+ * changes one on the table itself — picks a column to group by, shuts a
789
+ * section, drags a column wider.
790
+ *
791
+ * It is the same door every other view change already uses: `ViewSwitcher`
792
+ * folds it into its `onViewChange` patch and `TablePage` writes that patch
793
+ * onto the view record with `client.recordUpdate`, carrying the version it
794
+ * read. The Grid has no view id and must not grow one — a component that
795
+ * wrote to a record it was never told about would be a second, parallel way
796
+ * to save a view.
797
+ *
798
+ * UNBOUND, NOTHING IS DEAD. A host that binds no door still gets grouping,
799
+ * collapsing and resizing for this visit — they are held in the grid's own
800
+ * state — they are simply not remembered.
801
+ */
802
+ onPresentationChange?: ((next: GridPresentation) => void) | undefined;
740
803
  className?: string | undefined;
741
804
  }
742
- declare function Grid({ tableId, pageSize, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, className, }: GridProps): react.JSX.Element;
805
+ declare function Grid({ tableId, pageSize, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, onPresentationChange, className, }: GridProps): react.JSX.Element;
743
806
  /**
744
807
  * One Field becomes one column. The header is the Field's own NAME — never its
745
808
  * key (`names.ts`) — and the cell is the value, rendered by its parity type and
@@ -2165,4 +2228,4 @@ declare function useCanShare(): boolean;
2165
2228
  declare function shareUnavailableReason(): string;
2166
2229
  declare function ShareControl({ kind, organizationId, subjectId, name, may, size, variant, className, }: ShareControlProps): ReactNode;
2167
2230
 
2168
- export { ACTION_KINDS, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type Capability, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartConfig, ChartFrame, type ChartKind, ChartLegendContent, type ChartSpec, ChartTooltipContent, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, EMPTY_PRESENTATION, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FROZEN_COLUMN_WIDTH, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormSubmitOutcome, type FormTheme, FormsPanel, type FormsPanelProps, Grid, GridCell, type GridEditing, type GridPresentation, 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, LEVEL_WORD, type LabelLookup, MACHINE_IDENTITY, NOT_ANSWERED_YET, NO_CHAT_REASON, NO_COLUMNS_WHY, NO_COLUMNS_YET, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_OPEN_RECORDS_REASON, NO_REASK_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OpenRecordsAsk, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, type PlainRefusal, type PortalAnswer, PortalCardView, type PortalCardViewProps, PortalShell, type PortalShellProps, PortalsPanel, type PortalsPanelProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type ReaskContext, 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, SubscriptionsPanel, type SubscriptionsPanelProps, 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_NOT_SAVED_YET, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, type WhatYouMayDo, addFields, blockFromSpec, bodyForReading, bodyFromKeys, colorFromTheValue, columnForField, currencyCodeFor, dashboardDeclareArgs, dashboardFromSummary, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldDeclarationFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDeclareArgs, formFromSummary, formPresentation, formatForField, groupLabel, hintForAPerson, hintIsMachineIdentity, humanize, idsOf, isId, isMachineIdentity, isPlainFieldType, isSignatureField, keyFor, laneFor, machineIdentityIn, memberName, parityTypesWithNoExplanation, parseGridPresentation, personActor, personRecordForMember, pointsAtRecords, presentationDocument, presentationIsEmpty, previewLine, recordName, recordsDataSource, refusalForAPerson, refusalLineForAPerson, renderValue, revokeConsequence, rowName, scalarText, shareUnavailableReason, specFromBlock, storeDecidesRights, submissionStamp, tableName, tableRightsAt, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useMeasuredWidth, useRecordLabels, useRecordRights, useRecordsUi, useRowRights, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument, whatIsMissing, whatYouMayDo, whatYouMayDoWithTable };
2231
+ export { ACTION_KINDS, ActionInbox, type ActionInboxProps, type ActionKind, BookingSlots, type BookingSlotsProps, CAPTURE_MODES, CHART_KINDS, CHART_KIND_LABEL, CHART_NEEDS, CHECKLIST_TABLE, COMMENT_TABLE, type Capability, type CaptureMode, type CaptureQueuePort, CaptureSheet, type CaptureSheetProps, type CellAddress, type CellRefusal, type CellState, ChartBlock, type ChartBlockProps, type ChartConfig, ChartFrame, type ChartKind, ChartLegendContent, type ChartSpec, ChartTooltipContent, ChecklistRunner, type ChecklistRunnerProps, type ChecklistSpec, type ChecklistStepSpec, CommentThread, type CommentThreadProps, CustomFieldsSection, type CustomFieldsSectionProps, DEFAULT_FIELDS, DEFAULT_VIEW_NAME, DashboardCanvas, type DashboardCanvasProps, type DeclareResult, DocRender, type DocRenderProps, DocTemplate, type DocTemplateProps, type DocTemplateSpec, EMPTY_PRESENTATION, type EditorKind, EmbedFrame, type EmbedFrameProps, type EnrichAsk, type EnrichOutcome, EnrichPanel, type EnrichPanelProps, ExportMenu, type ExportMenuProps, FIELD_TYPE_CHOICES, FIELD_TYPE_GROUPS, FORM_FLOWS, FROZEN_COLUMN_WIDTH, FieldControl, FieldEditor, type FieldEditorControlProps, type FieldEditorProps, FieldLabel, type FieldProposalRow, type FieldTypeChoice, FormBuilder, type FormBuilderProps, type FormFlow, type FormQuestionSpec, FormRunner, type FormRunnerProps, type FormSpec, type FormSubmitOutcome, type FormTheme, FormsPanel, type FormsPanelProps, Grid, GridCell, type GridEditing, type GridGrouping, type GridPresentation, 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, LEVEL_WORD, type LabelLookup, MACHINE_IDENTITY, MAX_ROW_HEIGHT, MIN_ROW_HEIGHT, NOT_ANSWERED_YET, NO_CHAT_REASON, NO_COLUMNS_WHY, NO_COLUMNS_YET, NO_ENRICH_REASON, NO_MEMBERS_REASON, NO_OPEN_RECORDS_REASON, NO_REASK_REASON, NO_RIGHTS, NO_SAVED_VIEWS_REASON, NO_SHARE_REASON, NO_UPLOAD_REASON, type NewFieldSpec, type NewTableSpec, NotifyRuleEditor, type NotifyRuleEditorProps, type NotifyRuleSpec, type OpenRecordsAsk, type OrganizationMember, PARITY_LABEL, PARITY_MADE_OF, Peek, type PeekProps, type PendingCapture, PersonPicker, type PersonPickerProps, type PickableFieldType, type PlainFieldType, type PlainRefusal, type PortalAnswer, PortalCardView, type PortalCardViewProps, PortalShell, type PortalShellProps, PortalsPanel, type PortalsPanelProps, type ProposalOutcome, ProposalRow, type ProposalRowProps, type ProposedChange, ProvenanceBadge, PublicViewPage, type PublicViewPageProps, type ReaskContext, 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, SubscriptionsPanel, type SubscriptionsPanelProps, 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_NOT_SAVED_YET, VIEW_TABLE, ViewBar, type ViewBarProps, type ViewLayout, type ViewSort, ViewSwitcher, type ViewSwitcherProps, type WhatYouMayDo, addFields, blockFromSpec, bodyForReading, bodyFromKeys, colorFromTheValue, columnForField, currencyCodeFor, dashboardDeclareArgs, dashboardFromSummary, declareTable, editorKindFor, ensureSystemTable, envelopeFor, fieldDeclarationFor, fieldIsEditable, fieldName, fieldToken, fieldTypeChoice, fieldTypeLabel, formDeclareArgs, formFromSummary, formPresentation, formatForField, groupLabel, hintForAPerson, hintIsMachineIdentity, humanize, idsOf, isId, isMachineIdentity, isPlainFieldType, isSignatureField, keyFor, laneFor, machineIdentityIn, memberName, parityTypesWithNoExplanation, parseGridPresentation, personActor, personRecordForMember, pointsAtRecords, presentationDocument, presentationIsEmpty, previewLine, recordName, recordsDataSource, refusalForAPerson, refusalLineForAPerson, renderValue, revokeConsequence, rowName, scalarText, shareUnavailableReason, specFromBlock, storeDecidesRights, submissionStamp, tableName, tableRightsAt, tokenFor, useCanShare, useEmbedHandshake, useGridEditing, useMeasuredWidth, useRecordLabels, useRecordRights, useRecordsUi, useRowRights, useSystemTable, useTableRights, useViewRecords, viewDocument, viewFromRecord, viewPatchDocument, whatIsMissing, whatYouMayDo, whatYouMayDoWithTable };
package/dist/index.js CHANGED
@@ -1706,6 +1706,27 @@ import {
1706
1706
  } from "@ai-matrx/design-system/data-table";
1707
1707
  var EMPTY_PRESENTATION = {};
1708
1708
  var FROZEN_COLUMN_WIDTH = 200;
1709
+ var MIN_ROW_HEIGHT = 24;
1710
+ var MAX_ROW_HEIGHT = 96;
1711
+ var AGGREGATE_KINDS = [
1712
+ "count",
1713
+ "sum",
1714
+ "average",
1715
+ "min",
1716
+ "max",
1717
+ "empty",
1718
+ "filled",
1719
+ "unique",
1720
+ "checked",
1721
+ "unchecked",
1722
+ "percentFilled"
1723
+ ];
1724
+ var GROUP_ORDERS = [
1725
+ "value-asc",
1726
+ "value-desc",
1727
+ "count-desc",
1728
+ "first-seen"
1729
+ ];
1709
1730
  function isRecord(v) {
1710
1731
  return typeof v === "object" && v !== null && !Array.isArray(v);
1711
1732
  }
@@ -1742,10 +1763,51 @@ function parseGridPresentation(raw) {
1742
1763
  const frozen = value["frozen"].filter((k) => typeof k === "string");
1743
1764
  if (frozen.length > 0) out.frozen = frozen;
1744
1765
  }
1766
+ const grouping = parseGrouping(value["grouping"]);
1767
+ if (grouping) out.grouping = grouping;
1768
+ if (isRecord(value["widths"])) {
1769
+ const widths = {};
1770
+ for (const [key, raw2] of Object.entries(value["widths"])) {
1771
+ if (typeof raw2 !== "number" || !Number.isFinite(raw2) || raw2 <= 0) continue;
1772
+ widths[key] = Math.round(raw2);
1773
+ }
1774
+ if (Object.keys(widths).length > 0) out.widths = widths;
1775
+ }
1776
+ const rowHeight = value["rowHeight"];
1777
+ if (typeof rowHeight === "number" && Number.isFinite(rowHeight) && rowHeight >= MIN_ROW_HEIGHT && rowHeight <= MAX_ROW_HEIGHT) {
1778
+ out.rowHeight = Math.round(rowHeight);
1779
+ }
1780
+ return out;
1781
+ }
1782
+ function parseGrouping(raw) {
1783
+ if (!isRecord(raw)) return void 0;
1784
+ const field = raw["field"];
1785
+ if (typeof field !== "string" || field.trim() === "") return void 0;
1786
+ const out = { field };
1787
+ if (isRecord(raw["aggregates"])) {
1788
+ const aggregates = {};
1789
+ for (const [key, spec] of Object.entries(raw["aggregates"])) {
1790
+ if (!isRecord(spec)) continue;
1791
+ const kind = spec["kind"];
1792
+ if (typeof kind !== "string") continue;
1793
+ if (!AGGREGATE_KINDS.includes(kind)) continue;
1794
+ const label = spec["label"];
1795
+ aggregates[key] = typeof label === "string" ? { kind, label } : { kind };
1796
+ }
1797
+ if (Object.keys(aggregates).length > 0) out.aggregates = aggregates;
1798
+ }
1799
+ const order = raw["order"];
1800
+ if (typeof order === "string" && GROUP_ORDERS.includes(order)) {
1801
+ out.order = order;
1802
+ }
1803
+ if (Array.isArray(raw["collapsed"])) {
1804
+ const collapsed = raw["collapsed"].filter((k) => typeof k === "string");
1805
+ if (collapsed.length > 0) out.collapsed = collapsed;
1806
+ }
1745
1807
  return out;
1746
1808
  }
1747
1809
  function presentationIsEmpty(p) {
1748
- return (p.style === void 0 || tableStyleIsEmpty(p.style)) && Object.keys(p.formats ?? {}).length === 0 && (p.frozen?.length ?? 0) === 0;
1810
+ return (p.style === void 0 || tableStyleIsEmpty(p.style)) && Object.keys(p.formats ?? {}).length === 0 && (p.frozen?.length ?? 0) === 0 && p.grouping === void 0 && Object.keys(p.widths ?? {}).length === 0 && p.rowHeight === void 0;
1749
1811
  }
1750
1812
  function presentationDocument(p) {
1751
1813
  return presentationIsEmpty(p) ? "" : JSON.stringify(p);
@@ -1816,6 +1878,7 @@ function Grid({
1816
1878
  toolbarActions,
1817
1879
  editable = true,
1818
1880
  presentation = EMPTY_PRESENTATION,
1881
+ onPresentationChange,
1819
1882
  className
1820
1883
  }) {
1821
1884
  const host = useRecordsUi();
@@ -1867,6 +1930,67 @@ function Grid({
1867
1930
  ),
1868
1931
  [ordered, canWrite, editing, mayWriteRow, whyNotRow, presentation.formats, frozenKeys]
1869
1932
  );
1933
+ const columnIds = useMemo6(() => ordered.map((field) => field.key), [ordered]);
1934
+ const [localColumns, setLocalColumns] = useState6(
1935
+ null
1936
+ );
1937
+ const [localWidths, setLocalWidths] = useState6(null);
1938
+ const writeLook = useCallback4(
1939
+ (next) => onPresentationChange?.(next),
1940
+ [onPresentationChange]
1941
+ );
1942
+ const widths = localWidths ?? presentation.widths;
1943
+ const columnState = useMemo6(
1944
+ () => ({
1945
+ order: localColumns?.order ?? columnIds,
1946
+ hidden: localColumns?.hidden ?? [],
1947
+ onChange: (next) => setLocalColumns(next),
1948
+ ...widths ? { widths } : {},
1949
+ // A drag that changed nothing would be the silent half of a control that
1950
+ // looks alive, so the width always lands somewhere — the session at
1951
+ // least, the view record when a door is bound.
1952
+ onWidthsChange: (next) => {
1953
+ setLocalWidths(next);
1954
+ writeLook({ ...presentation, widths: next });
1955
+ }
1956
+ }),
1957
+ [columnIds, localColumns, widths, presentation, writeLook]
1958
+ );
1959
+ const groupingConfig = useMemo6(() => {
1960
+ const view = presentation.grouping;
1961
+ const field = view?.field ?? null;
1962
+ if (field === null && !onPresentationChange) return null;
1963
+ const aggregates = view && Object.keys(view.aggregates ?? {}).length > 0 ? view.aggregates : field ? { [field]: { kind: "count" } } : void 0;
1964
+ return {
1965
+ columnId: field,
1966
+ rowNoun: "record",
1967
+ ...aggregates ? { aggregates } : {},
1968
+ ...view?.order ? { order: view.order } : {},
1969
+ ...view?.collapsed ? { collapsed: view.collapsed } : {},
1970
+ ...onPresentationChange ? {
1971
+ onColumnIdChange: (columnId) => {
1972
+ if (columnId === null) {
1973
+ const { grouping: _dropped, ...rest } = presentation;
1974
+ writeLook(rest);
1975
+ return;
1976
+ }
1977
+ writeLook({
1978
+ ...presentation,
1979
+ grouping: {
1980
+ field: columnId,
1981
+ ...presentation.grouping?.aggregates ? { aggregates: presentation.grouping.aggregates } : {},
1982
+ ...presentation.grouping?.order ? { order: presentation.grouping.order } : {}
1983
+ }
1984
+ });
1985
+ },
1986
+ onCollapsedChange: (collapsed) => {
1987
+ const current = presentation.grouping;
1988
+ if (!current) return;
1989
+ writeLook({ ...presentation, grouping: { ...current, collapsed } });
1990
+ }
1991
+ } : {}
1992
+ };
1993
+ }, [presentation, onPresentationChange, writeLook]);
1870
1994
  if (table.error) return /* @__PURE__ */ jsx9(RefusalNotice, { error: table.error, className });
1871
1995
  if (fields.error) return /* @__PURE__ */ jsx9(RefusalNotice, { error: fields.error, className });
1872
1996
  const nothingToShowYet = table.loading || fields.loading || !rights.known || records.loading && rows.length === 0;
@@ -1930,6 +2054,15 @@ function Grid({
1930
2054
  pageSize,
1931
2055
  detail: { enabled: false },
1932
2056
  window: { enabled: false },
2057
+ ...groupingConfig ? { grouping: groupingConfig } : {},
2058
+ columnState,
2059
+ ...presentation.rowHeight ? { rowHeight: presentation.rowHeight } : {},
2060
+ virtualize: true,
2061
+ coverage: {
2062
+ answeredBy: "client",
2063
+ noun: "record",
2064
+ ...typeof records.data?.total === "number" ? { total: records.data.total } : {}
2065
+ },
1933
2066
  ...presentation.style ? {
1934
2067
  tableStyle: {
1935
2068
  style: presentation.style,
@@ -3850,6 +3983,7 @@ function ViewSwitcher({
3850
3983
  tableId: view.subject,
3851
3984
  pageSize,
3852
3985
  ...local.presentation ?? view.presentation ? { presentation: local.presentation ?? view.presentation } : {},
3986
+ ...onViewChange ? { onPresentationChange: (next) => change({ presentation: next }) } : {},
3853
3987
  ...onOpenRecord ? { onOpenRecord } : {},
3854
3988
  ...onNewRecordForm ? { onNewRecordForm } : {}
3855
3989
  }
@@ -6712,10 +6846,13 @@ function NotifyRuleEditor({ tableId, seed, className }) {
6712
6846
  const [busy, setBusy] = useState30(false);
6713
6847
  const load = useCallback17(async () => {
6714
6848
  const [held, offered] = await Promise.all([
6715
- client.aggSubscriptions(),
6849
+ // THE PERSON'S OWN DOOR, not the notifier's. It answers what is addressed
6850
+ // to them plus — only where they hold admin on this Table — anyone's over
6851
+ // it, and it is narrowed to Tables they can already open.
6852
+ client.subscriptions({ table_id: tableId }),
6716
6853
  // The cadences are ASKED of the store, never a list typed into a picker
6717
6854
  // here that could drift from what the digest runner understands.
6718
- client.aggSubscriptionCadences()
6855
+ client.subscriptionCadences()
6719
6856
  ]);
6720
6857
  if (!held.ok) {
6721
6858
  setError(held.error);
@@ -6726,7 +6863,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
6726
6863
  if (offered.ok) setCadences(offered.data);
6727
6864
  if (host.savedViews) setViews(await host.savedViews());
6728
6865
  else setViews(null);
6729
- }, [client, host]);
6866
+ }, [client, host, tableId]);
6730
6867
  useEffect21(() => {
6731
6868
  void load();
6732
6869
  }, [load]);
@@ -6816,6 +6953,7 @@ function NotifyRuleEditor({ tableId, seed, className }) {
6816
6953
  held.cadence === "digest" && held.schedule ? /* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: held.schedule }) : null,
6817
6954
  held.recipient_user_id === null ? /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: "This one has nobody to tell, so it fires at nobody." }) : null,
6818
6955
  held.saved_view_id === null ? /* @__PURE__ */ jsx32("span", { className: "text-destructive", children: "This one names no view, so the store never admits a record to it." }) : null,
6956
+ held.muted ? /* @__PURE__ */ jsx32("span", { className: "text-muted-foreground", children: "Switched off \u2014 it tells nobody until somebody switches it back on." }) : null,
6819
6957
  rights.write ? /* @__PURE__ */ jsx32(
6820
6958
  Button27,
6821
6959
  {
@@ -9337,6 +9475,8 @@ export {
9337
9475
  LAYOUT_NO_FIELD,
9338
9476
  LEVEL_WORD,
9339
9477
  MACHINE_IDENTITY,
9478
+ MAX_ROW_HEIGHT,
9479
+ MIN_ROW_HEIGHT,
9340
9480
  NOT_ANSWERED_YET,
9341
9481
  NO_CHAT_REASON,
9342
9482
  NO_COLUMNS_WHY,