@tailor-platform/app-shell 0.35.1 → 1.0.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.
@@ -374,6 +374,54 @@ declare type AsyncFetcherFn<T> = (query: string | null, options: {
374
374
  signal: AbortSignal;
375
375
  }) => Promise<T[]>;
376
376
 
377
+ export declare function Attachment({ items, onUpload, onDelete, onDownload, uploadLabel, uploadHint, accept, disabled, className, }: AttachmentProps): JSX.Element;
378
+
379
+ declare type AttachmentControlledProps = Pick<AttachmentProps, "items" | "onUpload" | "onDelete" | "accept" | "disabled">;
380
+
381
+ export declare interface AttachmentItem {
382
+ /** Unique identifier for the attachment item. */
383
+ id: string;
384
+ /** Original filename shown for non-image attachments. */
385
+ fileName: string;
386
+ /** MIME type used to switch image/file preview rendering. */
387
+ mimeType: string;
388
+ /** Optional preview URL for image attachments. */
389
+ previewUrl?: string;
390
+ }
391
+
392
+ export declare type AttachmentOperation = {
393
+ type: "upload";
394
+ file: File;
395
+ item: AttachmentItem;
396
+ } | {
397
+ type: "delete";
398
+ item: AttachmentItem;
399
+ };
400
+
401
+ export declare type AttachmentProps = {
402
+ /** List of attachments to render. */
403
+ items?: AttachmentItem[];
404
+ /** Called when files are selected or dropped. */
405
+ onUpload: (files: File[]) => void;
406
+ /** Called when delete action is selected for an item. */
407
+ onDelete: (item: AttachmentItem) => void;
408
+ /** Called when download action is selected for an item. */
409
+ onDownload?: (item: AttachmentItem) => void;
410
+ /** Upload label shown in the upload tile. */
411
+ uploadLabel?: string;
412
+ /** Supporting text shown below the upload label (e.g. accepted formats, max size). */
413
+ uploadHint?: string;
414
+ /** Accepted file types passed to the hidden file input. */
415
+ accept?: string;
416
+ /** Disable upload and item actions. */
417
+ disabled?: boolean;
418
+ /**
419
+ * Classes on the root wrapper. The component does not apply outer padding or borders—use
420
+ * this, or a parent such as `Card.Content`, for spacing and chrome.
421
+ */
422
+ className?: string;
423
+ };
424
+
377
425
  export { AuthClient }
378
426
 
379
427
  /**
@@ -680,6 +728,18 @@ declare namespace Body_2 {
680
728
  var displayName: string;
681
729
  }
682
730
 
731
+ /**
732
+ * Builds a Tailor Platform QueryInput-compatible type from table metadata.
733
+ */
734
+ export declare type BuildQueryVariables<TTable extends TableMetadata> = {
735
+ [F in TTable["fields"][number] as F extends {
736
+ readonly name: infer N extends string;
737
+ readonly type: infer T;
738
+ } ? T extends keyof FieldTypeToFilterConfigType ? FieldTypeToFilterConfigType[T] extends never ? never : N : never : never]?: F extends {
739
+ readonly type: infer T extends keyof FieldTypeToFilterConfigType & keyof FieldTypeToTSType;
740
+ } ? FieldTypeToFilterConfigType[T] extends infer FCT extends FilterConfig["type"] ? FilterInputForFieldType<FCT, ResolveFieldValueType<F, T>> : never : never;
741
+ };
742
+
683
743
  /**
684
744
  * A styled button component with multiple variants and sizes.
685
745
  *
@@ -756,6 +816,122 @@ declare namespace Close_2 {
756
816
  var displayName: string;
757
817
  }
758
818
 
819
+ /**
820
+ * Collection control interface for UI components to interact with
821
+ * filter, sort, and pagination state.
822
+ */
823
+ export declare interface CollectionControl<TFieldName extends string = string, TFilter = Filter<TFieldName>> {
824
+ filters: Filter<TFieldName>[];
825
+ addFilter<F extends TFieldName>(field: F, operator: OperatorForField<TFilter, F>, value: unknown): void;
826
+ setFilters: (filters: Filter<TFieldName>[]) => void;
827
+ removeFilter(field: TFieldName): void;
828
+ clearFilters: () => void;
829
+ sortStates: SortState[];
830
+ setSort(field: TFieldName, direction?: "Asc" | "Desc"): void;
831
+ clearSort: () => void;
832
+ pageSize: number;
833
+ setPageSize: (size: number) => void;
834
+ cursor: string | null;
835
+ paginationDirection: "forward" | "backward";
836
+ nextPage: (cursor: string) => void;
837
+ prevPage: (cursor: string) => void;
838
+ resetPage: () => void;
839
+ goToFirstPage: () => void;
840
+ /**
841
+ * Navigate to the last page.
842
+ *
843
+ * Requests the last `pageSize` items by setting `paginationDirection` to
844
+ * `"backward"` with no cursor.
845
+ */
846
+ goToLastPage: () => void;
847
+ }
848
+
849
+ /**
850
+ * Provider that shares collection control state via React Context.
851
+ *
852
+ * > **Note:** `DataTable.Root` automatically wraps its children with this provider
853
+ * > when `control` is supplied to `useDataTable`. Use `CollectionControlProvider`
854
+ * > directly only when you need to share control state with components that live
855
+ * > **outside** of `DataTable.Root` (e.g. a sibling filter panel or pagination
856
+ * > widget). Wrapping `DataTable.Root` with an outer `CollectionControlProvider`
857
+ * > while also passing `control` to `useDataTable` results in a double-wrap: the
858
+ * > inner provider (created by `DataTable.Root`) will silently shadow the outer
859
+ * > one for all descendants inside the table.
860
+ *
861
+ * @example
862
+ * ```tsx
863
+ * const { variables, control } = useCollectionVariables({ params: { pageSize: 20 } });
864
+ *
865
+ * <CollectionControlProvider value={control}>
866
+ * <FilterPanel />
867
+ * <DataTable.Root>...</DataTable.Root>
868
+ * <Pagination />
869
+ * </CollectionControlProvider>
870
+ * ```
871
+ */
872
+ export declare function CollectionControlProvider({ value, children, }: {
873
+ value: CollectionControl;
874
+ children: ReactNode;
875
+ }): JSX.Element;
876
+
877
+ /**
878
+ * GraphQL collection result format (Tailor Platform standard).
879
+ */
880
+ export declare interface CollectionResult<T> {
881
+ edges: {
882
+ node: T;
883
+ }[];
884
+ pageInfo: PageInfo;
885
+ total?: number | null;
886
+ }
887
+
888
+ /**
889
+ * Collection variables split into explicit sub-properties.
890
+ */
891
+ export declare interface CollectionVariables {
892
+ query: Record<string, Record<string, unknown>> | undefined;
893
+ order: {
894
+ field: string;
895
+ direction: "Asc" | "Desc";
896
+ }[] | undefined;
897
+ pagination: PaginationVariables;
898
+ }
899
+
900
+ /**
901
+ * A column definition for DataTable.
902
+ */
903
+ export declare interface Column<TRow extends Record<string, unknown>> {
904
+ /** Column header text. Omit for action or icon-only columns. */
905
+ label?: string;
906
+ /** Renders the cell content for a given row. Required. */
907
+ render: (row: TRow) => ReactNode;
908
+ /**
909
+ * Stable identifier used for column visibility toggling and as the React key.
910
+ * Falls back to `label` when omitted. Set this explicitly when `label` is
911
+ * absent or not unique.
912
+ */
913
+ id?: string;
914
+ /** Fixed column width in pixels. When omitted the column sizes naturally. */
915
+ width?: number;
916
+ /**
917
+ * Extracts the raw value from a row for purposes such as sorting or
918
+ * clipboard copying. Not used for rendering — use `render` for that.
919
+ */
920
+ accessor?: (row: TRow) => unknown;
921
+ /**
922
+ * Sort configuration. When set, the column header becomes clickable and
923
+ * cycles through `Asc → Desc → undefined`.
924
+ * Use `fieldTypeToSortConfig` or `inferColumns` to derive this automatically.
925
+ */
926
+ sort?: SortConfig;
927
+ /**
928
+ * Filter configuration. When set, this column appears as an option in
929
+ * `DataTable.Filters`.
930
+ * Use `fieldTypeToFilterConfig` or `inferColumns` to derive this automatically.
931
+ */
932
+ filter?: FilterConfig;
933
+ }
934
+
759
935
  /**
760
936
  * Supported area values for Layout.Column
761
937
  */
@@ -766,6 +942,59 @@ declare type ColumnArea = "left" | "main" | "right";
766
942
  */
767
943
  declare type ColumnCount = 1 | 2 | 3;
768
944
 
945
+ /**
946
+ * Object returned by `createColumnHelper`.
947
+ */
948
+ declare interface ColumnHelper<TRow extends Record<string, unknown>> {
949
+ /**
950
+ * Define a column with an explicit render function.
951
+ *
952
+ * @example
953
+ * ```tsx
954
+ * column({ label: "Name", render: (row) => row.name })
955
+ * column({ label: "Actions", render: (row) => <button>Edit {row.name}</button> })
956
+ * ```
957
+ */
958
+ column: (options: Column<TRow>) => Column<TRow>;
959
+ /**
960
+ * Bind table metadata once and return a per-field column factory.
961
+ *
962
+ * The returned factory **throws at call time** if the given field name is not
963
+ * found in `tableMetadata`. This typically happens at module initialisation
964
+ * (i.e. when columns are defined outside a component), so it surfaces as an
965
+ * uncaught error rather than a render error. Field-name narrowing is only
966
+ * active when `tableMetadata` is typed from an `as const` source (e.g. a
967
+ * file generated by `appShellMetadataPlugin`).
968
+ *
969
+ * @throws {Error} If the field name is not found in the provided table metadata.
970
+ *
971
+ * @example
972
+ * ```tsx
973
+ * const infer = inferColumns(tableMetadata.order);
974
+ * const columns = [
975
+ * column(infer("title")),
976
+ * column({
977
+ * ...infer("status"),
978
+ * render: (row) => <StatusBadge value={row.status} />
979
+ * }),
980
+ * ];
981
+ * ```
982
+ */
983
+ inferColumns: <const TTable extends TableMetadata = TableMetadata>(tableMetadata: TTable) => ColumnInferFn<TRow, TTable>;
984
+ }
985
+
986
+ /**
987
+ * Per-field column factory returned by `inferColumns(tableMetadata)`.
988
+ *
989
+ * Derives label, sort config, and filter config from the field's metadata.
990
+ * Sort and filter can be suppressed per call via `options`.
991
+ *
992
+ * @param dataKey - A field name from the bound table metadata.
993
+ * @param options - Optional per-column overrides (label, width, sort, filter).
994
+ * @throws {Error} If `dataKey` is not found in the metadata passed to `inferColumns`.
995
+ */
996
+ declare type ColumnInferFn<TRow extends Record<string, unknown>, TTable extends TableMetadata = TableMetadata> = (dataKey: TableFieldName<TTable>, options?: MetadataFieldOptions) => Column<TRow>;
997
+
769
998
  /**
770
999
  * Props for individual Layout.Column component
771
1000
  */
@@ -1226,6 +1455,23 @@ declare interface CreatableProps<T extends object> {
1226
1455
  */
1227
1456
  export declare function createAuthClient(config: AuthClientConfig): EnhancedAuthClient;
1228
1457
 
1458
+ /**
1459
+ * Factory that captures the row type once and returns `column` and `inferColumns`
1460
+ * with `TRow` already bound.
1461
+ *
1462
+ * @example
1463
+ * ```tsx
1464
+ * const { column, inferColumns } = createColumnHelper<Order>();
1465
+ *
1466
+ * const infer = inferColumns(tableMetadata.order);
1467
+ * const columns = [
1468
+ * column(infer("title")),
1469
+ * column({ label: "Actions", render: (row) => <button>Edit {row.name}</button> }),
1470
+ * ];
1471
+ * ```
1472
+ */
1473
+ export declare function createColumnHelper<TRow extends Record<string, unknown>>(): ColumnHelper<TRow>;
1474
+
1229
1475
  /**
1230
1476
  * Create a type-safe path builder from route definitions.
1231
1477
  *
@@ -1382,6 +1628,173 @@ export declare type CsvSchema = {
1382
1628
  columns: readonly CsvColumn[];
1383
1629
  };
1384
1630
 
1631
+ export declare const DataTable: {
1632
+ /**
1633
+ * Context/provider root. Wraps all other `DataTable.*` components and
1634
+ * wires state from `useDataTable()` into context.
1635
+ */
1636
+ readonly Root: typeof DataTableRoot;
1637
+ /**
1638
+ * Container for toolbar content (column visibility, search, etc.).
1639
+ * Place inside `DataTable.Root`, before `DataTable.Table`.
1640
+ */
1641
+ readonly Toolbar: typeof DataTableToolbar;
1642
+ /**
1643
+ * Auto-generated filter chips from column filter configs.
1644
+ *
1645
+ * **Requires `control`** — `useDataTable()` must receive `control` from
1646
+ * `useCollectionVariables()`, otherwise this component throws at render time.
1647
+ */
1648
+ readonly Filters: typeof DataTableFilters;
1649
+ /**
1650
+ * Renders `<table>` with built-in `Headers` and `Body`.
1651
+ * Place inside `DataTable.Root`.
1652
+ */
1653
+ readonly Table: typeof DataTableTable;
1654
+ /**
1655
+ * Footer container for pagination and other footer content.
1656
+ * Place inside `DataTable.Root`, after `DataTable.Table`.
1657
+ */
1658
+ readonly Footer: typeof DataTableFooter;
1659
+ /**
1660
+ * Pre-built pagination controls. Place inside `DataTable.Footer`.
1661
+ *
1662
+ * **Requires `control`** — `useDataTable()` must receive `control` from
1663
+ * `useCollectionVariables()`, otherwise this component throws at render time.
1664
+ *
1665
+ * **Go-to-first / go-to-last buttons** — Rendered only when `totalPages` is
1666
+ * non-null (i.e. the backend returns a total count). When `totalPages` is
1667
+ * `null`, these buttons and the page counter are omitted.
1668
+ */
1669
+ readonly Pagination: typeof DataTablePagination;
1670
+ };
1671
+
1672
+ /**
1673
+ * Context value provided by `DataTable.Root`.
1674
+ *
1675
+ * `control` is intentionally excluded from this context: collection control
1676
+ * (filters, sort, and pagination) is managed by `CollectionControlProvider`
1677
+ * via a separate context. Keeping them separate means `DataTable.Root` works
1678
+ * without any collection control (read-only / static tables), while
1679
+ * `CollectionControlProvider` can optionally wrap it when filtering and
1680
+ * pagination are needed. This also avoids coupling `DataTableContextValue`
1681
+ * to `UseDataTableReturn` — changes to `UseDataTableReturn` require an
1682
+ * explicit decision about whether they should appear in the context.
1683
+ */
1684
+ export declare interface DataTableContextValue<TRow extends Record<string, unknown>> {
1685
+ rows: TRow[];
1686
+ loading: boolean;
1687
+ error: Error | null;
1688
+ sortStates: SortState[];
1689
+ onSort?: (field: string, direction?: "Asc" | "Desc") => void;
1690
+ pageInfo: PageInfo;
1691
+ total: number | null;
1692
+ totalPages: number | null;
1693
+ nextPage: (cursor: string) => void;
1694
+ prevPage: (cursor: string) => void;
1695
+ hasPrevPage: boolean;
1696
+ hasNextPage: boolean;
1697
+ /**
1698
+ * The resolved page size from the collection control. `0` when no control is
1699
+ * configured. Used to render the correct number of skeleton / ghost rows.
1700
+ */
1701
+ pageSize: number;
1702
+ columns: Column<TRow>[];
1703
+ visibleColumns: Column<TRow>[];
1704
+ toggleColumn: (fieldOrId: string) => void;
1705
+ showAllColumns: () => void;
1706
+ hideAllColumns: () => void;
1707
+ isColumnVisible: (fieldOrId: string) => boolean;
1708
+ onClickRow?: (row: TRow) => void;
1709
+ rowActions?: RowAction<TRow>[];
1710
+ selectedIds: string[];
1711
+ isRowSelected: (row: TRow) => boolean;
1712
+ toggleRowSelection?: (row: TRow) => void;
1713
+ /**
1714
+ * Selects all rows on the **current page** only. Cross-page selection is not supported.
1715
+ * Undefined when `onSelectionChange` is not provided.
1716
+ */
1717
+ selectAllRows?: () => void;
1718
+ clearSelection?: () => void;
1719
+ isAllSelected: boolean;
1720
+ isIndeterminate: boolean;
1721
+ }
1722
+
1723
+ /**
1724
+ * Data input for `useDataTable` hook.
1725
+ */
1726
+ export declare interface DataTableData<TRow> {
1727
+ rows: TRow[];
1728
+ pageInfo?: PageInfo;
1729
+ total?: number | null;
1730
+ }
1731
+
1732
+ /** Use `DataTable.Filters` instead of calling this directly. */
1733
+ declare function DataTableFilters({ className }: {
1734
+ className?: string;
1735
+ }): JSX.Element | null;
1736
+
1737
+ declare namespace DataTableFilters {
1738
+ var displayName: string;
1739
+ }
1740
+
1741
+ /** Use `DataTable.Footer` instead of calling this directly. */
1742
+ declare function DataTableFooter({ children, className }: {
1743
+ children: ReactNode;
1744
+ className?: string;
1745
+ }): JSX.Element;
1746
+
1747
+ declare namespace DataTableFooter {
1748
+ var displayName: string;
1749
+ }
1750
+
1751
+ /** Use `DataTable.Pagination` instead of calling this directly. */
1752
+ declare function DataTablePagination({ pageSizeOptions }?: DataTablePaginationProps): JSX.Element;
1753
+
1754
+ declare namespace DataTablePagination {
1755
+ var displayName: string;
1756
+ }
1757
+
1758
+ export declare interface DataTablePaginationProps {
1759
+ /**
1760
+ * Available page-size options shown in a dropdown selector.
1761
+ * When provided, a page-size switcher is rendered.
1762
+ */
1763
+ pageSizeOptions?: number[];
1764
+ }
1765
+
1766
+ /** Use `DataTable.Root` instead of calling this directly. */
1767
+ declare function DataTableRoot<TRow extends Record<string, unknown>>({ value, children, className, }: DataTableRootProps<TRow>): JSX.Element;
1768
+
1769
+ declare namespace DataTableRoot {
1770
+ var displayName: string;
1771
+ }
1772
+
1773
+ export declare interface DataTableRootProps<TRow extends Record<string, unknown>> {
1774
+ value: UseDataTableReturn<TRow>;
1775
+ children: ReactNode;
1776
+ className?: string;
1777
+ }
1778
+
1779
+ /** Use `DataTable.Table` instead of calling this directly. */
1780
+ declare function DataTableTable({ className }: {
1781
+ className?: string;
1782
+ }): JSX.Element;
1783
+
1784
+ declare namespace DataTableTable {
1785
+ var displayName: string;
1786
+ }
1787
+
1788
+ /** Use `DataTable.Toolbar` instead of calling this directly. */
1789
+ declare function DataTableToolbar({ children, className }: {
1790
+ children: ReactNode;
1791
+ className?: string;
1792
+ }): JSX.Element;
1793
+
1794
+ declare namespace DataTableToolbar {
1795
+ var displayName: string;
1796
+ }
1797
+
1385
1798
  /**
1386
1799
  * Date format options
1387
1800
  */
@@ -1900,7 +2313,7 @@ declare type FieldConfig = FieldDivider | FieldDefinition;
1900
2313
  */
1901
2314
  declare interface FieldDefinition {
1902
2315
  /** Field type determines rendering (defaults to "text") */
1903
- type?: FieldType;
2316
+ type?: FieldType_2;
1904
2317
  /** Path to the value in the data object (supports dot notation) */
1905
2318
  key: string;
1906
2319
  /** Display label for the field */
@@ -1944,6 +2357,22 @@ declare interface FieldMeta {
1944
2357
  truncateLines?: number;
1945
2358
  }
1946
2359
 
2360
+ /**
2361
+ * Metadata for a single field.
2362
+ */
2363
+ export declare interface FieldMetadata {
2364
+ readonly name: string;
2365
+ readonly type: FieldType;
2366
+ readonly required: boolean;
2367
+ readonly enumValues?: readonly string[];
2368
+ readonly arrayItemType?: FieldType;
2369
+ readonly description?: string;
2370
+ readonly relation?: {
2371
+ readonly fieldName: string;
2372
+ readonly targetTable: string;
2373
+ };
2374
+ }
2375
+
1947
2376
  declare type FieldRootProps = Pick<React_2.ComponentProps<typeof Field_2.Root>, "name" | "disabled" | "validate" | "validationMode" | "validationDebounceTime" | "className" | "style"> & {
1948
2377
  children: React_2.ReactNode;
1949
2378
  /** Whether the field has been blurred. Maps to Base UI's `touched`. */
@@ -1988,10 +2417,101 @@ declare type FieldsetRootProps = Pick<React_2.ComponentProps<typeof Fieldset_2.R
1988
2417
  children: React_2.ReactNode;
1989
2418
  };
1990
2419
 
2420
+ /**
2421
+ * Field type mapping for Data View.
2422
+ */
2423
+ export declare type FieldType = "string" | "number" | "boolean" | "uuid" | "datetime" | "date" | "time" | "enum" | "array" | "nested" | "file";
2424
+
1991
2425
  /**
1992
2426
  * Supported field types for DescriptionCard
1993
2427
  */
1994
- declare type FieldType = "text" | "badge" | "money" | "date" | "link" | "address" | "reference";
2428
+ declare type FieldType_2 = "text" | "badge" | "money" | "date" | "link" | "address" | "reference";
2429
+
2430
+ /**
2431
+ * Map metadata field type to FilterConfig.
2432
+ * Returns undefined for types that don't support filtering.
2433
+ */
2434
+ export declare function fieldTypeToFilterConfig(field: string, type: FieldType, enumValues?: readonly string[]): FilterConfig | undefined;
2435
+
2436
+ /**
2437
+ * Type-level mapping from `FieldType` (metadata) to `FilterConfig["type"]`.
2438
+ */
2439
+ declare type FieldTypeToFilterConfigType = {
2440
+ string: "string";
2441
+ number: "number";
2442
+ boolean: "boolean";
2443
+ uuid: "uuid";
2444
+ datetime: "date";
2445
+ date: "date";
2446
+ time: "date";
2447
+ enum: "enum";
2448
+ array: never;
2449
+ nested: never;
2450
+ file: never;
2451
+ };
2452
+
2453
+ /**
2454
+ * Map metadata field type to SortConfig.
2455
+ * Returns undefined for types that don't support sorting.
2456
+ */
2457
+ export declare function fieldTypeToSortConfig(field: string, type: FieldType): SortConfig | undefined;
2458
+
2459
+ declare type FieldTypeToTSType = {
2460
+ string: string;
2461
+ number: number;
2462
+ boolean: boolean;
2463
+ uuid: string;
2464
+ datetime: string;
2465
+ date: string;
2466
+ time: string;
2467
+ enum: string;
2468
+ };
2469
+
2470
+ /**
2471
+ * Active filter state.
2472
+ *
2473
+ * @typeParam TFieldName - Union of allowed field name strings (default: `string`).
2474
+ */
2475
+ export declare interface Filter<TFieldName extends string = string> {
2476
+ field: TFieldName;
2477
+ operator: FilterOperator;
2478
+ value: unknown;
2479
+ }
2480
+
2481
+ /**
2482
+ * Filter configuration for a column.
2483
+ * The `type` determines which operators are available.
2484
+ * The `field` identifies the backend field name used for filtering.
2485
+ */
2486
+ export declare type FilterConfig = {
2487
+ field: string;
2488
+ type: "string";
2489
+ } | {
2490
+ field: string;
2491
+ type: "number";
2492
+ } | {
2493
+ field: string;
2494
+ type: "date";
2495
+ } | {
2496
+ field: string;
2497
+ type: "enum";
2498
+ options: SelectOption[];
2499
+ } | {
2500
+ field: string;
2501
+ type: "boolean";
2502
+ } | {
2503
+ field: string;
2504
+ type: "uuid";
2505
+ };
2506
+
2507
+ declare type FilterInputForFieldType<TFilterConfigType extends FilterConfig["type"], TValue> = {
2508
+ [Op in OperatorForFilterType[TFilterConfigType]]?: OperatorValueType<Op, TValue>;
2509
+ };
2510
+
2511
+ /**
2512
+ * Union of all available filter operators.
2513
+ */
2514
+ export declare type FilterOperator = OperatorForFilterType[FilterConfig["type"]];
1995
2515
 
1996
2516
  /** The table footer section (`<tfoot>`). */
1997
2517
  declare function Footer({ className, ...props }: React_2.ComponentProps<"tfoot">): JSX.Element;
@@ -2504,6 +3024,26 @@ declare namespace MenuSeparator {
2504
3024
  var displayName: string;
2505
3025
  }
2506
3026
 
3027
+ /**
3028
+ * Options for metadata-based single field inference.
3029
+ */
3030
+ export declare interface MetadataFieldOptions {
3031
+ /** Override the column header text. Defaults to the field's `description` or `name` from metadata. */
3032
+ label?: string;
3033
+ /** Fixed column width in pixels. When omitted the column sizes naturally. */
3034
+ width?: number;
3035
+ /**
3036
+ * Set to `false` to suppress the auto-generated sort config for this field.
3037
+ * Defaults to `true` (sort is enabled when the field type supports it).
3038
+ */
3039
+ sort?: boolean;
3040
+ /**
3041
+ * Set to `false` to suppress the auto-generated filter config for this field.
3042
+ * Defaults to `true` (filter is enabled when the field type supports it).
3043
+ */
3044
+ filter?: boolean;
3045
+ }
3046
+
2507
3047
  /**
2508
3048
  * MetricCard — Compact card for dashboard KPI display (title, value, optional trend and description).
2509
3049
  *
@@ -2573,6 +3113,54 @@ declare type Module = Omit<CommonPageResource, "meta"> & {
2573
3113
 
2574
3114
  declare type Modules = Array<Module>;
2575
3115
 
3116
+ /**
3117
+ * Extract the node type from a cursor connection result.
3118
+ */
3119
+ export declare type NodeType<T extends {
3120
+ edges: {
3121
+ node: unknown;
3122
+ }[];
3123
+ } | null | undefined> = NonNullable<T>["edges"][number]["node"];
3124
+
3125
+ /**
3126
+ * Resolve the operator union for a specific field within a filter type.
3127
+ */
3128
+ declare type OperatorForField<TFilter, F extends string> = [Extract<TFilter, {
3129
+ field: F;
3130
+ }>] extends [
3131
+ never
3132
+ ] ? FilterOperator : Extract<TFilter, {
3133
+ field: F;
3134
+ }> extends {
3135
+ operator: infer O;
3136
+ } ? O : FilterOperator;
3137
+
3138
+ /**
3139
+ * Maps each filter type to the union of operators it supports.
3140
+ */
3141
+ declare type OperatorForFilterType = {
3142
+ [T in FilterConfig["type"]]: (typeof OPERATORS_BY_FILTER_TYPE)[T][number];
3143
+ };
3144
+
3145
+ /**
3146
+ * Operators available per filter type (Tailor Platform schema).
3147
+ */
3148
+ export declare const OPERATORS_BY_FILTER_TYPE: {
3149
+ readonly string: readonly ["eq", "ne", "contains", "notContains", "hasPrefix", "hasSuffix", "notHasPrefix", "notHasSuffix", "in", "nin"];
3150
+ readonly number: readonly ["eq", "ne", "gt", "gte", "lt", "lte", "between", "in", "nin"];
3151
+ readonly date: readonly ["eq", "ne", "gt", "gte", "lt", "lte", "between", "in", "nin"];
3152
+ readonly enum: readonly ["eq", "ne", "in", "nin"];
3153
+ readonly boolean: readonly ["eq", "ne"];
3154
+ readonly uuid: readonly ["eq", "ne", "in", "nin"];
3155
+ };
3156
+
3157
+ declare type OperatorValueType<TOp extends string, TValue> = TOp extends "in" | "nin" ? TValue[] : TOp extends "between" ? {
3158
+ min: TValue;
3159
+ max: TValue;
3160
+ } : TValue;
3161
+
3162
+ declare type OrderableFieldType = "string" | "number" | "boolean" | "datetime" | "date" | "time" | "enum";
3163
+
2576
3164
  /**
2577
3165
  * A React component that can be used as a page in file-based routing.
2578
3166
  *
@@ -2597,11 +3185,31 @@ declare type PageEntry = {
2597
3185
  component: PageComponent;
2598
3186
  };
2599
3187
 
3188
+ /**
3189
+ * Page info for cursor-based pagination (Relay Connection spec).
3190
+ */
3191
+ export declare interface PageInfo {
3192
+ hasNextPage: boolean;
3193
+ hasPreviousPage: boolean;
3194
+ endCursor: string | null;
3195
+ startCursor: string | null;
3196
+ }
3197
+
2600
3198
  export declare type PageMeta = {
2601
3199
  title: string;
2602
3200
  icon?: ReactNode;
2603
3201
  };
2604
3202
 
3203
+ /**
3204
+ * Pagination variables for cursor-based pagination (Tailor Platform format).
3205
+ */
3206
+ export declare interface PaginationVariables {
3207
+ first?: number;
3208
+ after?: string | null;
3209
+ last?: number;
3210
+ before?: string | null;
3211
+ }
3212
+
2605
3213
  /** The row data passed to `onValidate`, after transforms have been applied. */
2606
3214
  export declare type ParsedRow = {
2607
3215
  /** 0-based row index, stable across edits. */
@@ -2676,6 +3284,10 @@ declare namespace RadioItemIndicator {
2676
3284
  */
2677
3285
  export declare const redirectTo: (to: string) => GuardResult;
2678
3286
 
3287
+ declare type ResolveFieldValueType<F, T extends keyof FieldTypeToTSType> = T extends "enum" ? F extends {
3288
+ readonly enumValues: readonly (infer V extends string)[];
3289
+ } ? V : string : FieldTypeToTSType[T];
3290
+
2679
3291
  /**
2680
3292
  * A resource that can be included in the sub-content in the root resource.
2681
3293
  *
@@ -2953,6 +3565,18 @@ declare namespace Row {
2953
3565
  var displayName: string;
2954
3566
  }
2955
3567
 
3568
+ /**
3569
+ * A single row action definition for the actions column.
3570
+ */
3571
+ export declare interface RowAction<TRow extends Record<string, unknown>> {
3572
+ id: string;
3573
+ label: string;
3574
+ icon?: ReactNode;
3575
+ variant?: "default" | "destructive";
3576
+ isDisabled?: (row: TRow) => boolean;
3577
+ onClick: (row: TRow) => void;
3578
+ }
3579
+
2956
3580
  /**
2957
3581
  * An async search source that can be plugged into the CommandPalette.
2958
3582
  *
@@ -3051,6 +3675,14 @@ declare namespace SelectItem {
3051
3675
  var displayName: string;
3052
3676
  }
3053
3677
 
3678
+ /**
3679
+ * Select option for enum/dropdown filters.
3680
+ */
3681
+ export declare interface SelectOption {
3682
+ value: string;
3683
+ label: string;
3684
+ }
3685
+
3054
3686
  declare interface SelectPropsBase<T> {
3055
3687
  /** Placeholder text shown when no value is selected */
3056
3688
  placeholder?: string;
@@ -3471,6 +4103,33 @@ export declare type SidebarLayoutProps = {
3471
4103
  */
3472
4104
  export declare const SidebarSeparator: () => JSX.Element;
3473
4105
 
4106
+ /**
4107
+ * Sort configuration for a column.
4108
+ * The `type` determines how values are compared when sorting.
4109
+ * The `field` identifies the backend field name used for ordering.
4110
+ */
4111
+ export declare type SortConfig = {
4112
+ field: string;
4113
+ type: "string";
4114
+ } | {
4115
+ field: string;
4116
+ type: "number";
4117
+ } | {
4118
+ field: string;
4119
+ type: "date";
4120
+ } | {
4121
+ field: string;
4122
+ type: "boolean";
4123
+ };
4124
+
4125
+ /**
4126
+ * Active sort state for a single field.
4127
+ */
4128
+ export declare interface SortState {
4129
+ field: string;
4130
+ direction: "Asc" | "Desc";
4131
+ }
4132
+
3474
4133
  /** Groups all parts of a submenu. */
3475
4134
  declare function SubmenuRoot({ children, ...props }: SubmenuRootProps): JSX.Element;
3476
4135
 
@@ -3500,6 +4159,57 @@ export declare const Table: {
3500
4159
  Caption: typeof Caption;
3501
4160
  };
3502
4161
 
4162
+ /**
4163
+ * Extract field names from a single table metadata object.
4164
+ */
4165
+ export declare type TableFieldName<TTable extends TableMetadata> = TTable["fields"][number] extends {
4166
+ readonly name: infer N;
4167
+ } ? N extends string ? N : never : never;
4168
+
4169
+ /**
4170
+ * Metadata for a single table.
4171
+ */
4172
+ export declare interface TableMetadata {
4173
+ readonly name: string;
4174
+ readonly pluralForm: string;
4175
+ readonly description?: string;
4176
+ readonly fields: readonly FieldMetadata[];
4177
+ readonly relations?: readonly {
4178
+ readonly relationType: "manyToOne" | "oneToOne" | "oneToMany";
4179
+ readonly fieldName: string;
4180
+ readonly targetTable: string;
4181
+ readonly foreignKeyField: string;
4182
+ }[];
4183
+ }
4184
+
4185
+ /**
4186
+ * Metadata-aware filter type from a single table metadata object.
4187
+ */
4188
+ export declare type TableMetadataFilter<TTable extends TableMetadata> = TTable["fields"][number] extends infer F ? F extends {
4189
+ readonly name: infer N;
4190
+ readonly type: infer T;
4191
+ } ? N extends string ? T extends keyof FieldTypeToFilterConfigType ? FieldTypeToFilterConfigType[T] extends never ? never : {
4192
+ field: N;
4193
+ operator: OperatorForFilterType[FieldTypeToFilterConfigType[T]];
4194
+ value: unknown;
4195
+ } : never : never : never : never;
4196
+
4197
+ /**
4198
+ * Map of all tables.
4199
+ */
4200
+ export declare type TableMetadataMap = {
4201
+ readonly [key: string]: TableMetadata;
4202
+ };
4203
+
4204
+ /**
4205
+ * Extract only orderable field names from a single table metadata object.
4206
+ */
4207
+ export declare type TableOrderableFieldName<TTable extends TableMetadata> = Extract<TTable["fields"][number], {
4208
+ readonly type: OrderableFieldType;
4209
+ }> extends {
4210
+ readonly name: infer N;
4211
+ } ? N extends string ? N : never : never;
4212
+
3503
4213
  declare type Theme = "dark" | "light" | "system";
3504
4214
 
3505
4215
  declare type ThemeProviderState = {
@@ -3774,6 +4484,33 @@ declare interface UseAsyncItemsReturn<T> {
3774
4484
  onOpenChange: (open: boolean) => void;
3775
4485
  }
3776
4486
 
4487
+ export declare function useAttachment(options?: UseAttachmentOptions): UseAttachmentReturn;
4488
+
4489
+ export declare type UseAttachmentOptions = {
4490
+ /** Initial items to populate (e.g. from an existing record). */
4491
+ initialItems?: AttachmentItem[];
4492
+ /** Accepted file types passed to the hidden file input. */
4493
+ accept?: string;
4494
+ /** Disable upload and item actions. */
4495
+ disabled?: boolean;
4496
+ };
4497
+
4498
+ declare type UseAttachmentProps = Omit<AttachmentControlledProps, "items"> & {
4499
+ items: AttachmentItem[];
4500
+ };
4501
+
4502
+ declare type UseAttachmentReturn = {
4503
+ props: UseAttachmentProps;
4504
+ /**
4505
+ * Flushes buffered operations to your backend by passing them to `fn`.
4506
+ * If `fn` throws, the buffer is preserved so the call can be retried.
4507
+ * The buffer is cleared only after `fn` resolves successfully.
4508
+ */
4509
+ applyChanges: (fn: (operations: AttachmentOperation[]) => Promise<void>) => Promise<void>;
4510
+ /** True while applyChanges is in progress. */
4511
+ isApplying: boolean;
4512
+ };
4513
+
3777
4514
  /**
3778
4515
  * Authentication hook.
3779
4516
  *
@@ -3861,6 +4598,90 @@ export declare const useAuthSuspense: () => {
3861
4598
  checkAuthStatus: () => Promise<AuthState>;
3862
4599
  };
3863
4600
 
4601
+ /**
4602
+ * Hook to access collection control from the nearest `CollectionControlProvider`.
4603
+ *
4604
+ * @typeParam TFieldName - Union of allowed field name strings (default: `string`).
4605
+ *
4606
+ * @throws Error if used outside of `CollectionControlProvider`.
4607
+ */
4608
+ export declare function useCollectionControl<TFieldName extends string = string>(): CollectionControl<TFieldName>;
4609
+
4610
+ /**
4611
+ * Options for `useCollectionVariables` hook.
4612
+ */
4613
+ export declare interface UseCollectionOptions<TFieldName extends string = string, TFilter extends Filter<TFieldName> = Filter<TFieldName>> {
4614
+ params?: {
4615
+ initialFilters?: TFilter[];
4616
+ initialSort?: {
4617
+ field: TFieldName;
4618
+ direction: "Asc" | "Desc";
4619
+ }[];
4620
+ pageSize?: number;
4621
+ };
4622
+ }
4623
+
4624
+ /**
4625
+ * Return type of `useCollectionVariables` hook.
4626
+ */
4627
+ export declare interface UseCollectionReturn<TFieldName extends string = string, TVariables = CollectionVariables, TFilter = Filter<TFieldName>> {
4628
+ variables: TVariables;
4629
+ control: CollectionControl<TFieldName, TFilter>;
4630
+ }
4631
+
4632
+ /**
4633
+ * Hook for managing collection query parameters (filters, sort, pagination)
4634
+ * with metadata-based field name typing and automatic `fieldType` detection.
4635
+ *
4636
+ * Returns `variables` with `query`, `order`, and `pagination` sub-properties
4637
+ * that can be mapped to GraphQL query variables.
4638
+ *
4639
+ * @example
4640
+ * ```tsx
4641
+ * import { tableMetadata } from "./generated/data-viewer-metadata.generated";
4642
+ *
4643
+ * const { variables } = useCollectionVariables({
4644
+ * tableMetadata: tableMetadata.task,
4645
+ * params: { pageSize: 20 },
4646
+ * });
4647
+ * const { query, order, pagination } = variables;
4648
+ * const [result] = useQuery({
4649
+ * query: GET_TASKS,
4650
+ * variables: { ...pagination, query, order },
4651
+ * });
4652
+ * ```
4653
+ */
4654
+ export declare function useCollectionVariables<const TTable extends TableMetadata>(options: UseCollectionOptions<TableFieldName<TTable>, TableMetadataFilter<TTable>> & {
4655
+ tableMetadata: TTable;
4656
+ }): UseCollectionReturn<TableFieldName<TTable>, {
4657
+ query: BuildQueryVariables<TTable> | undefined;
4658
+ order: {
4659
+ field: TableOrderableFieldName<TTable>;
4660
+ direction: "Asc" | "Desc";
4661
+ }[] | undefined;
4662
+ pagination: PaginationVariables;
4663
+ }, TableMetadataFilter<TTable>>;
4664
+
4665
+ /**
4666
+ * Hook for managing collection query parameters (filters, sort, pagination).
4667
+ *
4668
+ * Returns `variables` with `query`, `order`, and `pagination` sub-properties
4669
+ * that can be mapped to GraphQL query variables.
4670
+ *
4671
+ * @example
4672
+ * ```tsx
4673
+ * const { variables } = useCollectionVariables({ params: { pageSize: 20 } });
4674
+ * const { query, order, pagination } = variables;
4675
+ * const [result] = useQuery({
4676
+ * query: GET_ORDERS,
4677
+ * variables: { ...pagination, query, order },
4678
+ * });
4679
+ * ```
4680
+ */
4681
+ export declare function useCollectionVariables(options: UseCollectionOptions & {
4682
+ tableMetadata?: never;
4683
+ }): UseCollectionReturn<string, CollectionVariables>;
4684
+
3864
4685
  /**
3865
4686
  * Hook that encapsulates the "creatable" combobox pattern — allowing users
3866
4687
  * to create new items on-the-fly from the dropdown.
@@ -4020,6 +4841,148 @@ declare type UseCsvImporterOptions<T extends CsvSchema> = {
4020
4841
  maxFileSize?: number;
4021
4842
  };
4022
4843
 
4844
+ /**
4845
+ * Hook that integrates data management, column visibility, row operations, and
4846
+ * sort/pagination state for the `DataTable.*` compound component.
4847
+ *
4848
+ * @example
4849
+ * ```tsx
4850
+ * const { variables, control } = useCollectionVariables({ params: { pageSize: 20 } });
4851
+ * const [result] = useQuery({
4852
+ * query: GET_ORDERS,
4853
+ * variables: { ...variables.pagination, query: variables.query, order: variables.order },
4854
+ * });
4855
+ *
4856
+ * const table = useDataTable<Order>({
4857
+ * columns,
4858
+ * data: {
4859
+ * rows: result.data?.orders?.edges.map(e => e.node) ?? [],
4860
+ * pageInfo: { ... },
4861
+ * total: result.data?.orders?.total,
4862
+ * },
4863
+ * loading: result.fetching,
4864
+ * control,
4865
+ * });
4866
+ *
4867
+ * <DataTable.Root value={table}>
4868
+ * <DataTable.Table />
4869
+ * <DataTable.Footer>
4870
+ * <DataTable.Pagination />
4871
+ * </DataTable.Footer>
4872
+ * </DataTable.Root>
4873
+ * ```
4874
+ */
4875
+ export declare function useDataTable<TRow extends Record<string, unknown>, TFieldName extends string = string, TFilter extends Filter<TFieldName> = Filter<TFieldName>>(options: UseDataTableOptions<TRow, TFieldName, TFilter>): UseDataTableReturn<TRow>;
4876
+
4877
+ /**
4878
+ * Hook to access the full DataTable state (rows, columns, sorting, pagination,
4879
+ * column visibility, and row operations) from the nearest `DataTable.Root`.
4880
+ *
4881
+ * This hook is intentionally part of the public API to support **custom
4882
+ * sub-components** rendered inside `DataTable.Root`. Use it when the built-in
4883
+ * `DataTable.*` sub-components (Table, Toolbar, Pagination, etc.) are not
4884
+ * sufficient and you need to build your own compound component that reads from
4885
+ * or writes to the same DataTable context — for example, a column-visibility
4886
+ * toggle panel or a custom row-action toolbar.
4887
+ *
4888
+ * For most use cases, prefer passing values from `useDataTable()` as props
4889
+ * rather than reaching into the context directly.
4890
+ *
4891
+ * @throws Error if used outside of `DataTable.Root`.
4892
+ */
4893
+ export declare function useDataTableContext<TRow extends Record<string, unknown>>(): DataTableContextValue<TRow>;
4894
+
4895
+ /**
4896
+ * Options for `useDataTable` hook.
4897
+ */
4898
+ export declare type UseDataTableOptions<TRow extends Record<string, unknown>, TFieldName extends string = string, TFilter extends Filter<TFieldName> = Filter<TFieldName>> = {
4899
+ /** Column definitions that describe what to render in each column. */
4900
+ columns: Column<TRow>[];
4901
+ /**
4902
+ * Fetched data to display. Pass `undefined` while loading; the table will
4903
+ * show a loading state automatically.
4904
+ */
4905
+ data: DataTableData<TRow> | undefined;
4906
+ /** When `true`, the table renders a loading indicator. */
4907
+ loading?: boolean;
4908
+ /** If set, an error message is rendered in the table body. */
4909
+ error?: Error | null;
4910
+ /**
4911
+ * Collection control returned by `useCollectionVariables()`. Required when
4912
+ * using `DataTable.Pagination` or `DataTable.Filters`.
4913
+ */
4914
+ control?: CollectionControl<TFieldName, TFilter>;
4915
+ /** Called when the user clicks a row. Adds a pointer cursor to rows. */
4916
+ onClickRow?: (row: TRow) => void;
4917
+ /**
4918
+ * Per-row action items rendered in a kebab-menu column on the right.
4919
+ * The column is omitted when this array is empty or not provided.
4920
+ */
4921
+ rowActions?: RowAction<TRow>[];
4922
+ /**
4923
+ * Called with the current array of selected row IDs whenever the selection
4924
+ * changes. Providing this prop enables the checkbox selection column.
4925
+ * Selection is ID-based (`row.id`) and persists across page changes.
4926
+ *
4927
+ * **Requirement:** Each row must have a string or number `id` field.
4928
+ * Rows without `id` are excluded from selection.
4929
+ *
4930
+ * **Note:** `selectAllRows` (triggered by the header checkbox) selects only
4931
+ * the rows on the **current page**, not all pages.
4932
+ */
4933
+ onSelectionChange?: (ids: string[]) => void;
4934
+ };
4935
+
4936
+ /**
4937
+ * Return type of `useDataTable` hook.
4938
+ */
4939
+ export declare interface UseDataTableReturn<TRow extends Record<string, unknown>> {
4940
+ rows: TRow[];
4941
+ loading: boolean;
4942
+ error: Error | null;
4943
+ sortStates: SortState[];
4944
+ onSort?: (field: string, direction?: "Asc" | "Desc") => void;
4945
+ pageInfo: PageInfo;
4946
+ total: number | null;
4947
+ totalPages: number | null;
4948
+ nextPage: (cursor: string) => void;
4949
+ prevPage: (cursor: string) => void;
4950
+ hasPrevPage: boolean;
4951
+ hasNextPage: boolean;
4952
+ columns: Column<TRow>[];
4953
+ visibleColumns: Column<TRow>[];
4954
+ toggleColumn: (fieldOrId: string) => void;
4955
+ showAllColumns: () => void;
4956
+ hideAllColumns: () => void;
4957
+ isColumnVisible: (fieldOrId: string) => boolean;
4958
+ /**
4959
+ * The resolved page size derived from the collection control.
4960
+ * `0` when no control (or `pageSize`) is configured.
4961
+ * Used by `DataTable.Table` to render the correct number of skeleton / ghost rows.
4962
+ */
4963
+ pageSize: number;
4964
+ /**
4965
+ * The collection control passed to `useDataTable`, stored here for
4966
+ * forwarding to `DataTable.Root`.
4967
+ *
4968
+ * **Note:** The type is widened to `CollectionControl` (i.e.
4969
+ * `CollectionControl<string>`) here — field-name and operator narrowing from
4970
+ * `useCollectionVariables({ tableMetadata })` is lost. For type-safe
4971
+ * `addFilter` calls, use the `control` returned directly by
4972
+ * `useCollectionVariables` rather than accessing it via this field.
4973
+ */
4974
+ control: CollectionControl | undefined;
4975
+ onClickRow?: (row: TRow) => void;
4976
+ rowActions?: RowAction<TRow>[];
4977
+ selectedIds: string[];
4978
+ isRowSelected: (row: TRow) => boolean;
4979
+ toggleRowSelection?: (row: TRow) => void;
4980
+ selectAllRows?: () => void;
4981
+ clearSelection?: () => void;
4982
+ isAllSelected: boolean;
4983
+ isIndeterminate: boolean;
4984
+ }
4985
+
4023
4986
  export { useLocation }
4024
4987
 
4025
4988
  export { useNavigate }