@ethanhann/mantine-dataview 0.2.0 → 0.4.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/README.md CHANGED
@@ -18,13 +18,16 @@ Built on [Mantine](https://mantine.dev) v9 and [TanStack Table](https://tanstack
18
18
  - Column data types (`text`, `number`, `currency`, `date`, `boolean`) with automatic Intl-based formatting.
19
19
  - Seven filter variants with smart controls: `SegmentedControl` for booleans, `RangeSlider` for bounded numbers,
20
20
  `DatePickerInput` for dates.
21
- - Custom filter components bring your own UI per column.
21
+ - Custom filter components. Bring your own UI per column.
22
22
  - Column pinning (left/right) with sticky positioning.
23
23
  - CSV export with optional formatted output.
24
24
  - Router-agnostic URL state sync with a default History-API adapter.
25
25
  - Cross-page row selection + a shared bulk-action bar.
26
26
  - Column-meta card composition (`title`/`subtitle`/`media`/`badge`/`meta`) + a `renderCard` escape hatch.
27
27
  - Responsive: force-to-cards below a breakpoint, filters collapse to a bottom drawer on mobile.
28
+ - Faceted search with server-provided counts on filter options and range buckets with dynamic totals.
29
+ - External parameters (`params`) for scope selectors, toggles, and other non-column filters.
30
+ - Controls automatically disabled while data is loading (opt-out with `disableWhileLoading`).
28
31
  - Loading / empty / filtered-empty / error states, consistent across both views.
29
32
  - Dark mode support via Mantine's color scheme system.
30
33
  - Strongly typed end to end; ships its own `.d.ts`. No icon dependency.
@@ -58,7 +61,7 @@ The easiest path is `useDataViewFetcher`, which owns the fetch lifecycle for you
58
61
 
59
62
  ```tsx
60
63
  import {
61
- DataView,
64
+ DataViewer,
62
65
  useDataViewFetcher,
63
66
  createColumnHelper,
64
67
  type DataColumnDef,
@@ -101,11 +104,11 @@ function Users() {
101
104
  },
102
105
  });
103
106
 
104
- return <DataView view={view}/>;
107
+ return <DataViewer view={view}/>;
105
108
  }
106
109
  ```
107
110
 
108
- `<DataView view={view} />` renders the toolbar, the active presentation, and pagination.
111
+ `<DataViewer view={view} />` renders the toolbar, the active presentation, and pagination.
109
112
 
110
113
  ## Column builder
111
114
 
@@ -153,12 +156,12 @@ or object to merge), `format`, `align`, `cell`, `enableSorting`.
153
156
  Compose your own layout by passing children:
154
157
 
155
158
  ```tsx
156
- <DataView view={view}>
157
- <DataView.Toolbar/>
158
- <DataView.BulkActions/>
159
- <DataView.Body/>
160
- <DataView.Pagination/>
161
- </DataView>
159
+ <DataViewer view={view}>
160
+ <DataViewer.Toolbar/>
161
+ <DataViewer.BulkActions/>
162
+ <DataViewer.Body/>
163
+ <DataViewer.Pagination/>
164
+ </DataViewer>
162
165
  ```
163
166
 
164
167
  Or use the standalone components directly for full control:
@@ -169,10 +172,54 @@ Or use the standalone components directly for full control:
169
172
  <DataPagination view={view}/>
170
173
  ```
171
174
 
175
+ ### Toolbar sections
176
+
177
+ Inject controls into the toolbar without rebuilding it from scratch using `leftSection`
178
+ and `rightSection`:
179
+
180
+ ```tsx
181
+ <DataViewer.Toolbar
182
+ leftSection={<Text fw={600}>Users</Text>}
183
+ rightSection={
184
+ <Group gap="xs">
185
+ <Button size="xs" onClick={() => view.exportCsv()}>Export</Button>
186
+ <Button size="xs" onClick={() => view.refetch()}>Refresh</Button>
187
+ </Group>
188
+ }
189
+ />
190
+ ```
191
+
192
+ - `leftSection` renders before the search input (start of the left group).
193
+ - `rightSection` renders after the view switcher (end of the right group).
194
+
195
+ Both sections are disabled during loading along with the other toolbar controls.
196
+
197
+ ### View switcher
198
+
199
+ The `ViewSwitcher` is exported for standalone use with customizable labels:
200
+
201
+ ```tsx
202
+ import { ViewSwitcher } from "@ethanhann/mantine-dataview";
203
+
204
+ // Default
205
+ <ViewSwitcher view={view} />
206
+
207
+ // Custom labels (text or icons)
208
+ <ViewSwitcher view={view} tableLabel="List" cardsLabel="Grid" />
209
+ <ViewSwitcher view={view} tableLabel={<IconList />} cardsLabel={<IconGrid />} />
210
+ ```
211
+
212
+ Or drive the view programmatically:
213
+
214
+ ```tsx
215
+ view.setView("cards"); // switch to cards
216
+ view.view; // current view: "table" | "cards"
217
+ ```
218
+
172
219
  ## Controlled (bring your own data layer)
173
220
 
174
- `useDataViewFetcher` is a thin convenience wrapper. The core, `useDataView`, is fully controlled
175
- you supply `rows`/`rowCount`/`status` and respond to `onRequestChange`:
221
+ `useDataViewFetcher` is a thin convenience wrapper. The core, `useDataView`, is fully controlled.
222
+ You supply `rows`/`rowCount`/`status` and respond to `onRequestChange`:
176
223
 
177
224
  ```tsx
178
225
  const [resp, setResp] = useState({rows: [], rowCount: 0});
@@ -198,21 +245,50 @@ const view = useDataView<User>({
198
245
 
199
246
  The request is emitted immediately for pagination/sorting and debounced for search/filters.
200
247
 
248
+ ### External parameters
249
+
250
+ Pass arbitrary parameters that aren't tied to a column. They're included in every
251
+ `DataViewRequest`, trigger a refetch when they change, and reset pagination to page 1:
252
+
253
+ ```tsx
254
+ const [tenantId, setTenantId] = useState("acme");
255
+ const [showArchived, setShowArchived] = useState(false);
256
+
257
+ const view = useDataViewFetcher<User>({
258
+ columns,
259
+ getRowId,
260
+ fetcher: async (request) => {
261
+ // request.params = { tenantId: "acme", showArchived: false }
262
+ const res = await api.list(request);
263
+ return {rows: res.items, rowCount: res.total};
264
+ },
265
+ params: {tenantId, showArchived},
266
+ });
267
+
268
+ // Render your own controls...
269
+ <Select data={tenants} value={tenantId} onChange={setTenantId}/>
270
+ <Switch checked={showArchived} onChange={(e) => setShowArchived(e.currentTarget.checked)}/>
271
+ ```
272
+
273
+ Values are typed as `FilterParam` (`string | number | boolean | null | string[] | number[]`).
274
+
201
275
  ### Refetching on external changes
202
276
 
203
- When state outside the dataview (e.g. a tenant selector, date range from another component)
204
- should trigger a refetch, pass it in `deps`:
277
+ For cases where external state affects the fetcher but isn't a named parameter (e.g. it's
278
+ baked into the closure), use `deps` to trigger a refetch:
205
279
 
206
280
  ```tsx
207
281
  const view = useDataViewFetcher<User>({
208
282
  columns,
209
283
  getRowId,
210
284
  fetcher,
211
- deps: [selectedTenantId, externalDateRange],
285
+ deps: [selectedTenantId],
212
286
  });
213
287
  ```
214
288
 
215
289
  When any value in `deps` changes, the current request is re-emitted to the fetcher.
290
+ Prefer `params` when the server needs to see the values; use `deps` when they're already
291
+ in the fetcher closure.
216
292
 
217
293
  ### Manual refresh
218
294
 
@@ -230,7 +306,7 @@ error retry button uses.
230
306
  Set `dataType` on a column's meta to enable automatic value formatting. When no explicit
231
307
  `cell` renderer is provided, the library formats values using `Intl.NumberFormat` or
232
308
  `Intl.DateTimeFormat` based on the data type. Raw values are preserved for server requests,
233
- sorting, and filtering formatting is display-only.
309
+ sorting, and filtering. Formatting is display-only.
234
310
 
235
311
  ```tsx
236
312
  col.accessor("price", {
@@ -254,9 +330,9 @@ col.accessor("createdAt", {
254
330
 
255
331
  ### Format overrides (three levels)
256
332
 
257
- 1. **Library defaults** built-in formatters per data type (above).
258
- 2. **Table-scoped** `formatDefaults` on the hook options, keyed by data type.
259
- 3. **Column-scoped** `format` on `ColumnMeta`, overrides everything for that column.
333
+ 1. **Library defaults**, the built-in formatters per data type (above).
334
+ 2. **Table-scoped**, `formatDefaults` on the hook options, keyed by data type.
335
+ 3. **Column-scoped**, `format` on `ColumnMeta`, overrides everything for that column.
260
336
 
261
337
  ```tsx
262
338
  const view = useDataViewFetcher({
@@ -315,7 +391,7 @@ col.accessor("avatar", {header: "Avatar", enableSorting: false});
315
391
 
316
392
  ## Custom headers
317
393
 
318
- Column headers support the same render function pattern as cells pass a component or
394
+ Column headers support the same render function pattern as cells. Pass a component or
319
395
  function to the `header` property:
320
396
 
321
397
  ```tsx
@@ -399,7 +475,7 @@ Define filters declaratively on column meta. Seven variants are built in:
399
475
  | `dateRange` | `DatePickerInput` (range) | Two-date calendar picker |
400
476
 
401
477
  ```tsx
402
- // Boolean renders as a segmented control
478
+ // Boolean, renders as a segmented control
403
479
  meta: {
404
480
  filter: {
405
481
  variant: "boolean"
@@ -465,19 +541,19 @@ col.accessor("location", {
465
541
  ```tsx
466
542
  import {FilterControl} from "@ethanhann/mantine-dataview";
467
543
 
468
- <DataView view={view}>
544
+ <DataViewer view={view}>
469
545
  {view.table.getColumn("inStock") && (
470
546
  <FilterControl column={view.table.getColumn("inStock")!}/>
471
547
  )}
472
- <DataView.Toolbar/>
473
- <DataView.Body/>
474
- <DataView.Pagination/>
475
- </DataView>
548
+ <DataViewer.Toolbar/>
549
+ <DataViewer.Body/>
550
+ <DataViewer.Pagination/>
551
+ </DataViewer>
476
552
  ```
477
553
 
478
554
  ### Programmatic filter control
479
555
 
480
- Reset all filters or clear a specific column from anywhere no need to be inside the toolbar:
556
+ Reset all filters or clear a specific column from anywhere, no need to be inside the toolbar:
481
557
 
482
558
  ```tsx
483
559
  // Reset all filters
@@ -494,6 +570,73 @@ Reset all filters or clear a specific column from anywhere — no need to be ins
494
570
  - **Mobile** (below `sm` breakpoint): always collapsed into a bottom drawer.
495
571
  - A "Reset filters" button appears automatically when any filter is active.
496
572
 
573
+ ## Faceted search
574
+
575
+ When the server returns `facets` in the response, filter controls automatically adapt to show
576
+ dynamic counts, disable zero-result options, and render clickable range buckets.
577
+
578
+ ### Server response with facets
579
+
580
+ ```tsx
581
+ fetcher: async (request) => {
582
+ const res = await api.list(request);
583
+ return {
584
+ rows: res.items,
585
+ rowCount: res.total,
586
+ facets: {
587
+ size: {
588
+ type: "values",
589
+ values: [
590
+ { value: "S", label: "Small", count: 12 },
591
+ { value: "M", label: "Medium", count: 34 },
592
+ { value: "L", label: "Large", count: 0 },
593
+ ],
594
+ },
595
+ price: {
596
+ type: "ranges",
597
+ ranges: [
598
+ { label: "Under $25", from: 0, to: 25, count: 15 },
599
+ { label: "$25-$50", from: 25, to: 50, count: 28 },
600
+ { label: "$50+", from: 50, to: 999, count: 7 },
601
+ ],
602
+ min: 5,
603
+ max: 249,
604
+ },
605
+ },
606
+ };
607
+ };
608
+ ```
609
+
610
+ ### How controls adapt
611
+
612
+ | Filter type | Without facets | With value facets | With range facets |
613
+ |------------|---------------|-------------------|-------------------|
614
+ | Select | Static options | Options with counts, zero-count dimmed | - |
615
+ | Boolean | All / Yes / No | All / Yes (12) / No (3) | - |
616
+ | Number range | Slider or inputs | Slider (bounds from facet) | Clickable range buckets + slider |
617
+ | Date range | Date picker | Date picker | Clickable range buckets + picker |
618
+
619
+ Facets are optional and backward compatible. Facet data updates on every fetch, creating the
620
+ classic faceted search loop where filtering one dimension updates counts on all others.
621
+
622
+ ### Facet types
623
+
624
+ ```ts
625
+ // Discrete values - for select, multiselect, boolean filters
626
+ type ValueFacet = {
627
+ type: "values";
628
+ values: { value: string; label?: string; count: number }[];
629
+ };
630
+
631
+ // Bucketed ranges - for numberRange, dateRange filters
632
+ type RangeFacet = {
633
+ type: "ranges";
634
+ ranges: { label: string; from: number | string; to: number | string; count: number }[];
635
+ min?: number | string;
636
+ max?: number | string;
637
+ };
638
+ ```
639
+
497
640
  ## Card composition
498
641
 
499
642
  In card view, each visible column is placed by its `meta.card.role`:
@@ -515,7 +658,7 @@ role group, columns are ordered by `meta.card.order`.
515
658
  For full control over card content, use `renderCard`:
516
659
 
517
660
  ```tsx
518
- <DataView
661
+ <DataViewer
519
662
  view={view}
520
663
  renderCard={({data, selected, toggleSelected}) => (
521
664
  <Card withBorder padding="md" onClick={toggleSelected}>
@@ -530,7 +673,7 @@ For full control over card content, use `renderCard`:
530
673
  To keep the default composition but wrap it in a custom card shell, use the `Card` slot:
531
674
 
532
675
  ```tsx
533
- <DataView
676
+ <DataViewer
534
677
  view={view}
535
678
  slots={{
536
679
  Card: ({data, selected, children}) => (
@@ -551,7 +694,7 @@ To keep the default composition but wrap it in a custom card shell, use the `Car
551
694
  Provide a `BulkActions` slot to add actions when rows are selected:
552
695
 
553
696
  ```tsx
554
- <DataView
697
+ <DataViewer
555
698
  view={view}
556
699
  slots={{
557
700
  BulkActions: (selection) => (
@@ -578,7 +721,7 @@ The `selection` object provides `count`, `ids` (all selected row IDs across page
578
721
  Override loading, empty, and error states:
579
722
 
580
723
  ```tsx
581
- <DataView
724
+ <DataViewer
582
725
  view={view}
583
726
  slots={{
584
727
  Empty: () => <Text>No users found.</Text>,
@@ -594,7 +737,7 @@ Override loading, empty, and error states:
594
737
  />
595
738
  ```
596
739
 
597
- A filtered-empty state is handled automatically it shows a "clear filters" action so
740
+ A filtered-empty state is handled automatically. It shows a "clear filters" action so
598
741
  users can reset without manually removing each filter.
599
742
 
600
743
  ## URL state sync
@@ -690,7 +833,7 @@ const view = useDataViewFetcher<User>({
690
833
  responsive: {forceCardsBelow: "sm", lockSwitcherOnMobile: true},
691
834
  });
692
835
 
693
- <DataView view={view} lockSwitcherOnMobile/>;
836
+ <DataViewer view={view} lockSwitcherOnMobile/>;
694
837
  ```
695
838
 
696
839
  When `forceCardsBelow` is set and the viewport is below that breakpoint:
@@ -700,23 +843,56 @@ When `forceCardsBelow` is set and the viewport is below that breakpoint:
700
843
  - The view switcher is disabled (or hidden entirely with `lockSwitcherOnMobile`).
701
844
  - Filters always open in a bottom drawer on mobile.
702
845
 
846
+ ## Loading behavior
847
+
848
+ By default, filter controls, sort controls, and column visibility/pinning menus are disabled
849
+ while data is loading. Sort headers in the table also become non-interactive, with a dimmed
850
+ appearance showing the current sort state. The search input stays enabled so users can keep
851
+ typing during debounced search.
852
+
853
+ Opt out per component:
854
+
855
+ ```tsx
856
+ <DataTable view={view} disableWhileLoading={false} />
857
+ <DataToolbar view={view} disableWhileLoading={false} />
858
+ ```
859
+
860
+ ### Animated row transitions
861
+
862
+ Instead of skeleton loading, rows can animate in and out with CSS transitions. New rows
863
+ fade and slide in, removed rows fade out, and unchanged rows stay in place:
864
+
865
+ ```tsx
866
+ <DataViewer view={view} animateRows />
867
+ ```
868
+
869
+ When `animateRows` is enabled:
870
+ - Previous rows stay visible while new data loads (no skeleton flash).
871
+ - New rows enter with a slide-down fade-in animation (200ms).
872
+ - Removed rows fade out (150ms) before being removed from the DOM.
873
+ - Works in both table and card views.
874
+
875
+ This is opt-in. The default behavior (skeleton loading) is unchanged.
876
+
703
877
  ## API overview
704
878
 
705
879
  | Export | Purpose |
706
880
  |----------------------------------------------------------------------|-----------------------------------------------|
707
- | `useDataView` | Headless core owns all feature state |
881
+ | `useDataView` | Headless core, owns all feature state |
708
882
  | `useDataViewFetcher` | Convenience wrapper that manages the fetch |
709
- | `DataView` (+ `.Toolbar` / `.BulkActions` / `.Body` / `.Pagination`) | Orchestrator + compound parts |
883
+ | `DataViewer` (+ `.Toolbar` / `.BulkActions` / `.Body` / `.Pagination`) | Orchestrator + compound parts |
710
884
  | `DataTable`, `DataCards` | The two presentations (usable standalone) |
711
885
  | `DataToolbar`, `DataPagination`, `DataBulkActions` | Standalone affordances |
712
886
  | `FilterControl` | Individual filter control (place anywhere) |
887
+ | `ViewSwitcher` | Table/Cards toggle (customizable labels) |
713
888
  | `exportCsv` | Standalone CSV export utility |
889
+ | `col` | Fluent column builder factory |
714
890
  | `createColumnHelper`, `composeCardLayout`, `resolveColumnLabel` | Column helpers |
715
891
  | `@ethanhann/mantine-dataview/url` | `windowHistoryAdapter` + serializer utilities |
716
892
 
717
893
  ### Customization slots
718
894
 
719
- Passed via the `slots` prop on `DataView` or the presentation components:
895
+ Passed via the `slots` prop on `DataViewer` or the presentation components:
720
896
 
721
897
  | Slot | Receives | Purpose |
722
898
  |----------------|-------------------------------------|----------------------------|
@@ -730,20 +906,20 @@ Passed via the `slots` prop on `DataView` or the presentation components:
730
906
 
731
907
  ## Known issues
732
908
 
733
- ### `DataView` name shadows the JS global
909
+ ### `DataViewer` name shadows the JS global
734
910
 
735
- The `DataView` component shares its name with the JavaScript `DataView` global (typed arrays).
911
+ The `DataViewer` component shares its name with the JavaScript `DataViewer` global (typed arrays).
736
912
  Linters like Biome's `noShadowRestrictedNames` will flag the import. Suppress it with:
737
913
 
738
914
  ```tsx
739
915
  // biome-ignore lint/suspicious/noShadowRestrictedNames: component name
740
- import {DataView} from "@ethanhann/mantine-dataview";
916
+ import {DataViewer} from "@ethanhann/mantine-dataview";
741
917
  ```
742
918
 
743
919
  Or import with an alias:
744
920
 
745
921
  ```tsx
746
- import {DataView as MantineDataView} from "@ethanhann/mantine-dataview";
922
+ import {DataViewer as MantineDataView} from "@ethanhann/mantine-dataview";
747
923
  ```
748
924
 
749
925
  ## Development
@@ -20,5 +20,7 @@ export interface DataCardsProps<TData> extends Omit<SimpleGridProps, "children">
20
20
  enableSelection?: boolean;
21
21
  /** Skeleton cards shown while loading. It defaults to the current page size, capped at 6. */
22
22
  loadingCardCount?: number;
23
+ /** Animate card enter/exit instead of showing skeletons. Default: false. */
24
+ animateRows?: boolean;
23
25
  }
24
- export declare function DataCards<TData>({ view, slots, renderCard, fallbackRole, enableSelection, loadingCardCount, cols, ...gridProps }: DataCardsProps<TData>): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
26
+ export declare function DataCards<TData>({ view, slots, renderCard, fallbackRole, enableSelection, loadingCardCount, animateRows, cols, ...gridProps }: DataCardsProps<TData>): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import('react').ReactPortal | import('react').ReactElement<unknown, string | import('react').JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
@@ -9,5 +9,9 @@ export interface DataTableProps<TData> extends Omit<TableProps, "data" | "childr
9
9
  enableSelection?: boolean;
10
10
  /** Skeleton rows shown while loading. It defaults to the current page size, capped at 8. */
11
11
  loadingRowCount?: number;
12
+ /** Disable sorting interactions while data is loading. Default: true. */
13
+ disableWhileLoading?: boolean;
14
+ /** Animate row enter/exit instead of showing skeletons. Default: false. */
15
+ animateRows?: boolean;
12
16
  }
13
- export declare function DataTable<TData>({ view, slots, enableSelection, loadingRowCount, ...tableProps }: DataTableProps<TData>): import("react").JSX.Element;
17
+ export declare function DataTable<TData>({ view, slots, enableSelection, loadingRowCount, disableWhileLoading, animateRows, ...tableProps }: DataTableProps<TData>): import("react").JSX.Element;
@@ -1,4 +1,5 @@
1
1
  import { GroupProps } from '@mantine/core';
2
+ import { ReactNode } from 'react';
2
3
  import { UseDataViewReturn } from '../../types/options';
3
4
  export interface DataToolbarProps<TData> extends Omit<GroupProps, "children"> {
4
5
  /** The `useDataView` instance to drive. */
@@ -12,5 +13,11 @@ export interface DataToolbarProps<TData> extends Omit<GroupProps, "children"> {
12
13
  showSort?: boolean;
13
14
  showVisibility?: boolean;
14
15
  showViewSwitcher?: boolean;
16
+ /** Disable search, filter, and sort controls while data is loading. Default: true. */
17
+ disableWhileLoading?: boolean;
18
+ /** Content injected at the start of the left control group (before search). */
19
+ leftSection?: ReactNode;
20
+ /** Content injected at the end of the right control group (after view switcher). */
21
+ rightSection?: ReactNode;
15
22
  }
16
- export declare function DataToolbar<TData>({ view, searchPlaceholder, filterInlineThreshold, lockSwitcherOnMobile, showSearch, showFilters, showSort, showVisibility, showViewSwitcher, ...groupProps }: DataToolbarProps<TData>): import("react").JSX.Element;
23
+ export declare function DataToolbar<TData>({ view, searchPlaceholder, filterInlineThreshold, lockSwitcherOnMobile, showSearch, showFilters, showSort, showVisibility, showViewSwitcher, disableWhileLoading, leftSection, rightSection, ...groupProps }: DataToolbarProps<TData>): import("react").JSX.Element;
@@ -1,5 +1,11 @@
1
+ import { ReactNode } from 'react';
1
2
  import { UseDataViewReturn } from '../../types/options';
2
- export declare function ViewSwitcher<TData>({ view, lockSwitcherOnMobile, }: {
3
+ export interface ViewSwitcherProps<TData> {
3
4
  view: UseDataViewReturn<TData>;
4
5
  lockSwitcherOnMobile?: boolean;
5
- }): import("react").JSX.Element | null;
6
+ /** Custom label for the table option. Default: "Table". */
7
+ tableLabel?: ReactNode;
8
+ /** Custom label for the cards option. Default: "Cards". */
9
+ cardsLabel?: ReactNode;
10
+ }
11
+ export declare function ViewSwitcher<TData>({ view, lockSwitcherOnMobile, tableLabel, cardsLabel, }: ViewSwitcherProps<TData>): import("react").JSX.Element | null;
@@ -1,2 +1,3 @@
1
1
  export { DataToolbar, type DataToolbarProps } from './DataToolbar';
2
2
  export { FilterControl } from './FilterControl';
3
+ export { ViewSwitcher, type ViewSwitcherProps } from './ViewSwitcher';
@@ -7,30 +7,32 @@ import { DataPaginationProps } from '../DataPagination';
7
7
  import { DataTableProps } from '../DataTable';
8
8
  import { DataToolbarProps } from '../DataToolbar';
9
9
  import { DataViewSlots } from '../types';
10
- export interface DataViewProps<TData> extends Omit<StackProps, "children"> {
10
+ export interface DataViewerProps<TData> extends Omit<StackProps, "children"> {
11
11
  /** The `useDataView` instance to project. */
12
12
  view: UseDataViewReturn<TData>;
13
13
  slots?: DataViewSlots<TData>;
14
14
  renderCard?: DataCardsProps<TData>["renderCard"];
15
15
  fallbackRole?: DataCardsProps<TData>["fallbackRole"];
16
16
  lockSwitcherOnMobile?: boolean;
17
+ /** Animate row enter/exit instead of showing skeletons. Default: false. */
18
+ animateRows?: boolean;
17
19
  /** Custom composition. It defaults to Toolbar, BulkActions, Body, and Pagination. */
18
20
  children?: ReactNode;
19
21
  }
20
- export declare function DataView<TData>({ view, slots, renderCard, fallbackRole, lockSwitcherOnMobile, children, ...stackProps }: DataViewProps<TData>): import("react").JSX.Element;
21
- export declare namespace DataView {
22
+ export declare function DataViewer<TData>({ view, slots, renderCard, fallbackRole, lockSwitcherOnMobile, animateRows, children, ...stackProps }: DataViewerProps<TData>): import("react").JSX.Element;
23
+ export declare namespace DataViewer {
22
24
  var Toolbar: typeof DataViewToolbar;
23
25
  var BulkActions: typeof DataViewBulkActions;
24
26
  var Body: typeof DataViewBody;
25
27
  var Pagination: typeof DataViewPagination;
26
28
  }
27
- export type DataViewToolbarProps<TData> = Omit<DataToolbarProps<TData>, "view">;
28
- declare function DataViewToolbar<TData>(props: DataViewToolbarProps<TData>): import("react").JSX.Element;
29
- export interface DataViewBodyProps<TData> {
29
+ export type DataViewerToolbarProps<TData> = Omit<DataToolbarProps<TData>, "view">;
30
+ declare function DataViewToolbar<TData>(props: DataViewerToolbarProps<TData>): import("react").JSX.Element;
31
+ export interface DataViewerBodyProps<TData> {
30
32
  tableProps?: Omit<DataTableProps<TData>, "view" | "slots">;
31
33
  cardsProps?: Omit<DataCardsProps<TData>, "view" | "slots" | "renderCard" | "fallbackRole">;
32
34
  }
33
- declare function DataViewBody<TData>({ tableProps, cardsProps, }: DataViewBodyProps<TData>): import("react").JSX.Element;
35
+ declare function DataViewBody<TData>({ tableProps, cardsProps, }: DataViewerBodyProps<TData>): import("react").JSX.Element;
34
36
  declare function DataViewPagination<TData>(props: Omit<DataPaginationProps<TData>, "view">): import("react").JSX.Element;
35
37
  declare function DataViewBulkActions<TData>(props: Omit<DataBulkActionsProps<TData>, "view" | "slots">): import("react").JSX.Element;
36
38
  export {};
@@ -8,6 +8,7 @@ export interface DataViewContextValue<TData> {
8
8
  renderCard?: DataCardsProps<TData>["renderCard"];
9
9
  fallbackRole?: ComposeCardOptions["fallbackRole"];
10
10
  lockSwitcherOnMobile?: boolean;
11
+ animateRows?: boolean;
11
12
  }
12
13
  export declare const DataViewProvider: import('react').Provider<DataViewContextValue<unknown> | null>;
13
14
  export declare function useDataViewContext<TData>(): DataViewContextValue<TData>;
@@ -0,0 +1,2 @@
1
+ export { type DataViewContextValue, useDataViewContext, } from './context';
2
+ export { DataViewer, type DataViewerBodyProps, type DataViewerProps, type DataViewerToolbarProps, } from './DataViewer';
@@ -0,0 +1,8 @@
1
+ import { Row } from '@tanstack/react-table';
2
+ export interface RowTransitionResult<TData> {
3
+ rows: Row<TData>[];
4
+ entering: Set<string>;
5
+ /** Increments each time the row set or order changes. Use as a CSS animation key. */
6
+ generation: number;
7
+ }
8
+ export declare function useRowTransition<TData>(currentRows: Row<TData>[], enabled: boolean): RowTransitionResult<TData>;