@cerberus-design/data-grid 0.25.3

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.
Files changed (69) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +35 -0
  3. package/dist/column-helpers.cjs +24 -0
  4. package/dist/column-helpers.d.cts +45 -0
  5. package/dist/column-helpers.d.ts +45 -0
  6. package/dist/column-helpers.js +20 -0
  7. package/dist/components/cerby-data-grid.client.cjs +14 -0
  8. package/dist/components/cerby-data-grid.client.d.cts +6 -0
  9. package/dist/components/cerby-data-grid.client.d.ts +6 -0
  10. package/dist/components/cerby-data-grid.client.js +10 -0
  11. package/dist/components/count-menu.client.cjs +52 -0
  12. package/dist/components/count-menu.client.d.cts +6 -0
  13. package/dist/components/count-menu.client.d.ts +6 -0
  14. package/dist/components/count-menu.client.js +48 -0
  15. package/dist/components/data-grid.client.cjs +85 -0
  16. package/dist/components/data-grid.client.d.cts +4 -0
  17. package/dist/components/data-grid.client.d.ts +4 -0
  18. package/dist/components/data-grid.client.js +81 -0
  19. package/dist/components/features.client.cjs +79 -0
  20. package/dist/components/features.client.d.cts +2 -0
  21. package/dist/components/features.client.d.ts +2 -0
  22. package/dist/components/features.client.js +75 -0
  23. package/dist/components/grid.client.cjs +319 -0
  24. package/dist/components/grid.client.d.cts +19 -0
  25. package/dist/components/grid.client.d.ts +19 -0
  26. package/dist/components/grid.client.js +312 -0
  27. package/dist/components/pagination.client.cjs +116 -0
  28. package/dist/components/pagination.client.d.cts +1 -0
  29. package/dist/components/pagination.client.d.ts +1 -0
  30. package/dist/components/pagination.client.js +112 -0
  31. package/dist/components/pinned-items.client.cjs +70 -0
  32. package/dist/components/pinned-items.client.d.cts +5 -0
  33. package/dist/components/pinned-items.client.d.ts +5 -0
  34. package/dist/components/pinned-items.client.js +66 -0
  35. package/dist/components/sort-items.client.cjs +58 -0
  36. package/dist/components/sort-items.client.d.cts +4 -0
  37. package/dist/components/sort-items.client.d.ts +4 -0
  38. package/dist/components/sort-items.client.js +54 -0
  39. package/dist/const.cjs +49 -0
  40. package/dist/const.d.cts +28 -0
  41. package/dist/const.d.ts +28 -0
  42. package/dist/const.js +33 -0
  43. package/dist/context.client.cjs +18 -0
  44. package/dist/context.client.d.cts +7 -0
  45. package/dist/context.client.d.ts +7 -0
  46. package/dist/context.client.js +13 -0
  47. package/dist/hooks.client.cjs +29 -0
  48. package/dist/hooks.client.d.cts +7 -0
  49. package/dist/hooks.client.d.ts +7 -0
  50. package/dist/hooks.client.js +23 -0
  51. package/dist/index.cjs +15 -0
  52. package/dist/index.d.cts +9 -0
  53. package/dist/index.d.ts +9 -0
  54. package/dist/index.js +4 -0
  55. package/dist/store.cjs +287 -0
  56. package/dist/store.d.cts +6 -0
  57. package/dist/store.d.ts +6 -0
  58. package/dist/store.js +283 -0
  59. package/dist/types.d.cts +198 -0
  60. package/dist/types.d.ts +198 -0
  61. package/dist/utils.cjs +59 -0
  62. package/dist/utils.d.cts +6 -0
  63. package/dist/utils.d.ts +6 -0
  64. package/dist/utils.js +51 -0
  65. package/dist/virtualizer.client.cjs +56 -0
  66. package/dist/virtualizer.client.d.cts +11 -0
  67. package/dist/virtualizer.client.d.ts +11 -0
  68. package/dist/virtualizer.client.js +52 -0
  69. package/package.json +72 -0
@@ -0,0 +1,198 @@
1
+ import { PageDetails, EnforceNoProperties, PaginationRootProps } from '@cerberus-design/react';
2
+ import { Setter, Accessor } from '@cerberus-design/signals';
3
+ import { ReactNode } from 'react';
4
+ import { RowSize } from './const';
5
+ export interface GridOptions<TData> {
6
+ /**
7
+ * The full Array of data you want the grid to render.
8
+ */
9
+ data: TData[];
10
+ /**
11
+ * A list of Defined Columns created using the column helper.
12
+ */
13
+ columns: ColumnDef<TData>[];
14
+ /**
15
+ * Initial options for feature-related settings.
16
+ */
17
+ initialState?: {
18
+ pagination?: boolean | PaginationOptions;
19
+ };
20
+ /**
21
+ * Called when a user clicks on a pagination page trigger.
22
+ */
23
+ onPageChange?: (details: PageDetails) => void;
24
+ /**
25
+ * Content to display above the Data Grid and within the Grid context.
26
+ */
27
+ toolbar?: ReactNode;
28
+ /**
29
+ * Content to display below the Data Grid and within the Grid context.
30
+ */
31
+ footer?: ReactNode;
32
+ /**
33
+ * The visual spacing of cells within a row. Can be a predefined size or any
34
+ * valid CSS sizing value.
35
+ *
36
+ * **default**: 'md'.
37
+ */
38
+ rowSize?: RowSizeOptions;
39
+ }
40
+ export type ColumnDef<TData, TKey extends keyof TData = keyof TData> = {
41
+ id: string;
42
+ /**
43
+ * The label or custom compoent to display.
44
+ */
45
+ header: string | ((props: {
46
+ colId: string;
47
+ }) => ReactNode);
48
+ /**
49
+ * A helper to access and manage the preferred value of the cell.
50
+ */
51
+ accessor: DisplayColAccessor | AccessorAccessor<TData, TKey> | AccessorFn<TData>;
52
+ /**
53
+ * Strictly define the cell width. Expects a pixel-based number.
54
+ * @default 150px
55
+ */
56
+ minWidth?: number;
57
+ /**
58
+ * Strictly define the cell width. Expects a pixel-based number. If the width
59
+ * provided is smaller than what is required for features, the minimum width
60
+ * of 100px will be used instead.
61
+ * @default 150px
62
+ */
63
+ width?: number;
64
+ features?: ColumnFeatures<TData, TKey>;
65
+ /**
66
+ * The cell renderer. Provides access to the accessor value and row data. This
67
+ * is used to provide custom components for the cell content.
68
+ *
69
+ * If no content is provided a string will be rendered.
70
+ */
71
+ cell?: ColCell<TData>;
72
+ };
73
+ export type PaginationOptions = {
74
+ /**
75
+ * The total number of rows that exist. This is useful if you choose to use
76
+ * server-side pagination design.
77
+ */
78
+ count?: PaginationRootProps['count'];
79
+ /**
80
+ * The default page index to start on.
81
+ */
82
+ defaultPage?: PaginationRootProps['defaultPage'];
83
+ /**
84
+ * The default page size to start with. **Must be included in customRange if
85
+ * using any value other than 25, 50, or 100**.
86
+ *
87
+ * default: 0
88
+ */
89
+ pageSize?: PaginationRootProps['pageSize'];
90
+ /**
91
+ * A custom range of page sizes to display in the page size dropdown.
92
+ */
93
+ customRange?: number[];
94
+ };
95
+ export type AccessorOptions<TData, TKey extends keyof TData> = {
96
+ id?: string;
97
+ header: string | ((props: {
98
+ colId: string;
99
+ }) => ReactNode);
100
+ features?: ColumnFeatures<TData, TKey>;
101
+ width?: number;
102
+ minWidth?: number;
103
+ maxWidth?: number;
104
+ cell?: ColCell<TData>;
105
+ };
106
+ export type DisplayOptions<TData, TKey extends keyof TData> = {
107
+ id: string;
108
+ header: string | ((props: {
109
+ colId: string;
110
+ }) => ReactNode);
111
+ width?: number;
112
+ features?: {
113
+ pinning?: ColumnFeatures<TData, TKey>['pinning'];
114
+ };
115
+ cell: ColCell<TData>;
116
+ };
117
+ export type InternalColumn<TData> = {
118
+ id: string;
119
+ pinned: Accessor<PinnedState>;
120
+ isFlex: Accessor<boolean>;
121
+ isVisible: Accessor<boolean>;
122
+ width: Accessor<number>;
123
+ pinnable: boolean;
124
+ sortable: boolean;
125
+ filterable: boolean;
126
+ getValue: ColumnDef<TData>['accessor'];
127
+ original: ColumnDef<TData>;
128
+ setFlex: Setter<boolean>;
129
+ setColWidth: Setter<number>;
130
+ setPinned: Setter<PinnedState>;
131
+ };
132
+ export type SortState = {
133
+ id: string;
134
+ desc: boolean;
135
+ };
136
+ export interface GridStore<TData> {
137
+ columns: Accessor<InternalColumn<TData>[]>;
138
+ rows: Accessor<TData[]>;
139
+ globalFilter: Accessor<string>;
140
+ sorting: Accessor<SortState[]>;
141
+ pageIndex: Accessor<number>;
142
+ pageSize: Accessor<number>;
143
+ pageRange: Accessor<number[]>;
144
+ pageCount: Accessor<number>;
145
+ currentPageRange: Accessor<{
146
+ start: number;
147
+ end: number;
148
+ }>;
149
+ isServerPaginated: Accessor<boolean>;
150
+ rootCssVars: Accessor<Record<string, string>>;
151
+ rowCount: Accessor<number>;
152
+ rowSize: Accessor<number>;
153
+ totalWidth: Accessor<number>;
154
+ visibleRows: Accessor<TData[]>;
155
+ resizeColumn: (colId: string, delta: number) => void;
156
+ setContainerWidth: (val: number) => void;
157
+ setPage: (details: PageDetails) => void;
158
+ setPageSize: (size: number) => void;
159
+ setGlobalFilter: (val: string) => void;
160
+ setSort: (colId: string, direction: SortDirection, multi?: boolean) => void;
161
+ togglePinned: (colId: string, state: PinnedState) => void;
162
+ toggleSort: (colId: string, multi?: boolean) => void;
163
+ updateData: (newData: TData[]) => void;
164
+ }
165
+ export type RowSizeOptions = RowSize | number;
166
+ export type ColumnFeatures<TData, TKey extends keyof TData> = {
167
+ /**
168
+ * Allow the column to be sorted and the rules to use.
169
+ */
170
+ sort?: (boolean & EnforceNoProperties<SortOptions<TData, TKey>>) | SortOptions<TData, TKey>;
171
+ /**
172
+ * Allow the column to be filtered and the rules to use.
173
+ */
174
+ filter?: boolean | {
175
+ operator?: 'contains' | 'equals' | 'startsWith';
176
+ };
177
+ /**
178
+ * Show pinning options in the column menu
179
+ */
180
+ pinning?: (boolean & EnforceNoProperties<PinnedOptions>) | PinnedOptions;
181
+ };
182
+ export type PinnedOptions = {
183
+ defaultPosition?: PinnedState;
184
+ };
185
+ export type SortOptions<TData, TKey extends keyof TData> = {
186
+ firstSortDirection?: SortDirection;
187
+ comparator?: Comparator<TData[TKey]>;
188
+ };
189
+ export type ColCell<TData> = (props: {
190
+ row: TData;
191
+ value: any;
192
+ }) => ReactNode;
193
+ export type DisplayColAccessor = () => undefined;
194
+ export type AccessorAccessor<TData, TKey extends keyof TData> = (row: TData) => TData[TKey];
195
+ export type AccessorFn<TData> = (row: TData) => ReactNode;
196
+ export type Comparator<TValue> = (a: TValue, b: TValue) => number;
197
+ export type SortDirection = 'asc' | 'desc' | null;
198
+ export type PinnedState = 'left' | 'right' | undefined | boolean;
@@ -0,0 +1,198 @@
1
+ import { PageDetails, EnforceNoProperties, PaginationRootProps } from '@cerberus-design/react';
2
+ import { Setter, Accessor } from '@cerberus-design/signals';
3
+ import { ReactNode } from 'react';
4
+ import { RowSize } from './const';
5
+ export interface GridOptions<TData> {
6
+ /**
7
+ * The full Array of data you want the grid to render.
8
+ */
9
+ data: TData[];
10
+ /**
11
+ * A list of Defined Columns created using the column helper.
12
+ */
13
+ columns: ColumnDef<TData>[];
14
+ /**
15
+ * Initial options for feature-related settings.
16
+ */
17
+ initialState?: {
18
+ pagination?: boolean | PaginationOptions;
19
+ };
20
+ /**
21
+ * Called when a user clicks on a pagination page trigger.
22
+ */
23
+ onPageChange?: (details: PageDetails) => void;
24
+ /**
25
+ * Content to display above the Data Grid and within the Grid context.
26
+ */
27
+ toolbar?: ReactNode;
28
+ /**
29
+ * Content to display below the Data Grid and within the Grid context.
30
+ */
31
+ footer?: ReactNode;
32
+ /**
33
+ * The visual spacing of cells within a row. Can be a predefined size or any
34
+ * valid CSS sizing value.
35
+ *
36
+ * **default**: 'md'.
37
+ */
38
+ rowSize?: RowSizeOptions;
39
+ }
40
+ export type ColumnDef<TData, TKey extends keyof TData = keyof TData> = {
41
+ id: string;
42
+ /**
43
+ * The label or custom compoent to display.
44
+ */
45
+ header: string | ((props: {
46
+ colId: string;
47
+ }) => ReactNode);
48
+ /**
49
+ * A helper to access and manage the preferred value of the cell.
50
+ */
51
+ accessor: DisplayColAccessor | AccessorAccessor<TData, TKey> | AccessorFn<TData>;
52
+ /**
53
+ * Strictly define the cell width. Expects a pixel-based number.
54
+ * @default 150px
55
+ */
56
+ minWidth?: number;
57
+ /**
58
+ * Strictly define the cell width. Expects a pixel-based number. If the width
59
+ * provided is smaller than what is required for features, the minimum width
60
+ * of 100px will be used instead.
61
+ * @default 150px
62
+ */
63
+ width?: number;
64
+ features?: ColumnFeatures<TData, TKey>;
65
+ /**
66
+ * The cell renderer. Provides access to the accessor value and row data. This
67
+ * is used to provide custom components for the cell content.
68
+ *
69
+ * If no content is provided a string will be rendered.
70
+ */
71
+ cell?: ColCell<TData>;
72
+ };
73
+ export type PaginationOptions = {
74
+ /**
75
+ * The total number of rows that exist. This is useful if you choose to use
76
+ * server-side pagination design.
77
+ */
78
+ count?: PaginationRootProps['count'];
79
+ /**
80
+ * The default page index to start on.
81
+ */
82
+ defaultPage?: PaginationRootProps['defaultPage'];
83
+ /**
84
+ * The default page size to start with. **Must be included in customRange if
85
+ * using any value other than 25, 50, or 100**.
86
+ *
87
+ * default: 0
88
+ */
89
+ pageSize?: PaginationRootProps['pageSize'];
90
+ /**
91
+ * A custom range of page sizes to display in the page size dropdown.
92
+ */
93
+ customRange?: number[];
94
+ };
95
+ export type AccessorOptions<TData, TKey extends keyof TData> = {
96
+ id?: string;
97
+ header: string | ((props: {
98
+ colId: string;
99
+ }) => ReactNode);
100
+ features?: ColumnFeatures<TData, TKey>;
101
+ width?: number;
102
+ minWidth?: number;
103
+ maxWidth?: number;
104
+ cell?: ColCell<TData>;
105
+ };
106
+ export type DisplayOptions<TData, TKey extends keyof TData> = {
107
+ id: string;
108
+ header: string | ((props: {
109
+ colId: string;
110
+ }) => ReactNode);
111
+ width?: number;
112
+ features?: {
113
+ pinning?: ColumnFeatures<TData, TKey>['pinning'];
114
+ };
115
+ cell: ColCell<TData>;
116
+ };
117
+ export type InternalColumn<TData> = {
118
+ id: string;
119
+ pinned: Accessor<PinnedState>;
120
+ isFlex: Accessor<boolean>;
121
+ isVisible: Accessor<boolean>;
122
+ width: Accessor<number>;
123
+ pinnable: boolean;
124
+ sortable: boolean;
125
+ filterable: boolean;
126
+ getValue: ColumnDef<TData>['accessor'];
127
+ original: ColumnDef<TData>;
128
+ setFlex: Setter<boolean>;
129
+ setColWidth: Setter<number>;
130
+ setPinned: Setter<PinnedState>;
131
+ };
132
+ export type SortState = {
133
+ id: string;
134
+ desc: boolean;
135
+ };
136
+ export interface GridStore<TData> {
137
+ columns: Accessor<InternalColumn<TData>[]>;
138
+ rows: Accessor<TData[]>;
139
+ globalFilter: Accessor<string>;
140
+ sorting: Accessor<SortState[]>;
141
+ pageIndex: Accessor<number>;
142
+ pageSize: Accessor<number>;
143
+ pageRange: Accessor<number[]>;
144
+ pageCount: Accessor<number>;
145
+ currentPageRange: Accessor<{
146
+ start: number;
147
+ end: number;
148
+ }>;
149
+ isServerPaginated: Accessor<boolean>;
150
+ rootCssVars: Accessor<Record<string, string>>;
151
+ rowCount: Accessor<number>;
152
+ rowSize: Accessor<number>;
153
+ totalWidth: Accessor<number>;
154
+ visibleRows: Accessor<TData[]>;
155
+ resizeColumn: (colId: string, delta: number) => void;
156
+ setContainerWidth: (val: number) => void;
157
+ setPage: (details: PageDetails) => void;
158
+ setPageSize: (size: number) => void;
159
+ setGlobalFilter: (val: string) => void;
160
+ setSort: (colId: string, direction: SortDirection, multi?: boolean) => void;
161
+ togglePinned: (colId: string, state: PinnedState) => void;
162
+ toggleSort: (colId: string, multi?: boolean) => void;
163
+ updateData: (newData: TData[]) => void;
164
+ }
165
+ export type RowSizeOptions = RowSize | number;
166
+ export type ColumnFeatures<TData, TKey extends keyof TData> = {
167
+ /**
168
+ * Allow the column to be sorted and the rules to use.
169
+ */
170
+ sort?: (boolean & EnforceNoProperties<SortOptions<TData, TKey>>) | SortOptions<TData, TKey>;
171
+ /**
172
+ * Allow the column to be filtered and the rules to use.
173
+ */
174
+ filter?: boolean | {
175
+ operator?: 'contains' | 'equals' | 'startsWith';
176
+ };
177
+ /**
178
+ * Show pinning options in the column menu
179
+ */
180
+ pinning?: (boolean & EnforceNoProperties<PinnedOptions>) | PinnedOptions;
181
+ };
182
+ export type PinnedOptions = {
183
+ defaultPosition?: PinnedState;
184
+ };
185
+ export type SortOptions<TData, TKey extends keyof TData> = {
186
+ firstSortDirection?: SortDirection;
187
+ comparator?: Comparator<TData[TKey]>;
188
+ };
189
+ export type ColCell<TData> = (props: {
190
+ row: TData;
191
+ value: any;
192
+ }) => ReactNode;
193
+ export type DisplayColAccessor = () => undefined;
194
+ export type AccessorAccessor<TData, TKey extends keyof TData> = (row: TData) => TData[TKey];
195
+ export type AccessorFn<TData> = (row: TData) => ReactNode;
196
+ export type Comparator<TValue> = (a: TValue, b: TValue) => number;
197
+ export type SortDirection = 'asc' | 'desc' | null;
198
+ export type PinnedState = 'left' | 'right' | undefined | boolean;
package/dist/utils.cjs ADDED
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
+
6
+ const _const = require('./const.cjs');
7
+
8
+ function determineRowHeight(rowSize = _const.SM) {
9
+ const prebuiltSizes = _const.ROW_SIZES.items;
10
+ if (typeof rowSize === "number") {
11
+ return rowSize;
12
+ }
13
+ if (prebuiltSizes.includes(rowSize)) {
14
+ const size = _const.ROW_SIZES.results[rowSize];
15
+ return size;
16
+ }
17
+ console.error(
18
+ "Unknown row size provided to Data Grid. The rowSize prop requires a number to determine pixel-based value.",
19
+ rowSize
20
+ );
21
+ return 0;
22
+ }
23
+ function determinePageSize(options) {
24
+ if (!options) return 0;
25
+ if (typeof options === "boolean" && options === true) {
26
+ return _const.SM_PAGE_SIZE;
27
+ }
28
+ if (options.customRange?.length) {
29
+ return options.customRange[0];
30
+ }
31
+ return options.pageSize ?? _const.SM_PAGE_SIZE;
32
+ }
33
+ function determinePageIndex(options) {
34
+ if (!options) return _const.DEFAULT_PAGE_IDX;
35
+ if (typeof options === "boolean" && options === true) {
36
+ return _const.DEFAULT_PAGE_IDX;
37
+ }
38
+ return options.defaultPage ?? _const.DEFAULT_PAGE_IDX;
39
+ }
40
+ function determinePageRange(options) {
41
+ if (!options) return _const.DEFAULT_PAGE_SIZES;
42
+ if (typeof options === "boolean" && options === true) {
43
+ return _const.DEFAULT_PAGE_SIZES;
44
+ }
45
+ return options.customRange ?? _const.DEFAULT_PAGE_SIZES;
46
+ }
47
+ function determineInitialCount(options) {
48
+ if (!options) return void 0;
49
+ if (typeof options === "boolean" && options === true) {
50
+ return void 0;
51
+ }
52
+ return options?.count ?? void 0;
53
+ }
54
+
55
+ exports.determineInitialCount = determineInitialCount;
56
+ exports.determinePageIndex = determinePageIndex;
57
+ exports.determinePageRange = determinePageRange;
58
+ exports.determinePageSize = determinePageSize;
59
+ exports.determineRowHeight = determineRowHeight;
@@ -0,0 +1,6 @@
1
+ import { PaginationOptions, RowSizeOptions } from './types';
2
+ export declare function determineRowHeight(rowSize?: RowSizeOptions): number;
3
+ export declare function determinePageSize(options?: boolean | PaginationOptions): number;
4
+ export declare function determinePageIndex(options?: boolean | PaginationOptions): number;
5
+ export declare function determinePageRange(options?: boolean | PaginationOptions): number[];
6
+ export declare function determineInitialCount(options?: boolean | PaginationOptions): number | undefined;
@@ -0,0 +1,6 @@
1
+ import { PaginationOptions, RowSizeOptions } from './types';
2
+ export declare function determineRowHeight(rowSize?: RowSizeOptions): number;
3
+ export declare function determinePageSize(options?: boolean | PaginationOptions): number;
4
+ export declare function determinePageIndex(options?: boolean | PaginationOptions): number;
5
+ export declare function determinePageRange(options?: boolean | PaginationOptions): number[];
6
+ export declare function determineInitialCount(options?: boolean | PaginationOptions): number | undefined;
package/dist/utils.js ADDED
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+ import { SM, ROW_SIZES, DEFAULT_PAGE_IDX, SM_PAGE_SIZE, DEFAULT_PAGE_SIZES } from './const.js';
3
+
4
+ function determineRowHeight(rowSize = SM) {
5
+ const prebuiltSizes = ROW_SIZES.items;
6
+ if (typeof rowSize === "number") {
7
+ return rowSize;
8
+ }
9
+ if (prebuiltSizes.includes(rowSize)) {
10
+ const size = ROW_SIZES.results[rowSize];
11
+ return size;
12
+ }
13
+ console.error(
14
+ "Unknown row size provided to Data Grid. The rowSize prop requires a number to determine pixel-based value.",
15
+ rowSize
16
+ );
17
+ return 0;
18
+ }
19
+ function determinePageSize(options) {
20
+ if (!options) return 0;
21
+ if (typeof options === "boolean" && options === true) {
22
+ return SM_PAGE_SIZE;
23
+ }
24
+ if (options.customRange?.length) {
25
+ return options.customRange[0];
26
+ }
27
+ return options.pageSize ?? SM_PAGE_SIZE;
28
+ }
29
+ function determinePageIndex(options) {
30
+ if (!options) return DEFAULT_PAGE_IDX;
31
+ if (typeof options === "boolean" && options === true) {
32
+ return DEFAULT_PAGE_IDX;
33
+ }
34
+ return options.defaultPage ?? DEFAULT_PAGE_IDX;
35
+ }
36
+ function determinePageRange(options) {
37
+ if (!options) return DEFAULT_PAGE_SIZES;
38
+ if (typeof options === "boolean" && options === true) {
39
+ return DEFAULT_PAGE_SIZES;
40
+ }
41
+ return options.customRange ?? DEFAULT_PAGE_SIZES;
42
+ }
43
+ function determineInitialCount(options) {
44
+ if (!options) return void 0;
45
+ if (typeof options === "boolean" && options === true) {
46
+ return void 0;
47
+ }
48
+ return options?.count ?? void 0;
49
+ }
50
+
51
+ export { determineInitialCount, determinePageIndex, determinePageRange, determinePageSize, determineRowHeight };
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
+
6
+ const signals = require('@cerberus-design/signals');
7
+ const react = require('react');
8
+
9
+ function useVirtualizer(store, viewportRef) {
10
+ const isServerPaginated = signals.useRead(store.isServerPaginated);
11
+ const rows = signals.useRead(store.visibleRows);
12
+ const rowHeight = signals.useRead(store.rowSize);
13
+ const [scrollTop, setScrollTop] = signals.useSignal(0);
14
+ const [containerHeight, setContainerHeight] = signals.useSignal(0);
15
+ react.useEffect(() => {
16
+ let rafId;
17
+ const el = viewportRef.current;
18
+ if (!el) return;
19
+ const onScroll = () => {
20
+ if (rafId) cancelAnimationFrame(rafId);
21
+ rafId = requestAnimationFrame(() => {
22
+ setScrollTop(el.scrollTop);
23
+ });
24
+ };
25
+ el.addEventListener("scroll", onScroll, { passive: true });
26
+ const observer = new ResizeObserver((entries) => {
27
+ for (const entry of entries) {
28
+ setContainerHeight(entry.contentRect.height);
29
+ }
30
+ });
31
+ observer.observe(el);
32
+ return () => {
33
+ el.removeEventListener("scroll", onScroll);
34
+ if (rafId) cancelAnimationFrame(rafId);
35
+ observer.disconnect();
36
+ };
37
+ }, [viewportRef, setScrollTop, setContainerHeight]);
38
+ return react.useMemo(() => {
39
+ if (isServerPaginated) {
40
+ return { virtualRows: [], totalHeight: 0, rowHeight };
41
+ }
42
+ const totalHeight = rows.length * rowHeight;
43
+ const buffer = 5;
44
+ const visibleCount = Math.ceil((containerHeight || 600) / rowHeight);
45
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - buffer);
46
+ const end = Math.min(rows.length, start + visibleCount + buffer * 2);
47
+ const virtualRows = rows.slice(start, end).map((row, index) => ({
48
+ data: row,
49
+ index: start + index,
50
+ offsetY: (start + index) * rowHeight
51
+ }));
52
+ return { virtualRows, totalHeight, rowHeight };
53
+ }, [isServerPaginated, rows, rowHeight, scrollTop, containerHeight]);
54
+ }
55
+
56
+ exports.useVirtualizer = useVirtualizer;
@@ -0,0 +1,11 @@
1
+ import { RefObject } from 'react';
2
+ import { GridStore } from './types';
3
+ export declare function useVirtualizer(store: GridStore<unknown>, viewportRef: RefObject<HTMLDivElement | null>): {
4
+ virtualRows: {
5
+ data: unknown;
6
+ index: number;
7
+ offsetY: number;
8
+ }[];
9
+ totalHeight: number;
10
+ rowHeight: number;
11
+ };
@@ -0,0 +1,11 @@
1
+ import { RefObject } from 'react';
2
+ import { GridStore } from './types';
3
+ export declare function useVirtualizer(store: GridStore<unknown>, viewportRef: RefObject<HTMLDivElement | null>): {
4
+ virtualRows: {
5
+ data: unknown;
6
+ index: number;
7
+ offsetY: number;
8
+ }[];
9
+ totalHeight: number;
10
+ rowHeight: number;
11
+ };
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+ import { useRead, useSignal } from '@cerberus-design/signals';
3
+ import { useEffect, useMemo } from 'react';
4
+
5
+ function useVirtualizer(store, viewportRef) {
6
+ const isServerPaginated = useRead(store.isServerPaginated);
7
+ const rows = useRead(store.visibleRows);
8
+ const rowHeight = useRead(store.rowSize);
9
+ const [scrollTop, setScrollTop] = useSignal(0);
10
+ const [containerHeight, setContainerHeight] = useSignal(0);
11
+ useEffect(() => {
12
+ let rafId;
13
+ const el = viewportRef.current;
14
+ if (!el) return;
15
+ const onScroll = () => {
16
+ if (rafId) cancelAnimationFrame(rafId);
17
+ rafId = requestAnimationFrame(() => {
18
+ setScrollTop(el.scrollTop);
19
+ });
20
+ };
21
+ el.addEventListener("scroll", onScroll, { passive: true });
22
+ const observer = new ResizeObserver((entries) => {
23
+ for (const entry of entries) {
24
+ setContainerHeight(entry.contentRect.height);
25
+ }
26
+ });
27
+ observer.observe(el);
28
+ return () => {
29
+ el.removeEventListener("scroll", onScroll);
30
+ if (rafId) cancelAnimationFrame(rafId);
31
+ observer.disconnect();
32
+ };
33
+ }, [viewportRef, setScrollTop, setContainerHeight]);
34
+ return useMemo(() => {
35
+ if (isServerPaginated) {
36
+ return { virtualRows: [], totalHeight: 0, rowHeight };
37
+ }
38
+ const totalHeight = rows.length * rowHeight;
39
+ const buffer = 5;
40
+ const visibleCount = Math.ceil((containerHeight || 600) / rowHeight);
41
+ const start = Math.max(0, Math.floor(scrollTop / rowHeight) - buffer);
42
+ const end = Math.min(rows.length, start + visibleCount + buffer * 2);
43
+ const virtualRows = rows.slice(start, end).map((row, index) => ({
44
+ data: row,
45
+ index: start + index,
46
+ offsetY: (start + index) * rowHeight
47
+ }));
48
+ return { virtualRows, totalHeight, rowHeight };
49
+ }, [isServerPaginated, rows, rowHeight, scrollTop, containerHeight]);
50
+ }
51
+
52
+ export { useVirtualizer };