flexi-datagrid 1.2.4 → 1.2.6

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
@@ -11,9 +11,14 @@ A modern, highly customizable, and feature-rich React data grid component design
11
11
  - **Multi-State Sorting:** Clickable column headers that support Ascending (asc), Descending (desc), and Unsorted states.
12
12
  - **Built-in Filtering:** Filter rows instantly with a clean popup search and multi-select dropdown for unique column values. The popup renders through a portal so it always floats above your grid content instead of being clipped by the table's scroll container.
13
13
  - **Row Grouping (Drag-and-Drop):** Drag column headers into the grouping zone to group your dataset hierarchically with expand/collapse support.
14
+ - **Column Reordering (Drag-and-Drop):** Drag any header and drop it on another to reorder columns, AG Grid-style. Column groups move as a unit; columns can be reordered within their own group or at the top level.
15
+ - **Column Resizing:** Drag the handle on the right edge of a header to resize a column live. Supports per-column `minWidth`/`maxWidth`, opt-out via `resizable: false`, and an `onColumnResize` callback.
14
16
  - **Nested/Grouped Headers:** Columns can be nested via `children` to render multi-level header rows.
15
17
  - **Sticky Actions:** Optional custom row actions column locked to the right side.
16
18
  - **Custom Cell Rendering:** Full control over how each cell is rendered via a `render` function.
19
+ - **Conditional Row Styling (AG Grid-style `rowClassRules`):** Map class names to predicates evaluated per row to highlight/style rows based on their data.
20
+ - **Row Click Events:** Pass `onRowClick` to react to clicks anywhere on a data row.
21
+ - **Virtualized Rows for Large Datasets:** Only the rows in (and just around) the visible viewport are mounted, so grids with thousands of rows stay smooth to scroll and filter.
17
22
  - **Full TypeScript Support:** Strongly typed configurations for robust developer experience.
18
23
 
19
24
  ---
@@ -58,10 +63,11 @@ const data: Employee[] = [
58
63
  ];
59
64
 
60
65
  const columns: ColumnConfig<Employee>[] = [
61
- { key: 'name', header: 'Name', sortable: true, filterable: true, pinned: 'left',style: { width: "400px", backgroundColor: "#f9f9f9" },
66
+ { key: 'name', header: 'Name', sortable: true, filterable: true, pinned: 'left', minWidth: 160, maxWidth: 500,
67
+ style: { width: "400px", backgroundColor: "#f9f9f9" },
62
68
  headerStyle: { fontWeight: "bold", color: "#333" } },
63
69
  { key: 'department', header: 'Department', sortable: true, filterable: true },
64
- { key: 'role', header: 'Role', sortable: true, filterable: true },
70
+ { key: 'role', header: 'Role', sortable: true, filterable: true, resizable: false },
65
71
  {
66
72
  key: 'salary',
67
73
  header: 'Salary',
@@ -84,14 +90,24 @@ export default function EmployeeTable() {
84
90
  { id: -1, name: '', department: '', role: 'Total', salary: data.reduce((sum, r) => sum + r.salary, 0) },
85
91
  ]}
86
92
  containerStyle={{ maxHeight: 480 }}
93
+ rowHeight={48}
94
+ overscan={8}
95
+ onColumnResize={(key, width) => console.log('resized', key, width)}
96
+ onColumnReorder={(orderedKeys) => console.log('reordered', orderedKeys)}
97
+ rowClassRules={{
98
+ 'row-high-earner': (record) => record.salary > 100000,
99
+ }}
100
+ onRowClick={(record) => console.log('clicked', record.id)}
87
101
  actions={(record) => (
88
- <button onClick={() => console.log('Edit', record.id)}>Edit</button>
102
+ <button onClick={(e) => { e.stopPropagation(); console.log('Edit', record.id); }}>Edit</button>
89
103
  )}
90
104
  />
91
105
  );
92
106
  }
93
107
  ```
94
108
 
109
+ `name` demonstrates a constrained resize range (`minWidth`/`maxWidth`), `role` opts out of resizing entirely (`resizable: false`), and dragging any header reorders columns — `onColumnResize`/`onColumnReorder` let you persist the user's layout. `rowClassRules` highlights any row with `salary > 100000`, and `onRowClick` logs the clicked row (the `Edit` button calls `stopPropagation` so clicking it doesn't also fire the row click). `containerStyle`'s bounded `maxHeight` (paired with `rowHeight`/`overscan`) is also what enables virtualized scrolling for large `data` arrays — see [Performance with Large Datasets](#performance-with-large-datasets).
110
+
95
111
  ---
96
112
 
97
113
  ## How It Works
@@ -114,7 +130,9 @@ Each entry in `columns` describes one column (or a group of columns, via `childr
114
130
  | `sortable` | `boolean` | Makes the header clickable, cycling through ascending → descending → unsorted. |
115
131
  | `pinned` | `boolean \| 'left' \| 'right'` | Pins the column to an edge by default (`true` is shorthand for `'left'`). Still toggleable per-column from the UI. |
116
132
  | `pinnedRender` | `(value, record) => ReactNode` | Overrides `render` specifically for rows supplied via `pinnedBottomRowData` (e.g. render a "Total" label or bold sum). Falls back to `render` when omitted. |
117
- | `children` | `ColumnConfig<T>[]` | Nest columns to render a grouped, multi-row header. Only leaf columns are sortable/filterable/pinnable. |
133
+ | `children` | `ColumnConfig<T>[]` | Nest columns to render a grouped, multi-row header. Only leaf columns are sortable/filterable/pinnable/resizable. |
134
+ | `resizable` | `boolean` | Set to `false` to hide the resize handle and lock the column's width. Defaults to `true` for leaf columns. |
135
+ | `minWidth` / `maxWidth` | `number` | Clamps how far a column can be resized, in pixels. |
118
136
 
119
137
  ### Grid props (`DataTableProps<T>`)
120
138
 
@@ -134,6 +152,12 @@ Each entry in `columns` describes one column (or a group of columns, via `childr
134
152
  | `bordered` | `boolean` | Draws full grid borders (all four sides of every cell) instead of the default minimal row/column dividers. |
135
153
  | `pinnedBottomRowData` | `T[]` | Rows rendered in a section fixed to the bottom of the grid (e.g. totals/summary rows). Independent of `data` — not affected by sorting, filtering, or grouping. |
136
154
  | `pinnedRowClassName` | `string \| (record: T, index: number) => string` | Extra class name(s) applied to each pinned-bottom row, for styling a totals/summary template. |
155
+ | `rowHeight` | `number` | Row height in pixels used for virtualized row rendering. Defaults to `48`, matching the built-in CSS row height — change both together if you customize row height. |
156
+ | `overscan` | `number` | Number of extra off-screen rows rendered above/below the viewport, to smooth fast scrolling. Defaults to `8`. |
157
+ | `onColumnResize` | `(columnKey: string, width: number) => void` | Called once a column resize drag ends, with the column's new width in pixels. |
158
+ | `onColumnReorder` | `(orderedLeafKeys: string[]) => void` | Called whenever columns are reordered via drag-and-drop, with the full leaf column order. |
159
+ | `rowClassRules` | `Record<string, (record: T, index: number) => boolean>` | AG Grid-style conditional row classes: maps a class name to a predicate. Every rule whose predicate returns `true` for a row is applied to that row's `<tr>`. Does not apply to `pinnedBottomRowData` rows (use `pinnedRowClassName` for those). |
160
+ | `onRowClick` | `(record: T, index: number, event: React.MouseEvent) => void` | Called when a data row is clicked, with the row's record, its index in the currently rendered (filtered/sorted/grouped) rows, and the click event. Adds a pointer cursor to rows when set. |
137
161
 
138
162
  ### Filtering
139
163
 
@@ -143,10 +167,72 @@ Any column with `filterable: true` gets a filter icon in its header. Clicking it
143
167
 
144
168
  Clicking a `sortable` column header cycles through ascending → descending → unsorted. Only one column can be actively sorted at a time.
145
169
 
170
+ ### Conditional Row Styling (`rowClassRules`)
171
+
172
+ `rowClassRules` mirrors AG Grid's API: an object mapping a CSS class name to a predicate function `(record, index) => boolean`. On every render, each rule is evaluated against each row, and every class whose predicate returns `true` is applied to that row's `<tr>` (multiple rules can match the same row at once). `index` is the row's position within the currently filtered/sorted/grouped rows, not the original `data` array.
173
+
174
+ ```tsx
175
+ const rowClassRules: Record<string, (record: Employee, index: number) => boolean> = {
176
+ 'row-high-earner': (record) => record.salary > 100000,
177
+ 'row-even': (_record, index) => index % 2 === 0,
178
+ };
179
+
180
+ <DataTable
181
+ columns={columns}
182
+ data={data}
183
+ rowKey="id"
184
+ rowClassRules={rowClassRules}
185
+ />
186
+ ```
187
+
188
+ ```css
189
+ .row-high-earner { background-color: #fef3c7; }
190
+ .row-even { background-color: #f8fafc; }
191
+ ```
192
+
193
+ Rules only apply to regular data rows — group header rows and `pinnedBottomRowData` rows are unaffected (style the latter with `pinnedRowClassName`).
194
+
195
+ ### Row Click Events
196
+
197
+ Pass `onRowClick` to be notified when a data row is clicked; the grid adds a pointer cursor to rows automatically once it's set. The handler receives the row's record, its index within the currently rendered rows, and the underlying `MouseEvent` — call `event.stopPropagation()` inside interactive cell content (e.g. an actions button) if you don't want that click to also bubble up as a row click.
198
+
199
+ ```tsx
200
+ <DataTable
201
+ columns={columns}
202
+ data={data}
203
+ rowKey="id"
204
+ onRowClick={(record, index, event) => console.log('clicked row', index, record)}
205
+ />
206
+ ```
207
+
146
208
  ### Row Grouping
147
209
 
148
210
  Set `groupBy` to enable a drop zone above the table. Dragging a sortable/leaf column header into it groups rows by that column's value, with collapsible group rows and per-group row counts. Multiple columns can be stacked to create nested groups; use `defaultGroupBy` to pre-group on mount.
149
211
 
212
+ ### Column Reordering
213
+
214
+ Drag any header cell and drop it on another to reorder columns, similar to AG Grid. Dragging a leaf column reorders it among its siblings; dragging a grouped-header cell moves the whole group. A column can only be dropped among its own siblings — you can't drag a column out of one group and into another. Pass `onColumnReorder` to be notified of the resulting leaf column order (e.g. to persist a user's layout).
215
+
216
+ Reordering composes with pinning: pinned-left and pinned-right columns still sort to their respective edges regardless of drag order.
217
+
218
+ ### Column Resizing
219
+
220
+ Hover the right edge of a resizable header to reveal a resize handle; drag it to resize the column live. All leaf columns are resizable by default — set `resizable: false` on a `ColumnConfig` to disable it for that column, and use `minWidth` / `maxWidth` to constrain how far it can be dragged. Pass `onColumnResize` to persist widths (e.g. to `localStorage`) between sessions.
221
+
222
+ ```tsx
223
+ const columns: ColumnConfig<Employee>[] = [
224
+ { key: 'name', header: 'Name', minWidth: 120, maxWidth: 400 },
225
+ { key: 'role', header: 'Role', resizable: false }, // fixed width, no handle
226
+ ];
227
+
228
+ <DataTable
229
+ columns={columns}
230
+ data={data}
231
+ rowKey="id"
232
+ onColumnResize={(key, width) => console.log('resized', key, width)}
233
+ />
234
+ ```
235
+
150
236
  ### Column Pinning
151
237
 
152
238
  Hovering a header reveals a pin icon. Clicking it cycles the column through unpinned → pinned left → pinned right → unpinned, locking it to the corresponding edge with a sticky position and shadow so it stays visible while scrolling horizontally. Columns marked `pinned: true` (or `pinned: 'left'`) start pinned left; `pinned: 'right'` starts pinned right.
@@ -194,6 +280,18 @@ The header row is always fixed in place (`position: sticky; top: 0`) relative to
194
280
 
195
281
  Pass `bordered` to draw full borders around every cell instead of the default minimal row/column dividers, for a classic spreadsheet look.
196
282
 
283
+ ### Performance with Large Datasets
284
+
285
+ Row rendering is virtualized: only the rows visible inside the scrollable container (plus a small `overscan` buffer) are ever mounted as actual `<tr>` elements, regardless of how many rows are in `data`. This keeps scrolling, sorting, and filtering smooth for grids with thousands of rows.
286
+
287
+ Virtualization requires a bounded, scrollable container and a known row height:
288
+
289
+ - Give the grid a `maxHeight` via `containerStyle` so `flexi-table-wrap` actually scrolls (see [Sticky Header](#sticky-header)) — without a bounded height, the browser page itself scrolls and every row has to be rendered.
290
+ - The default row height is `48px`, matching the built-in CSS. If you override row height via custom CSS, pass the same value through the `rowHeight` prop so the virtualizer's scroll math stays accurate.
291
+ - Tune `overscan` (default `8`) if you see blank flashes on very fast scrolling — a higher value trades a bit of extra rendering for smoother scroll.
292
+
293
+ Filtering is also optimized for large datasets: a filter column's unique values are computed once per column (not on every keystroke), and column lookups used during filtering/sorting/grouping are indexed by key instead of scanned linearly.
294
+
197
295
  ---
198
296
 
199
297
  ## 🛠 Local Development
@@ -14,6 +14,9 @@ export interface ColumnConfig<T> {
14
14
  pinned?: boolean | 'left' | 'right';
15
15
  children?: ColumnConfig<T>[];
16
16
  getValue?: (record: T) => any;
17
+ resizable?: boolean;
18
+ minWidth?: number;
19
+ maxWidth?: number;
17
20
  }
18
21
  type PinSide = 'left' | 'right';
19
22
  interface DataTableProps<T> {
@@ -31,6 +34,20 @@ interface DataTableProps<T> {
31
34
  bordered?: boolean;
32
35
  pinnedBottomRowData?: T[];
33
36
  pinnedRowClassName?: string | ((record: T, index: number) => string);
37
+ /** Row height in px, used for virtualized row rendering. Must match the CSS row height. */
38
+ rowHeight?: number;
39
+ /** Number of off-screen rows rendered above/below the viewport to smooth scrolling. */
40
+ overscan?: number;
41
+ onColumnResize?: (columnKey: string, width: number) => void;
42
+ onColumnReorder?: (orderedLeafKeys: string[]) => void;
43
+ /**
44
+ * AG Grid-style conditional row classes: maps a class name to a predicate that receives
45
+ * the row's record and its index within the currently rendered (filtered/sorted/flattened)
46
+ * rows. Every rule whose predicate returns true is applied; rules are re-evaluated whenever
47
+ * `data` or its derived filtered/sorted/grouped order changes.
48
+ */
49
+ rowClassRules?: Record<string, (record: T, index: number) => boolean>;
50
+ onRowClick?: (record: T, index: number, event: React.MouseEvent<HTMLTableRowElement>) => void;
34
51
  }
35
- export declare function DataTable<T>({ columns, data, rowKey, actions, isLoading, groupBy, defaultGroupBy, onPinChange, onGroupChange, containerStyle, tableStyle, bordered, pinnedBottomRowData, pinnedRowClassName, }: DataTableProps<T>): React.JSX.Element;
52
+ export declare function DataTable<T>({ columns, data, rowKey, actions, isLoading, groupBy, defaultGroupBy, onPinChange, onGroupChange, containerStyle, tableStyle, bordered, pinnedBottomRowData, pinnedRowClassName, rowHeight, overscan, onColumnResize, onColumnReorder, rowClassRules, onRowClick, }: DataTableProps<T>): React.JSX.Element;
36
53
  export {};
@@ -1,2 +1,2 @@
1
- .flexi-root{width:100%;position:relative}.flexi-root>*+*{margin-top:.75rem}.flexi-groupzone{box-sizing:border-box;background-color:#f8fafc80;border:1px dashed #e2e8f0;border-radius:.75rem;align-items:center;gap:.5rem;width:100%;min-height:52px;padding:.5rem 1rem;transition:all .2s;display:flex}.flexi-groupzone--dragover{background-color:#eff6ff80;border:1px solid #3b82f6;transform:scale(.99)}.flexi-groupzone-hint{color:#64748b;-webkit-user-select:none;user-select:none;font-size:12px;font-weight:500}.flexi-groupzone-chips{flex-wrap:wrap;align-items:center;gap:.375rem;display:flex}.flexi-groupzone-label{text-transform:uppercase;letter-spacing:.05em;color:#64748b;margin-right:.25rem;font-size:11px;font-weight:700}.flexi-chip{color:#64748b;background-color:#fff;border:1px solid #e2e8f0;border-radius:.5rem;align-items:center;gap:.375rem;padding:.25rem .25rem .25rem .5rem;font-size:12px;font-weight:600;display:flex;box-shadow:0 1px 2px #0000000d}.flexi-chip-remove{border-radius:5px;width:18px;height:18px}.flexi-table-wrap{box-sizing:border-box;background-color:#fff;border:1px solid #f1f5f9;border-radius:.75rem;width:100%;overflow:auto;box-shadow:0 1px 2px #0000000d}.flexi-table{caption-side:bottom;border-collapse:collapse;border-spacing:0;table-layout:fixed;width:100%;font-size:.875rem;position:relative}.flexi-table--bordered th,.flexi-table--bordered td{border:1px solid #e2e8f0}.flexi-thead{-webkit-user-select:none;user-select:none;z-index:40;position:sticky}.flexi-header-row{border-bottom:1px solid #f1f5f9}.flexi-group-spacer-th{border-right:1px solid #f1f5f9;width:48px}.flexi-th{text-align:center;vertical-align:middle;z-index:25;background-color:#f8fafc;border-bottom:1px solid #f1f5f9;border-right:1px solid #f1f5f9;height:48px;padding:0 1rem;font-size:12px;font-weight:700;position:sticky;top:0}.flexi-th--draggable{cursor:grab}.flexi-th--draggable:active{cursor:grabbing}.flexi-th--pinned{background-color:#f8fafc}.flexi-th-inner{justify-content:space-between;align-items:center;gap:.25rem;width:100%;min-width:0;display:flex}.flexi-th-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;align-items:center;gap:.375rem;min-width:0;display:flex;overflow:hidden}.flexi-th-label--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.flexi-th-label--sortable:hover{color:#2563eb}.flexi-th-text{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.flexi-sort-icon{color:#94a3b8;opacity:0;transition:color .15s,opacity .15s}.flexi-sort-icon--active{color:#2563eb;opacity:1}.flexi-th-inner:hover .flexi-sort-icon{opacity:1}.flexi-th-actions{flex:none;align-items:center;gap:2px;display:flex}.flexi-icon-btn{color:#64748b;background-color:#0000;border-radius:6px;justify-content:center;align-items:center;width:22px;height:22px;margin:0;padding:0;transition:background-color .15s,color .15s,transform .1s;display:inline-flex}.flexi-icon-btn:hover{color:#334155;background-color:#e2e8f0}.flexi-icon-btn:active{background-color:#cbd5e1;transform:scale(.92)}.flexi-icon-btn:focus-visible{outline-offset:1px;outline:2px solid #93c5fd}.flexi-filter-btn{color:#64748b;opacity:0}.flexi-filter-btn--active{color:#2563eb;opacity:1}.flexi-filter-btn--active:hover{color:#2563eb;background-color:#dbeafe}.flexi-pin-btn{color:#cbd5e1;opacity:0}.flexi-pin-btn--pinned{color:#3b82f6;opacity:1}.flexi-pin-btn--pinned:hover{color:#2563eb;background-color:#dbeafe}.flexi-th-inner:hover .flexi-filter-btn,.flexi-th-inner:hover .flexi-pin-btn{opacity:1}.flexi-actions-th{vertical-align:middle;text-align:right;height:48px;padding:0 1rem;font-size:12px;font-weight:700;box-shadow:-1px 0 #e2e8f0}.flexi-filter-dropdown{color:#334155;text-align:left;pointer-events:auto;background-color:#fff;border:1px solid #e2e8f0;border-radius:.5rem;flex-direction:column;width:13rem;padding:.5rem 0;font-weight:400;display:flex;position:absolute;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.flexi-filter-search{border-bottom:1px solid #f1f5f9;margin-bottom:.25rem;padding:0 .5rem .5rem}.flexi-input{color:#475569;box-sizing:border-box;border:1px solid #e2e8f0;border-radius:.25rem;width:100%;padding:.25rem .5rem;font-size:12px;font-weight:500}.flexi-input:focus{border-color:#3b82f6;outline:none}.flexi-filter-list{flex-direction:column;gap:.25rem;max-height:10rem;padding:0 .5rem;display:flex;overflow-y:auto}.flexi-filter-empty{color:#64748b;text-align:center;padding:.5rem;font-size:11px}.flexi-filter-option{cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.25rem;align-items:center;gap:.5rem;padding:.375rem .5rem;font-size:12px;display:flex}.flexi-filter-option:hover{background-color:#f8fafc}.flexi-filter-option-text{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.flexi-checkbox{accent-color:#2563eb;border:1px solid #cbd5e1;border-radius:.25rem;width:.875rem;height:.875rem}.flexi-checkbox:focus{outline-offset:1px;outline:2px solid #3b82f6}.flexi-filter-footer{border-top:1px solid #f1f5f9;justify-content:flex-end;margin-top:.5rem;padding:.25rem .5rem 0;display:flex}.flexi-filter-clear{color:#ef4444;padding:.125rem .5rem;font-size:11px;font-weight:500}.flexi-filter-clear:hover{text-decoration:underline}.flexi-tbody{display:table-row-group}.flexi-tbody tr+tr{border-top:1px solid #f1f5f9}.flexi-empty-cell{text-align:center;color:#64748b;padding:2rem;font-size:12px;font-weight:500}.flexi-group-row{-webkit-user-select:none;user-select:none;background-color:#f8fafc99;transition:background-color .15s}.flexi-group-row:hover{background-color:#f1f5f9cc}.flexi-group-cell{color:#334155;border-right:1px solid #f1f5f9;padding:.75rem 1rem;font-size:12px;font-weight:600}.flexi-group-toggle{text-align:left;border-radius:6px;align-items:center;gap:.375rem;margin:-4px -8px -4px -4px;padding:4px 8px 4px 4px;transition:background-color .15s;display:flex}.flexi-group-toggle:hover{background-color:#e2e8f099}.flexi-group-toggle:focus-visible{outline-offset:1px;outline:2px solid #93c5fd}.flexi-icon-muted{color:#64748b}.flexi-group-value{color:#1e293b;white-space:nowrap;text-overflow:ellipsis;width:10rem;font-weight:700;overflow:hidden}.flexi-group-count{color:#64748b;background-color:#e2e8f0b3;border-radius:9999px;margin-left:.25rem;padding:.05rem .375rem;font-size:10px;font-weight:500}.flexi-group-filler{background-color:#f8fafc4d}.flexi-row{border-bottom:1px solid #f1f5f9;height:48px;transition:background-color .15s}.flexi-row:hover{background-color:#f8fafccc}.flexi-row-indent-cell{background-color:#fff;border-right:1px solid #f1f5f9;width:48px}.flexi-cell{vertical-align:middle;padding:.25rem 1rem;transition:background-color .15s}.flexi-row:hover .flexi-cell--pinned{background-color:#f1f5f9}.flexi-cell-text{color:#64748b;white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:500;display:block;overflow:hidden}.flexi-actions-cell{vertical-align:middle;text-align:right;background-color:#fff;padding:.25rem 1rem;box-shadow:-1px 0 #e2e8f0}.flexi-row:hover .flexi-actions-cell{background-color:#f8fafccc}.flexi-tbody--pinned-bottom{box-shadow:0 -2px 5px -2px #0000001a}.flexi-row--pinned-bottom{background-color:#f8fafc;font-weight:600}.flexi-row--pinned-bottom:hover,.flexi-row--pinned-bottom .flexi-cell,.flexi-row--pinned-bottom .flexi-actions-cell{background-color:#f8fafc}.flexi-row--pinned-bottom .flexi-cell-text{color:#334155}.flexi-actions-inner{opacity:0;justify-content:flex-end;gap:.25rem;transition:opacity .15s;display:flex}.flexi-row:hover .flexi-actions-inner{opacity:1}.flexi-icon-xs{width:.75rem;height:.75rem}.flexi-icon-sm{width:.875rem;height:.875rem}.flexi-icon-md{width:1rem;height:1rem}.flexi-root button{appearance:none;cursor:pointer;font:inherit;color:inherit;background:0 0;border:none;margin:0;padding:0;line-height:normal}.flexi-root input{font:inherit}.flexi-root table{border-collapse:collapse;border-spacing:0}
1
+ .flexi-root{width:100%;position:relative}.flexi-root>*+*{margin-top:.75rem}.flexi-groupzone{box-sizing:border-box;background-color:#f8fafc80;border:1px dashed #e2e8f0;border-radius:.75rem;align-items:center;gap:.5rem;width:100%;min-height:52px;padding:.5rem 1rem;transition:all .2s;display:flex}.flexi-groupzone--dragover{background-color:#eff6ff80;border:1px solid #3b82f6;transform:scale(.99)}.flexi-groupzone-hint{color:#64748b;-webkit-user-select:none;user-select:none;font-size:12px;font-weight:500}.flexi-groupzone-chips{flex-wrap:wrap;align-items:center;gap:.375rem;display:flex}.flexi-groupzone-label{text-transform:uppercase;letter-spacing:.05em;color:#64748b;margin-right:.25rem;font-size:11px;font-weight:700}.flexi-chip{color:#64748b;background-color:#fff;border:1px solid #e2e8f0;border-radius:.5rem;align-items:center;gap:.375rem;padding:.25rem .25rem .25rem .5rem;font-size:12px;font-weight:600;display:flex;box-shadow:0 1px 2px #0000000d}.flexi-chip-remove{border-radius:5px;width:18px;height:18px}.flexi-table-wrap{box-sizing:border-box;background-color:#fff;border:1px solid #f1f5f9;border-radius:.75rem;width:100%;overflow:auto;box-shadow:0 1px 2px #0000000d}.flexi-table{caption-side:bottom;border-collapse:collapse;border-spacing:0;table-layout:fixed;width:100%;font-size:.875rem;position:relative}.flexi-table--bordered th,.flexi-table--bordered td{border:1px solid #e2e8f0}.flexi-thead{-webkit-user-select:none;user-select:none;z-index:40;position:sticky}.flexi-header-row{border-bottom:1px solid #f1f5f9}.flexi-group-spacer-th{border-right:1px solid #f1f5f9;width:48px}.flexi-th{text-align:center;vertical-align:middle;z-index:25;background-color:#f8fafc;border-bottom:1px solid #f1f5f9;border-right:1px solid #f1f5f9;height:48px;padding:0 1rem;font-size:12px;font-weight:700;position:sticky;top:0}.flexi-th--draggable{cursor:grab}.flexi-th--draggable:active{cursor:grabbing}.flexi-th--pinned{background-color:#f8fafc}.flexi-th-inner{justify-content:space-between;align-items:center;gap:.25rem;width:100%;min-width:0;display:flex}.flexi-th-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;align-items:center;gap:.375rem;min-width:0;display:flex;overflow:hidden}.flexi-th-label--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.flexi-th-label--sortable:hover{color:#2563eb}.flexi-th-text{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.flexi-sort-icon{color:#94a3b8;opacity:0;transition:color .15s,opacity .15s}.flexi-sort-icon--active{color:#2563eb;opacity:1}.flexi-th-inner:hover .flexi-sort-icon{opacity:1}.flexi-th-actions{flex:none;align-items:center;gap:2px;display:flex}.flexi-th-resizer{cursor:col-resize;touch-action:none;-webkit-user-select:none;user-select:none;z-index:5;width:6px;position:absolute;top:0;bottom:0;right:0}.flexi-th-resizer:hover,.flexi-th-resizer:active{background-color:#93c5fd}.flexi-icon-btn{color:#64748b;background-color:#0000;border-radius:6px;justify-content:center;align-items:center;width:22px;height:22px;margin:0;padding:0;transition:background-color .15s,color .15s,transform .1s;display:inline-flex}.flexi-icon-btn:hover{color:#334155;background-color:#e2e8f0}.flexi-icon-btn:active{background-color:#cbd5e1;transform:scale(.92)}.flexi-icon-btn:focus-visible{outline-offset:1px;outline:2px solid #93c5fd}.flexi-filter-btn{color:#64748b;opacity:0}.flexi-filter-btn--active{color:#2563eb;opacity:1}.flexi-filter-btn--active:hover{color:#2563eb;background-color:#dbeafe}.flexi-pin-btn{color:#cbd5e1;opacity:0}.flexi-pin-btn--pinned{color:#3b82f6;opacity:1}.flexi-pin-btn--pinned:hover{color:#2563eb;background-color:#dbeafe}.flexi-th-inner:hover .flexi-filter-btn,.flexi-th-inner:hover .flexi-pin-btn{opacity:1}.flexi-actions-th{vertical-align:middle;text-align:right;height:48px;padding:0 1rem;font-size:12px;font-weight:700;box-shadow:-1px 0 #e2e8f0}.flexi-filter-dropdown{color:#334155;text-align:left;pointer-events:auto;background-color:#fff;border:1px solid #e2e8f0;border-radius:.5rem;flex-direction:column;width:13rem;padding:.5rem 0;font-weight:400;display:flex;position:absolute;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.flexi-filter-search{border-bottom:1px solid #f1f5f9;margin-bottom:.25rem;padding:0 .5rem .5rem}.flexi-input{color:#475569;box-sizing:border-box;border:1px solid #e2e8f0;border-radius:.25rem;width:100%;padding:.25rem .5rem;font-size:12px;font-weight:500}.flexi-input:focus{border-color:#3b82f6;outline:none}.flexi-filter-list{flex-direction:column;gap:.25rem;max-height:10rem;padding:0 .5rem;display:flex;overflow-y:auto}.flexi-filter-empty{color:#64748b;text-align:center;padding:.5rem;font-size:11px}.flexi-filter-option{cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:.25rem;align-items:center;gap:.5rem;padding:.375rem .5rem;font-size:12px;display:flex}.flexi-filter-option:hover{background-color:#f8fafc}.flexi-filter-option-text{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.flexi-checkbox{accent-color:#2563eb;border:1px solid #cbd5e1;border-radius:.25rem;width:.875rem;height:.875rem}.flexi-checkbox:focus{outline-offset:1px;outline:2px solid #3b82f6}.flexi-filter-footer{border-top:1px solid #f1f5f9;justify-content:flex-end;margin-top:.5rem;padding:.25rem .5rem 0;display:flex}.flexi-filter-clear{color:#ef4444;padding:.125rem .5rem;font-size:11px;font-weight:500}.flexi-filter-clear:hover{text-decoration:underline}.flexi-tbody{display:table-row-group}.flexi-tbody tr+tr{border-top:1px solid #f1f5f9}.flexi-empty-cell{text-align:center;color:#64748b;padding:2rem;font-size:12px;font-weight:500}.flexi-group-row{-webkit-user-select:none;user-select:none;background-color:#f8fafc99;height:48px;transition:background-color .15s}.flexi-group-row:hover{background-color:#f1f5f9cc}.flexi-group-cell{color:#334155;border-right:1px solid #f1f5f9;padding:.75rem 1rem;font-size:12px;font-weight:600}.flexi-group-toggle{text-align:left;border-radius:6px;align-items:center;gap:.375rem;margin:-4px -8px -4px -4px;padding:4px 8px 4px 4px;transition:background-color .15s;display:flex}.flexi-group-toggle:hover{background-color:#e2e8f099}.flexi-group-toggle:focus-visible{outline-offset:1px;outline:2px solid #93c5fd}.flexi-icon-muted{color:#64748b}.flexi-group-value{color:#1e293b;white-space:nowrap;text-overflow:ellipsis;width:10rem;font-weight:700;overflow:hidden}.flexi-group-count{color:#64748b;background-color:#e2e8f0b3;border-radius:9999px;margin-left:.25rem;padding:.05rem .375rem;font-size:10px;font-weight:500}.flexi-group-filler{background-color:#f8fafc4d}.flexi-row{border-bottom:1px solid #f1f5f9;height:48px;transition:background-color .15s}.flexi-row:hover{background-color:#f8fafccc}.flexi-row--clickable{cursor:pointer}.flexi-row-indent-cell{background-color:#fff;border-right:1px solid #f1f5f9;width:48px}.flexi-cell{vertical-align:middle;padding:.25rem 1rem;transition:background-color .15s}.flexi-row:hover .flexi-cell--pinned{background-color:#f1f5f9}.flexi-cell-text{color:#64748b;white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:500;display:block;overflow:hidden}.flexi-actions-cell{vertical-align:middle;text-align:right;background-color:#fff;padding:.25rem 1rem;box-shadow:-1px 0 #e2e8f0}.flexi-row:hover .flexi-actions-cell{background-color:#f8fafccc}.flexi-tbody--pinned-bottom{box-shadow:0 -2px 5px -2px #0000001a}.flexi-row--pinned-bottom{background-color:#f8fafc;font-weight:600}.flexi-row--pinned-bottom:hover,.flexi-row--pinned-bottom .flexi-cell,.flexi-row--pinned-bottom .flexi-actions-cell{background-color:#f8fafc}.flexi-row--pinned-bottom .flexi-cell-text{color:#334155}.flexi-actions-inner{opacity:0;justify-content:flex-end;gap:.25rem;transition:opacity .15s;display:flex}.flexi-row:hover .flexi-actions-inner{opacity:1}.flexi-icon-xs{width:.75rem;height:.75rem}.flexi-icon-sm{width:.875rem;height:.875rem}.flexi-icon-md{width:1rem;height:1rem}.flexi-root button{appearance:none;cursor:pointer;font:inherit;color:inherit;background:0 0;border:none;margin:0;padding:0;line-height:normal}.flexi-root input{font:inherit}.flexi-root table{border-collapse:collapse;border-spacing:0}
2
2
  /*$vite$:1*/
package/dist/index.es.js CHANGED
@@ -1,60 +1,67 @@
1
- import { ArrowDown as e, ArrowUp as t, ArrowUpDown as n, ChevronDown as r, ChevronRight as i, Filter as a, Pin as o, PinOff as s, X as c } from "lucide-react";
2
- import { useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
3
- import { createPortal as ee } from "react-dom";
4
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
1
+ import { ArrowDown as e, ArrowUp as t, ArrowUpDown as n, ChevronDown as r, ChevronRight as i, Filter as a, Pin as o, PinOff as s, X as ee } from "lucide-react";
2
+ import { useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
3
+ import { createPortal as te } from "react-dom";
4
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
5
5
  //#region src/DataTable.tsx
6
6
  var h = (e) => {
7
7
  let t = [];
8
8
  return e.forEach((e) => {
9
9
  e.children && e.children.length > 0 ? t.push(...h(e.children)) : t.push(e);
10
10
  }), t;
11
- }, g = (...e) => e.filter(Boolean).join(" "), _ = (e) => {
11
+ }, g = (...e) => e.filter(Boolean).join(" "), ne = (e) => {
12
12
  if (e === !0) return "left";
13
13
  if (e === "left" || e === "right") return e;
14
- };
15
- function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy: S = !1, defaultGroupBy: ne = [], onPinChange: C, onGroupChange: w, containerStyle: re, tableStyle: ie, bordered: ae = !1, pinnedBottomRowData: T = [], pinnedRowClassName: E }) {
16
- let [D, O] = f(null), [k, A] = f({}), [j, M] = f(""), [N, oe] = f(null), P = d(/* @__PURE__ */ new Map()), [F, I] = f(ne), [L, se] = f({}), [ce, R] = f(!1), [z, le] = f({
14
+ }, re = (e, t, n) => {
15
+ let r = (e) => {
16
+ let n = t[e];
17
+ return n === "left" ? 0 : n === "right" ? 2 : 1;
18
+ }, i = (e) => e.map((e, t) => ({
19
+ col: e,
20
+ idx: t
21
+ })).sort((e, t) => {
22
+ let i = r(e.col.key) - r(t.col.key);
23
+ return i === 0 ? (n[e.col.key] ?? e.idx) - (n[t.col.key] ?? t.idx) : i;
24
+ }).map(({ col: e }) => e.children && e.children.length > 0 ? {
25
+ ...e,
26
+ children: i(e.children)
27
+ } : e);
28
+ return i(e);
29
+ }, ie = 48, ae = 150, oe = 60;
30
+ function _({ columns: _, data: v, rowKey: y, actions: b, isLoading: se, groupBy: x = !1, defaultGroupBy: ce = [], onPinChange: le, onGroupChange: S, containerStyle: ue, tableStyle: de, bordered: fe = !1, pinnedBottomRowData: C = [], pinnedRowClassName: pe, rowHeight: w = ie, overscan: me = 8, onColumnResize: he, onColumnReorder: ge, rowClassRules: _e, onRowClick: T }) {
31
+ let [E, ve] = d(null), [D, ye] = d({}), [O, k] = d(""), [A, be] = d(null), j = u(/* @__PURE__ */ new Map()), [M, xe] = d(ce), [N, Se] = d({}), [Ce, P] = d(!1), [F, we] = d({
17
32
  key: null,
18
33
  direction: null
19
- }), B = u(() => h(v), [v]), [V, ue] = f(() => {
34
+ }), [I, Te] = d({}), [L, Ee] = d({}), R = u(null), z = u(!1), B = u(null), V = l(() => h(_), [_]), [H, De] = d(() => {
20
35
  let e = {};
21
- return B.forEach((t) => {
22
- let n = _(t.pinned);
36
+ return V.forEach((t) => {
37
+ let n = ne(t.pinned);
23
38
  n && (e[t.key] = n);
24
39
  }), e;
25
- }), H = u(() => {
26
- let e = (t) => {
27
- let n = (e) => {
28
- let t = V[e];
29
- return t === "left" ? 0 : t === "right" ? 2 : 1;
30
- };
31
- return [...t].sort((e, t) => n(e.key) - n(t.key)).map((t) => t.children && t.children.length > 0 ? {
32
- ...t,
33
- children: e(t.children)
34
- } : t);
35
- };
36
- return e(v);
37
- }, [v, V]), U = u(() => {
38
- let e = h(H), t = S ? F : [];
40
+ }), U = l(() => re(_, H, L), [
41
+ _,
42
+ H,
43
+ L
44
+ ]), W = l(() => {
45
+ let e = h(U), t = x ? M : [];
39
46
  return e.filter((e) => !t.includes(e.key));
40
47
  }, [
41
- H,
42
- F,
43
- S
44
- ]), W = d(null), G = d(null);
45
- l(() => {
48
+ U,
49
+ M,
50
+ x
51
+ ]), G = u(null), K = u(null);
52
+ c(() => {
46
53
  function e(e) {
47
- let t = e.target, n = D ? P.current.get(D) : null;
48
- G.current && !G.current.contains(t) && !(n && n.contains(t)) && (O(null), M(""));
54
+ let t = e.target, n = E ? j.current.get(E) : null;
55
+ K.current && !K.current.contains(t) && !(n && n.contains(t)) && (ve(null), k(""));
49
56
  }
50
57
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
51
- }, [D]), l(() => {
52
- if (!D) return;
58
+ }, [E]), c(() => {
59
+ if (!E) return;
53
60
  let e = () => {
54
- let e = P.current.get(D), t = W.current;
61
+ let e = j.current.get(E), t = G.current;
55
62
  if (!e || !t) return;
56
63
  let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
57
- oe({
64
+ be({
58
65
  top: n.bottom - r.top + 4,
59
66
  left: n.left - r.left
60
67
  });
@@ -62,37 +69,87 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
62
69
  return e(), window.addEventListener("scroll", e, !0), window.addEventListener("resize", e), () => {
63
70
  window.removeEventListener("scroll", e, !0), window.removeEventListener("resize", e);
64
71
  };
65
- }, [D]);
66
- let de = (e) => typeof b == "function" ? b(e) : String(e[b]), fe = (e) => {
67
- ue((t) => {
72
+ }, [E]);
73
+ let Oe = (e) => typeof y == "function" ? y(e) : String(e[y]), ke = (e, t) => {
74
+ if (!_e) return;
75
+ let n;
76
+ for (let r in _e) _e[r](e, t) && (n = n ? `${n} ${r}` : r);
77
+ return n;
78
+ }, Ae = (e) => {
79
+ De((t) => {
68
80
  let n = t[e], r = n ? n === "left" ? "right" : void 0 : "left", i = { ...t };
69
- return r ? i[e] = r : delete i[e], C && C(e, !!r, r), i;
81
+ return r ? i[e] = r : delete i[e], le && le(e, !!r, r), i;
70
82
  });
71
- }, pe = (e) => {
83
+ }, je = (e) => {
72
84
  let t = "asc";
73
- z.key === e && (t = z.direction === "asc" ? "desc" : z.direction === "desc" ? null : "asc"), le({
85
+ F.key === e && (t = F.direction === "asc" ? "desc" : F.direction === "desc" ? null : "asc"), we({
74
86
  key: t ? e : null,
75
87
  direction: t
76
88
  });
77
- }, me = (e, t) => {
78
- S && (e.dataTransfer.setData("text/plain", t), e.dataTransfer.effectAllowed = "move");
79
- }, he = (e) => {
80
- e.preventDefault(), R(!1);
89
+ }, Me = (e, t, n) => {
90
+ if (z.current) {
91
+ e.preventDefault();
92
+ return;
93
+ }
94
+ R.current = t, n && e.dataTransfer.setData("text/plain", t), e.dataTransfer.effectAllowed = "move";
95
+ }, Ne = (e, t, n) => {
96
+ let r = e.map((e) => e.key);
97
+ if (r.includes(t) && r.includes(n)) return e;
98
+ for (let r of e) if (r.children && r.children.length > 0) {
99
+ let e = Ne(r.children, t, n);
100
+ if (e) return e;
101
+ }
102
+ return null;
103
+ }, Pe = (e, t) => {
104
+ e.preventDefault(), e.stopPropagation();
105
+ let n = R.current;
106
+ if (R.current = null, !n || n === t) return;
107
+ let r = Ne(U, n, t);
108
+ if (!r) return;
109
+ let i = r.map((e) => e.key), a = i.indexOf(n), o = i.indexOf(t);
110
+ i.splice(o, 0, i.splice(a, 1)[0]);
111
+ let s = { ...L };
112
+ i.forEach((e, t) => {
113
+ s[e] = t;
114
+ }), Ee(s), ge && ge(h(re(_, H, s)).map((e) => e.key));
115
+ }, Fe = (e, t) => {
116
+ e.preventDefault(), e.stopPropagation(), z.current = !0, B.current = {
117
+ key: t.key,
118
+ startX: e.clientX,
119
+ startWidth: J(t)
120
+ };
121
+ let n = t.minWidth ?? oe, r = t.maxWidth, i = (e) => {
122
+ let t = B.current;
123
+ if (!t) return;
124
+ let i = t.startWidth + (e.clientX - t.startX);
125
+ i = Math.max(n, i), r && (i = Math.min(r, i)), Te((e) => e[t.key] === i ? e : {
126
+ ...e,
127
+ [t.key]: i
128
+ });
129
+ }, a = () => {
130
+ let e = B.current;
131
+ B.current = null, window.removeEventListener("mousemove", i), window.removeEventListener("mouseup", a), requestAnimationFrame(() => {
132
+ z.current = !1;
133
+ }), e && he && Te((t) => (t[e.key] !== void 0 && he(e.key, t[e.key]), t));
134
+ };
135
+ window.addEventListener("mousemove", i), window.addEventListener("mouseup", a);
136
+ }, Ie = (e) => {
137
+ e.preventDefault(), P(!1);
81
138
  let t = e.dataTransfer.getData("text/plain");
82
- if (t && !F.includes(t)) {
83
- let e = [...F, t];
84
- I(e), w && w(e);
139
+ if (t && !M.includes(t)) {
140
+ let e = [...M, t];
141
+ xe(e), S && S(e);
85
142
  }
86
- }, ge = (e) => {
87
- let t = F.filter((t) => t !== e);
88
- I(t), se({}), w && w(t);
89
- }, K = u(() => {
143
+ }, Le = (e) => {
144
+ let t = M.filter((t) => t !== e);
145
+ xe(t), Se({}), S && S(t);
146
+ }, q = l(() => {
90
147
  let e = (t) => {
91
148
  let n = 0;
92
149
  return t.forEach((t) => {
93
150
  n = t.children && t.children.length > 0 ? Math.max(n, 1 + e(t.children)) : Math.max(n, 1);
94
151
  }), n;
95
- }, t = e(H), n = Array.from({ length: t }, () => []), r = (e) => !e.children || e.children.length === 0 ? F.includes(e.key) && S ? 0 : 1 : e.children.reduce((e, t) => e + r(t), 0), i = S ? F : [], a = (e, o) => {
152
+ }, t = e(U), n = Array.from({ length: t }, () => []), r = (e) => !e.children || e.children.length === 0 ? M.includes(e.key) && x ? 0 : 1 : e.children.reduce((e, t) => e + r(t), 0), i = x ? M : [], a = (e, o) => {
96
153
  e.forEach((e) => {
97
154
  if (i.includes(e.key)) return;
98
155
  let s = r(e);
@@ -107,69 +164,76 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
107
164
  }));
108
165
  });
109
166
  };
110
- return a(H, 0), n.filter((e) => e.length > 0);
167
+ return a(U, 0), n.filter((e) => e.length > 0);
111
168
  }, [
112
- H,
113
- F,
114
- S
115
- ]), q = (e) => {
116
- let t = e.style?.width || e.headerStyle?.width || "150px";
117
- return typeof t == "number" ? t : parseInt(String(t), 10) || 150;
118
- }, _e = u(() => {
169
+ U,
170
+ M,
171
+ x
172
+ ]), J = (e) => {
173
+ if (I[e.key] !== void 0) return I[e.key];
174
+ let t = e.style?.width || e.headerStyle?.width || `${ae}px`;
175
+ return typeof t == "number" ? t : parseInt(String(t), 10) || ae;
176
+ }, Re = l(() => {
119
177
  let e = {}, t = 0;
120
- S && F.length > 0 && (t += 48), U.forEach((n) => {
121
- V[n.key] === "left" && (e[n.key] = {
178
+ x && M.length > 0 && (t += 48), W.forEach((n) => {
179
+ H[n.key] === "left" && (e[n.key] = {
122
180
  side: "left",
123
181
  offset: t
124
- }, t += q(n));
182
+ }, t += J(n));
125
183
  });
126
- let n = x ? 100 : 0;
127
- for (let t = U.length - 1; t >= 0; t--) {
128
- let r = U[t];
129
- V[r.key] === "right" && (e[r.key] = {
184
+ let n = b ? 100 : 0;
185
+ for (let t = W.length - 1; t >= 0; t--) {
186
+ let r = W[t];
187
+ H[r.key] === "right" && (e[r.key] = {
130
188
  side: "right",
131
189
  offset: n
132
- }, n += q(r));
190
+ }, n += J(r));
133
191
  }
134
192
  return e;
135
193
  }, [
136
- U,
137
- V,
138
- F,
139
- S,
140
- x
141
- ]), ve = (e, t) => {
142
- A((n) => {
194
+ W,
195
+ H,
196
+ M,
197
+ x,
198
+ b,
199
+ I
200
+ ]), ze = (e, t) => {
201
+ ye((n) => {
143
202
  let r = n[e] || [], i = r.includes(t) ? r.filter((e) => e !== t) : [...r, t], a = {
144
203
  ...n,
145
204
  [e]: i
146
205
  };
147
206
  return a[e].length === 0 && delete a[e], a;
148
207
  });
149
- }, ye = (e) => {
150
- A((t) => {
208
+ }, Be = (e) => {
209
+ ye((t) => {
151
210
  let n = { ...t };
152
211
  return delete n[e], n;
153
212
  });
154
- }, J = u(() => {
155
- if (!D) return [];
156
- let e = B.find((e) => e.key === D), t = y.map((t) => e?.getValue ? e.getValue(t) : t[D]), n = Array.from(new Set(t)).filter((e) => e != null);
157
- return j.trim() ? n.filter((e) => String(e).toLowerCase().includes(j.toLowerCase())) : n;
213
+ }, Y = l(() => {
214
+ let e = /* @__PURE__ */ new Map();
215
+ return V.forEach((t) => e.set(t.key, t)), e;
216
+ }, [V]), Ve = l(() => {
217
+ if (!E) return [];
218
+ let e = Y.get(E), t = v.map((t) => e?.getValue ? e.getValue(t) : t[E]);
219
+ return Array.from(new Set(t)).filter((e) => e != null);
158
220
  }, [
159
- y,
160
- D,
161
- j,
162
- B
163
- ]), Y = u(() => {
164
- let e = y.filter((e) => Object.entries(k).every(([t, n]) => {
165
- if (!n || n.length === 0) return !0;
166
- let r = B.find((e) => e.key === t), i = r?.getValue ? r.getValue(e) : e[t];
221
+ v,
222
+ E,
223
+ Y
224
+ ]), He = l(() => {
225
+ if (!O.trim()) return Ve;
226
+ let e = O.toLowerCase();
227
+ return Ve.filter((t) => String(t).toLowerCase().includes(e));
228
+ }, [Ve, O]), Ue = l(() => {
229
+ let e = Object.entries(D).filter(([, e]) => e && e.length > 0), t = e.length === 0 ? v : v.filter((t) => e.every(([e, n]) => {
230
+ let r = Y.get(e), i = r?.getValue ? r.getValue(t) : t[e];
167
231
  return n.includes(i);
168
232
  }));
169
- if (z.key && z.direction) {
170
- let { key: t, direction: n } = z, r = B.find((e) => e.key === t);
171
- e = [...e].sort((e, i) => {
172
- let a = r?.getValue ? r.getValue(e) : e[t], o = r?.getValue ? r.getValue(i) : i[t];
233
+ if (F.key && F.direction) {
234
+ let { key: e, direction: n } = F, r = Y.get(e);
235
+ t = [...t].sort((t, i) => {
236
+ let a = r?.getValue ? r.getValue(t) : t[e], o = r?.getValue ? r.getValue(i) : i[e];
173
237
  if (a === o) return 0;
174
238
  if (a == null) return 1;
175
239
  if (o == null) return -1;
@@ -180,17 +244,17 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
180
244
  }), n === "asc" ? s : -s;
181
245
  });
182
246
  }
183
- return e;
247
+ return t;
184
248
  }, [
185
- y,
186
- k,
187
- z,
188
- B
189
- ]), X = u(() => {
190
- if (!S || F.length === 0) return Y;
249
+ v,
250
+ D,
251
+ F,
252
+ Y
253
+ ]), We = l(() => {
254
+ if (!x || M.length === 0) return Ue;
191
255
  let e = (t, n, r = "") => {
192
- if (n >= F.length) return t;
193
- let i = F[n], a = B.find((e) => e.key === i), o = {};
256
+ if (n >= M.length) return t;
257
+ let i = M[n], a = Y.get(i), o = {};
194
258
  return t.forEach((e) => {
195
259
  let t = a?.getValue ? a.getValue(e) : e[i], n = String(t ?? "N/A");
196
260
  o[n] || (o[n] = []), o[n].push(e);
@@ -207,35 +271,70 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
207
271
  };
208
272
  });
209
273
  };
210
- return e(Y, 0);
274
+ return e(Ue, 0);
211
275
  }, [
212
- Y,
213
- F,
214
- S,
215
- B
216
- ]), be = (e) => {
217
- se((t) => {
276
+ Ue,
277
+ M,
278
+ x,
279
+ Y
280
+ ]), Ge = (e) => {
281
+ Se((t) => {
218
282
  let n = t[e] !== !1;
219
283
  return {
220
284
  ...t,
221
285
  [e]: !n
222
286
  };
223
287
  });
224
- }, Z = u(() => {
225
- if (!S || F.length === 0) return X;
288
+ }, X = l(() => {
289
+ if (!x || M.length === 0) return We;
226
290
  let e = [], t = (n) => {
227
291
  n.forEach((n) => {
228
- n.isGroupRow ? (e.push(n), L[n.path] !== !1 && t(n.children)) : e.push(n);
292
+ n.isGroupRow ? (e.push(n), N[n.path] !== !1 && t(n.children)) : e.push(n);
229
293
  });
230
294
  };
231
- return t(X), e;
295
+ return t(We), e;
232
296
  }, [
297
+ We,
298
+ N,
299
+ M,
300
+ x
301
+ ]), Ke = u(null), [qe, Je] = d(0), [Ye, Xe] = d(0);
302
+ c(() => {
303
+ let e = Ke.current;
304
+ if (!e) return;
305
+ let t = () => Je(e.scrollTop);
306
+ Xe(e.clientHeight), Je(e.scrollTop), e.addEventListener("scroll", t, { passive: !0 });
307
+ let n;
308
+ return typeof ResizeObserver < "u" && (n = new ResizeObserver(() => Xe(e.clientHeight)), n.observe(e)), () => {
309
+ e.removeEventListener("scroll", t), n?.disconnect();
310
+ };
311
+ }, []);
312
+ let Z = X.length, { startIndex: Ze, endIndex: Qe, topSpacerHeight: Q, bottomSpacerHeight: $e } = l(() => {
313
+ if (Ye === 0) return {
314
+ startIndex: 0,
315
+ endIndex: Z,
316
+ topSpacerHeight: 0,
317
+ bottomSpacerHeight: 0
318
+ };
319
+ let e = Math.floor(qe / w), t = Math.ceil(Ye / w), n = Math.max(0, e - me), r = Math.min(Z, e + t + me);
320
+ return {
321
+ startIndex: n,
322
+ endIndex: r,
323
+ topSpacerHeight: n * w,
324
+ bottomSpacerHeight: (Z - r) * w
325
+ };
326
+ }, [
327
+ qe,
328
+ Ye,
329
+ Z,
330
+ w,
331
+ me
332
+ ]), et = l(() => X.slice(Ze, Qe), [
233
333
  X,
234
- L,
235
- F,
236
- S
237
- ]), Q = (e, t = !1, n) => {
238
- let r = _e[e];
334
+ Ze,
335
+ Qe
336
+ ]), tt = (e, t = !1, n) => {
337
+ let r = Re[e];
239
338
  if (!r) return n || {};
240
339
  let i = r.side === "right";
241
340
  return {
@@ -247,18 +346,18 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
247
346
  boxShadow: i ? "-2px 0 5px -2px rgba(0,0,0,0.1)" : "2px 0 5px -2px rgba(0,0,0,0.1)",
248
347
  ...n
249
348
  };
250
- }, xe = u(() => T.map((e, t) => (T.length - 1 - t) * 48), [T]), $ = U.length + +!!x + (S && F.length > 0 ? 1 : 0);
349
+ }, nt = l(() => C.map((e, t) => (C.length - 1 - t) * 48), [C]), $ = W.length + +!!b + (x && M.length > 0 ? 1 : 0);
251
350
  return /* @__PURE__ */ m("div", {
252
- ref: W,
351
+ ref: G,
253
352
  className: "flexi-root",
254
- children: [S && /* @__PURE__ */ p("div", {
353
+ children: [x && /* @__PURE__ */ p("div", {
255
354
  onDragOver: (e) => {
256
- e.preventDefault(), R(!0);
355
+ e.preventDefault(), P(!0);
257
356
  },
258
- onDragLeave: () => R(!1),
259
- onDrop: he,
260
- className: g("flexi-groupzone", ce && "flexi-groupzone--dragover"),
261
- children: F.length === 0 ? /* @__PURE__ */ p("span", {
357
+ onDragLeave: () => P(!1),
358
+ onDrop: Ie,
359
+ className: g("flexi-groupzone", Ce && "flexi-groupzone--dragover"),
360
+ children: M.length === 0 ? /* @__PURE__ */ p("span", {
262
361
  className: "flexi-groupzone-hint",
263
362
  children: "Drag a column header here to group your records by that field"
264
363
  }) : /* @__PURE__ */ m("div", {
@@ -266,35 +365,39 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
266
365
  children: [/* @__PURE__ */ p("span", {
267
366
  className: "flexi-groupzone-label",
268
367
  children: "Grouped By:"
269
- }), F.map((e) => /* @__PURE__ */ m("div", {
368
+ }), M.map((e) => /* @__PURE__ */ m("div", {
270
369
  className: "flexi-chip",
271
- children: [/* @__PURE__ */ p("span", { children: B.find((t) => t.key === e)?.header || e }), /* @__PURE__ */ p("button", {
370
+ children: [/* @__PURE__ */ p("span", { children: V.find((t) => t.key === e)?.header || e }), /* @__PURE__ */ p("button", {
272
371
  type: "button",
273
- onClick: () => ge(e),
372
+ onClick: () => Le(e),
274
373
  className: "flexi-icon-btn flexi-chip-remove",
275
- children: /* @__PURE__ */ p(c, { className: "flexi-icon-xs" })
374
+ children: /* @__PURE__ */ p(ee, { className: "flexi-icon-xs" })
276
375
  })]
277
376
  }, e))]
278
377
  })
279
378
  }), /* @__PURE__ */ p("div", {
379
+ ref: Ke,
280
380
  className: "flexi-table-wrap",
281
- style: re,
381
+ style: ue,
282
382
  children: /* @__PURE__ */ m("table", {
283
- className: g("flexi-table", ae && "flexi-table--bordered"),
284
- style: ie,
383
+ className: g("flexi-table", fe && "flexi-table--bordered"),
384
+ style: de,
285
385
  children: [
286
386
  /* @__PURE__ */ m("colgroup", { children: [
287
- S && F.length > 0 && /* @__PURE__ */ p("col", { style: { width: "48px" } }),
288
- U.map((e) => /* @__PURE__ */ p("col", { style: e.style }, e.key)),
289
- x && /* @__PURE__ */ p("col", { style: { width: "100px" } })
387
+ x && M.length > 0 && /* @__PURE__ */ p("col", { style: { width: "48px" } }),
388
+ W.map((e) => /* @__PURE__ */ p("col", { style: {
389
+ ...e.style,
390
+ width: J(e)
391
+ } }, e.key)),
392
+ b && /* @__PURE__ */ p("col", { style: { width: "100px" } })
290
393
  ] }),
291
394
  /* @__PURE__ */ p("thead", {
292
395
  className: "flexi-thead",
293
- children: K.map((r, i) => /* @__PURE__ */ m("tr", {
396
+ children: q.map((r, i) => /* @__PURE__ */ m("tr", {
294
397
  className: "flexi-header-row",
295
398
  children: [
296
- i === 0 && S && F.length > 0 && /* @__PURE__ */ p("th", {
297
- rowSpan: K.length,
399
+ i === 0 && x && M.length > 0 && /* @__PURE__ */ p("th", {
400
+ rowSpan: q.length,
298
401
  className: "flexi-group-spacer-th",
299
402
  style: {
300
403
  position: "sticky",
@@ -304,59 +407,59 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
304
407
  backgroundColor: "rgb(248, 250, 252)"
305
408
  }
306
409
  }),
307
- r.map(({ col: r, rowSpan: i, colSpan: c }) => {
308
- let l = (k[r.key]?.length || 0) > 0, u = !!V[r.key], d = Q(r.key, !0, r.headerStyle), f = !r.children || r.children.length === 0, h = z.key === r.key, _ = !!(S && f);
309
- return /* @__PURE__ */ p("th", {
410
+ r.map(({ col: r, rowSpan: i, colSpan: ee }) => {
411
+ let c = (D[r.key]?.length || 0) > 0, l = !!H[r.key], u = tt(r.key, !0, r.headerStyle), d = !r.children || r.children.length === 0, f = F.key === r.key, h = !!(x && d), ne = d && r.resizable !== !1;
412
+ return /* @__PURE__ */ m("th", {
310
413
  rowSpan: i,
311
- colSpan: c,
312
- ..._ ? {
313
- draggable: !0,
314
- onDragStart: (e) => me(e, r.key)
315
- } : {},
316
- className: g("flexi-th", _ && "flexi-th--draggable", u && "flexi-th--pinned", r.className),
317
- style: d,
318
- children: /* @__PURE__ */ m("div", {
414
+ colSpan: ee,
415
+ draggable: !0,
416
+ onDragStart: (e) => Me(e, r.key, d),
417
+ onDragOver: (e) => e.preventDefault(),
418
+ onDrop: (e) => Pe(e, r.key),
419
+ className: g("flexi-th", "flexi-th--draggable", h && "flexi-th--group-draggable", l && "flexi-th--pinned", r.className, r.headerClassName),
420
+ style: u,
421
+ children: [/* @__PURE__ */ m("div", {
319
422
  className: "flexi-th-inner",
320
423
  children: [
321
424
  /* @__PURE__ */ m("div", {
322
- className: g("flexi-th-label", r.sortable && f && "flexi-th-label--sortable"),
323
- onClick: () => r.sortable && f && pe(r.key),
425
+ className: g("flexi-th-label", r.sortable && d && "flexi-th-label--sortable"),
426
+ onClick: () => r.sortable && d && je(r.key),
324
427
  children: [/* @__PURE__ */ p("span", {
325
428
  className: "flexi-th-text",
326
429
  children: r.header
327
- }), f && r.sortable && /* @__PURE__ */ p("span", {
328
- className: g("flexi-sort-icon", h && "flexi-sort-icon--active"),
329
- children: h && z.direction === "asc" ? /* @__PURE__ */ p(t, { className: "flexi-icon-sm" }) : h && z.direction === "desc" ? /* @__PURE__ */ p(e, { className: "flexi-icon-sm" }) : /* @__PURE__ */ p(n, { className: "flexi-icon-sm" })
430
+ }), d && r.sortable && /* @__PURE__ */ p("span", {
431
+ className: g("flexi-sort-icon", f && "flexi-sort-icon--active"),
432
+ children: f && F.direction === "asc" ? /* @__PURE__ */ p(t, { className: "flexi-icon-sm" }) : f && F.direction === "desc" ? /* @__PURE__ */ p(e, { className: "flexi-icon-sm" }) : /* @__PURE__ */ p(n, { className: "flexi-icon-sm" })
330
433
  })]
331
434
  }),
332
435
  /* @__PURE__ */ m("div", {
333
436
  className: "flexi-th-actions",
334
- children: [f && r.filterable && /* @__PURE__ */ p("button", {
437
+ children: [d && r.filterable && /* @__PURE__ */ p("button", {
335
438
  type: "button",
336
439
  ref: (e) => {
337
- e ? P.current.set(r.key, e) : P.current.delete(r.key);
440
+ e ? j.current.set(r.key, e) : j.current.delete(r.key);
338
441
  },
339
442
  onClick: (e) => {
340
- e.stopPropagation(), M(""), O(D === r.key ? null : r.key);
443
+ e.stopPropagation(), k(""), ve(E === r.key ? null : r.key);
341
444
  },
342
- className: g("flexi-icon-btn", "flexi-filter-btn", l && "flexi-filter-btn--active"),
445
+ className: g("flexi-icon-btn", "flexi-filter-btn", c && "flexi-filter-btn--active"),
343
446
  children: /* @__PURE__ */ p(a, { className: "flexi-icon-sm" })
344
- }), f && /* @__PURE__ */ p("button", {
447
+ }), d && /* @__PURE__ */ p("button", {
345
448
  type: "button",
346
449
  onClick: (e) => {
347
- e.stopPropagation(), fe(r.key);
450
+ e.stopPropagation(), Ae(r.key);
348
451
  },
349
- className: g("flexi-icon-btn", "flexi-pin-btn", u && "flexi-pin-btn--pinned"),
350
- title: V[r.key] === "left" ? "Pinned left (click to pin right)" : V[r.key] === "right" ? "Pinned right (click to unpin)" : "Pin column left",
351
- children: p(u ? s : o, { className: "flexi-icon-sm" })
452
+ className: g("flexi-icon-btn", "flexi-pin-btn", l && "flexi-pin-btn--pinned"),
453
+ title: H[r.key] === "left" ? "Pinned left (click to pin right)" : H[r.key] === "right" ? "Pinned right (click to unpin)" : "Pin column left",
454
+ children: p(l ? s : o, { className: "flexi-icon-sm" })
352
455
  })]
353
456
  }),
354
- D === r.key && f && N && W.current && ee(/* @__PURE__ */ m("div", {
355
- ref: G,
457
+ E === r.key && d && A && G.current && te(/* @__PURE__ */ m("div", {
458
+ ref: K,
356
459
  className: "flexi-filter-dropdown",
357
460
  style: {
358
- top: N.top,
359
- left: N.left,
461
+ top: A.top,
462
+ left: A.left,
360
463
  zIndex: 9999
361
464
  },
362
465
  children: [
@@ -365,47 +468,52 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
365
468
  children: /* @__PURE__ */ p("input", {
366
469
  type: "text",
367
470
  placeholder: "Search values...",
368
- value: j,
369
- onChange: (e) => M(e.target.value),
471
+ value: O,
472
+ onChange: (e) => k(e.target.value),
370
473
  className: "flexi-input",
371
474
  onClick: (e) => e.stopPropagation()
372
475
  })
373
476
  }),
374
477
  /* @__PURE__ */ p("div", {
375
478
  className: "flexi-filter-list",
376
- children: J.length === 0 ? /* @__PURE__ */ p("div", {
479
+ children: He.length === 0 ? /* @__PURE__ */ p("div", {
377
480
  className: "flexi-filter-empty",
378
481
  children: "No results found"
379
- }) : J.map((e, t) => /* @__PURE__ */ m("label", {
482
+ }) : He.map((e, t) => /* @__PURE__ */ m("label", {
380
483
  className: "flexi-filter-option",
381
484
  children: [/* @__PURE__ */ p("input", {
382
485
  type: "checkbox",
383
486
  className: "flexi-checkbox",
384
- checked: k[r.key]?.includes(e) || !1,
385
- onChange: () => ve(r.key, e)
487
+ checked: D[r.key]?.includes(e) || !1,
488
+ onChange: () => ze(r.key, e)
386
489
  }), /* @__PURE__ */ p("span", {
387
490
  className: "flexi-filter-option-text",
388
491
  children: String(e)
389
492
  })]
390
493
  }, t))
391
494
  }),
392
- l && /* @__PURE__ */ p("div", {
495
+ c && /* @__PURE__ */ p("div", {
393
496
  className: "flexi-filter-footer",
394
497
  children: /* @__PURE__ */ p("button", {
395
498
  type: "button",
396
- onClick: () => ye(r.key),
499
+ onClick: () => Be(r.key),
397
500
  className: "flexi-filter-clear",
398
501
  children: "Clear Filter"
399
502
  })
400
503
  })
401
504
  ]
402
- }), W.current)
505
+ }), G.current)
403
506
  ]
404
- })
507
+ }), ne && /* @__PURE__ */ p("div", {
508
+ className: "flexi-th-resizer",
509
+ onMouseDown: (e) => Fe(e, r),
510
+ onClick: (e) => e.stopPropagation(),
511
+ onDragStart: (e) => e.preventDefault()
512
+ })]
405
513
  }, r.key);
406
514
  }),
407
- i === 0 && x && /* @__PURE__ */ p("th", {
408
- rowSpan: K.length,
515
+ i === 0 && b && /* @__PURE__ */ p("th", {
516
+ rowSpan: q.length,
409
517
  className: "flexi-actions-th",
410
518
  style: {
411
519
  position: "sticky",
@@ -420,27 +528,53 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
420
528
  }),
421
529
  /* @__PURE__ */ p("tbody", {
422
530
  className: "flexi-tbody",
423
- children: te ? /* @__PURE__ */ p("tr", { children: /* @__PURE__ */ p("td", {
531
+ children: se ? /* @__PURE__ */ p("tr", { children: /* @__PURE__ */ p("td", {
424
532
  colSpan: $,
425
533
  className: "flexi-empty-cell",
426
534
  children: "Loading records..."
427
- }) }) : Z.length === 0 ? /* @__PURE__ */ p("tr", { children: /* @__PURE__ */ p("td", {
535
+ }) }) : X.length === 0 ? /* @__PURE__ */ p("tr", { children: /* @__PURE__ */ p("td", {
428
536
  colSpan: $,
429
537
  className: "flexi-empty-cell",
430
538
  children: "No records found matching criteria."
431
- }) }) : Z.map((e, t) => Se(e, t))
539
+ }) }) : /* @__PURE__ */ m(f, { children: [
540
+ Q > 0 && /* @__PURE__ */ p("tr", {
541
+ "aria-hidden": "true",
542
+ style: { height: Q },
543
+ children: /* @__PURE__ */ p("td", {
544
+ colSpan: $,
545
+ style: {
546
+ padding: 0,
547
+ border: "none",
548
+ height: Q
549
+ }
550
+ })
551
+ }),
552
+ et.map((e, t) => rt(e, Ze + t)),
553
+ $e > 0 && /* @__PURE__ */ p("tr", {
554
+ "aria-hidden": "true",
555
+ style: { height: $e },
556
+ children: /* @__PURE__ */ p("td", {
557
+ colSpan: $,
558
+ style: {
559
+ padding: 0,
560
+ border: "none",
561
+ height: $e
562
+ }
563
+ })
564
+ })
565
+ ] })
432
566
  }),
433
- T.length > 0 && /* @__PURE__ */ p("tbody", {
567
+ C.length > 0 && /* @__PURE__ */ p("tbody", {
434
568
  className: "flexi-tbody flexi-tbody--pinned-bottom",
435
- children: T.map((e, t) => Ce(e, t))
569
+ children: C.map((e, t) => it(e, t))
436
570
  })
437
571
  ]
438
572
  })
439
573
  })]
440
574
  });
441
- function Se(e, t) {
575
+ function rt(e, t) {
442
576
  if (e.isGroupRow) {
443
- let n = L[e.path] !== !1;
577
+ let n = N[e.path] !== !1;
444
578
  return /* @__PURE__ */ m("tr", {
445
579
  className: "flexi-group-row",
446
580
  children: [/* @__PURE__ */ p("td", {
@@ -454,7 +588,7 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
454
588
  },
455
589
  children: /* @__PURE__ */ m("button", {
456
590
  type: "button",
457
- onClick: () => be(e.path),
591
+ onClick: () => Ge(e.path),
458
592
  className: "flexi-group-toggle",
459
593
  children: [
460
594
  p(n ? r : i, { className: "flexi-icon-md flexi-icon-muted" }),
@@ -474,11 +608,12 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
474
608
  })]
475
609
  }, `group-header-${e.path}-${t}`);
476
610
  }
477
- let n = de(e);
611
+ let n = Oe(e);
478
612
  return /* @__PURE__ */ m("tr", {
479
- className: "flexi-row",
613
+ className: g("flexi-row", T && "flexi-row--clickable", ke(e, t)),
614
+ onClick: T ? (n) => T(e, t, n) : void 0,
480
615
  children: [
481
- S && F?.length > 0 && /* @__PURE__ */ p("td", {
616
+ x && M?.length > 0 && /* @__PURE__ */ p("td", {
482
617
  className: "flexi-row-indent-cell",
483
618
  style: {
484
619
  position: "sticky",
@@ -486,10 +621,10 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
486
621
  zIndex: 10
487
622
  }
488
623
  }),
489
- U?.map((t) => {
490
- let n = e[t.key], r = Q(t.key, !1, t.style);
624
+ W?.map((t) => {
625
+ let n = e[t.key], r = tt(t.key, !1, t.style);
491
626
  return /* @__PURE__ */ p("td", {
492
- className: g("flexi-cell", !!V[t.key] && "flexi-cell--pinned", t.className),
627
+ className: g("flexi-cell", !!H[t.key] && "flexi-cell--pinned", t.className),
493
628
  style: r,
494
629
  children: t.render ? t.render(n, e) : /* @__PURE__ */ p("span", {
495
630
  className: "flexi-cell-text",
@@ -497,7 +632,7 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
497
632
  })
498
633
  }, t.key);
499
634
  }),
500
- x && /* @__PURE__ */ p("td", {
635
+ b && /* @__PURE__ */ p("td", {
501
636
  className: "flexi-actions-cell",
502
637
  style: {
503
638
  position: "sticky",
@@ -505,16 +640,16 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
505
640
  },
506
641
  children: /* @__PURE__ */ p("div", {
507
642
  className: "flexi-actions-inner",
508
- children: x(e)
643
+ children: b(e)
509
644
  })
510
645
  })
511
646
  ]
512
647
  }, n ?? `row-${t}`);
513
648
  }
514
- function Ce(e, t) {
515
- let n = typeof E == "function" ? E(e, t) : E, r = {
649
+ function it(e, t) {
650
+ let n = typeof pe == "function" ? pe(e, t) : pe, r = {
516
651
  position: "sticky",
517
- bottom: `${xe[t]}px`,
652
+ bottom: `${nt[t]}px`,
518
653
  background: "#",
519
654
  zIndex: 45
520
655
  };
@@ -522,7 +657,7 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
522
657
  className: g("flexi-row", "flexi-row--pinned-bottom", n),
523
658
  style: r,
524
659
  children: [
525
- S && F?.length > 0 && /* @__PURE__ */ p("td", {
660
+ x && M?.length > 0 && /* @__PURE__ */ p("td", {
526
661
  className: "flexi-row-indent-cell",
527
662
  style: {
528
663
  position: "sticky",
@@ -530,8 +665,8 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
530
665
  zIndex: 10
531
666
  }
532
667
  }),
533
- U?.map((t) => {
534
- let n = e[t.key], r = Q(t.key, !1, t.style), i = !!V[t.key], a = t.pinnedRender ?? t.render;
668
+ W?.map((t) => {
669
+ let n = e[t.key], r = tt(t.key, !1, t.style), i = !!H[t.key], a = t.pinnedRender ?? t.render;
535
670
  return /* @__PURE__ */ p("td", {
536
671
  className: g("flexi-cell", i && "flexi-cell--pinned", t.className),
537
672
  style: r,
@@ -541,7 +676,7 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
541
676
  })
542
677
  }, t.key);
543
678
  }),
544
- x && /* @__PURE__ */ p("td", {
679
+ b && /* @__PURE__ */ p("td", {
545
680
  className: "flexi-actions-cell",
546
681
  style: {
547
682
  position: "sticky",
@@ -549,7 +684,7 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
549
684
  },
550
685
  children: /* @__PURE__ */ p("div", {
551
686
  className: "flexi-actions-inner",
552
- children: x(e)
687
+ children: b(e)
553
688
  })
554
689
  })
555
690
  ]
@@ -557,4 +692,4 @@ function v({ columns: v, data: y, rowKey: b, actions: x, isLoading: te, groupBy:
557
692
  }
558
693
  }
559
694
  //#endregion
560
- export { v as DataTable };
695
+ export { _ as DataTable };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("lucide-react"),require("react"),require("react-dom"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`lucide-react`,`react`,`react-dom`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.FlexiDataGrid={},e.LucideReact,e.React,e.ReactDOM,e.JSX))})(this,function(e,t,n,r,i){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var a=Object.create,o=Object.defineProperty,s=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty,d=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=c(t),a=0,l=i.length,d;a<l;a++)d=i[a],!u.call(e,d)&&d!==n&&o(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=s(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:a(l(e)),d(t||!e||!e.__esModule?o(n,`default`,{value:e,enumerable:!0}):n,e)))(n,1);var f=e=>{let t=[];return e.forEach(e=>{e.children&&e.children.length>0?t.push(...f(e.children)):t.push(e)}),t},p=(...e)=>e.filter(Boolean).join(` `),m=e=>{if(e===!0)return`left`;if(e===`left`||e===`right`)return e};function h({columns:e,data:a,rowKey:o,actions:s,isLoading:c,groupBy:l=!1,defaultGroupBy:u=[],onPinChange:d,onGroupChange:h,containerStyle:g,tableStyle:ee,bordered:te=!1,pinnedBottomRowData:_=[],pinnedRowClassName:v}){let[y,b]=(0,n.useState)(null),[x,S]=(0,n.useState)({}),[C,w]=(0,n.useState)(``),[T,E]=(0,n.useState)(null),D=(0,n.useRef)(new Map),[O,k]=(0,n.useState)(u),[A,j]=(0,n.useState)({}),[ne,M]=(0,n.useState)(!1),[N,re]=(0,n.useState)({key:null,direction:null}),P=(0,n.useMemo)(()=>f(e),[e]),[F,ie]=(0,n.useState)(()=>{let e={};return P.forEach(t=>{let n=m(t.pinned);n&&(e[t.key]=n)}),e}),I=(0,n.useMemo)(()=>{let t=e=>{let n=e=>{let t=F[e];return t===`left`?0:t===`right`?2:1};return[...e].sort((e,t)=>n(e.key)-n(t.key)).map(e=>e.children&&e.children.length>0?{...e,children:t(e.children)}:e)};return t(e)},[e,F]),L=(0,n.useMemo)(()=>{let e=f(I),t=l?O:[];return e.filter(e=>!t.includes(e.key))},[I,O,l]),R=(0,n.useRef)(null),z=(0,n.useRef)(null);(0,n.useEffect)(()=>{function e(e){let t=e.target,n=y?D.current.get(y):null;z.current&&!z.current.contains(t)&&!(n&&n.contains(t))&&(b(null),w(``))}return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[y]),(0,n.useEffect)(()=>{if(!y)return;let e=()=>{let e=D.current.get(y),t=R.current;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect();E({top:n.bottom-r.top+4,left:n.left-r.left})};return e(),window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,e),()=>{window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,e)}},[y]);let ae=e=>typeof o==`function`?o(e):String(e[o]),oe=e=>{ie(t=>{let n=t[e],r=n?n===`left`?`right`:void 0:`left`,i={...t};return r?i[e]=r:delete i[e],d&&d(e,!!r,r),i})},B=e=>{let t=`asc`;N.key===e&&(t=N.direction===`asc`?`desc`:N.direction===`desc`?null:`asc`),re({key:t?e:null,direction:t})},V=(e,t)=>{l&&(e.dataTransfer.setData(`text/plain`,t),e.dataTransfer.effectAllowed=`move`)},H=e=>{e.preventDefault(),M(!1);let t=e.dataTransfer.getData(`text/plain`);if(t&&!O.includes(t)){let e=[...O,t];k(e),h&&h(e)}},U=e=>{let t=O.filter(t=>t!==e);k(t),j({}),h&&h(t)},W=(0,n.useMemo)(()=>{let e=t=>{let n=0;return t.forEach(t=>{n=t.children&&t.children.length>0?Math.max(n,1+e(t.children)):Math.max(n,1)}),n},t=e(I),n=Array.from({length:t},()=>[]),r=e=>!e.children||e.children.length===0?O.includes(e.key)&&l?0:1:e.children.reduce((e,t)=>e+r(t),0),i=l?O:[],a=(e,o)=>{e.forEach(e=>{if(i.includes(e.key))return;let s=r(e);s!==0&&(e.children&&e.children.length>0?(n[o].push({col:e,rowSpan:1,colSpan:s}),a(e.children,o+1)):n[o].push({col:e,rowSpan:t-o,colSpan:1}))})};return a(I,0),n.filter(e=>e.length>0)},[I,O,l]),G=e=>{let t=e.style?.width||e.headerStyle?.width||`150px`;return typeof t==`number`?t:parseInt(String(t),10)||150},K=(0,n.useMemo)(()=>{let e={},t=0;l&&O.length>0&&(t+=48),L.forEach(n=>{F[n.key]===`left`&&(e[n.key]={side:`left`,offset:t},t+=G(n))});let n=s?100:0;for(let t=L.length-1;t>=0;t--){let r=L[t];F[r.key]===`right`&&(e[r.key]={side:`right`,offset:n},n+=G(r))}return e},[L,F,O,l,s]),se=(e,t)=>{S(n=>{let r=n[e]||[],i=r.includes(t)?r.filter(e=>e!==t):[...r,t],a={...n,[e]:i};return a[e].length===0&&delete a[e],a})},q=e=>{S(t=>{let n={...t};return delete n[e],n})},J=(0,n.useMemo)(()=>{if(!y)return[];let e=P.find(e=>e.key===y),t=a.map(t=>e?.getValue?e.getValue(t):t[y]),n=Array.from(new Set(t)).filter(e=>e!=null);return C.trim()?n.filter(e=>String(e).toLowerCase().includes(C.toLowerCase())):n},[a,y,C,P]),Y=(0,n.useMemo)(()=>{let e=a.filter(e=>Object.entries(x).every(([t,n])=>{if(!n||n.length===0)return!0;let r=P.find(e=>e.key===t),i=r?.getValue?r.getValue(e):e[t];return n.includes(i)}));if(N.key&&N.direction){let{key:t,direction:n}=N,r=P.find(e=>e.key===t);e=[...e].sort((e,i)=>{let a=r?.getValue?r.getValue(e):e[t],o=r?.getValue?r.getValue(i):i[t];if(a===o)return 0;if(a==null)return 1;if(o==null)return-1;let s=0;return s=typeof a==`number`&&typeof o==`number`?a-o:String(a).localeCompare(String(o),void 0,{numeric:!0,sensitivity:`base`}),n===`asc`?s:-s})}return e},[a,x,N,P]),X=(0,n.useMemo)(()=>{if(!l||O.length===0)return Y;let e=(t,n,r=``)=>{if(n>=O.length)return t;let i=O[n],a=P.find(e=>e.key===i),o={};return t.forEach(e=>{let t=a?.getValue?a.getValue(e):e[i],n=String(t??`N/A`);o[n]||(o[n]=[]),o[n].push(e)}),Object.entries(o).map(([t,a])=>{let o=r?`${r}➔${t}`:t;return{isGroupRow:!0,groupKey:i,groupValue:t,path:o,depth:n,children:e(a,n+1,o),totalItemsCount:a.length}})};return e(Y,0)},[Y,O,l,P]),ce=e=>{j(t=>{let n=t[e]!==!1;return{...t,[e]:!n}})},Z=(0,n.useMemo)(()=>{if(!l||O.length===0)return X;let e=[],t=n=>{n.forEach(n=>{n.isGroupRow?(e.push(n),A[n.path]!==!1&&t(n.children)):e.push(n)})};return t(X),e},[X,A,O,l]),Q=(e,t=!1,n)=>{let r=K[e];if(!r)return n||{};let i=r.side===`right`;return{position:`sticky`,[i?`right`:`left`]:`${r.offset}px`,...t?{top:0}:{},zIndex:t?30:20,background:`#f8fafc`,boxShadow:i?`-2px 0 5px -2px rgba(0,0,0,0.1)`:`2px 0 5px -2px rgba(0,0,0,0.1)`,...n}},le=(0,n.useMemo)(()=>_.map((e,t)=>(_.length-1-t)*48),[_]),$=L.length+ +!!s+(l&&O.length>0?1:0);return(0,i.jsxs)(`div`,{ref:R,className:`flexi-root`,children:[l&&(0,i.jsx)(`div`,{onDragOver:e=>{e.preventDefault(),M(!0)},onDragLeave:()=>M(!1),onDrop:H,className:p(`flexi-groupzone`,ne&&`flexi-groupzone--dragover`),children:O.length===0?(0,i.jsx)(`span`,{className:`flexi-groupzone-hint`,children:`Drag a column header here to group your records by that field`}):(0,i.jsxs)(`div`,{className:`flexi-groupzone-chips`,children:[(0,i.jsx)(`span`,{className:`flexi-groupzone-label`,children:`Grouped By:`}),O.map(e=>(0,i.jsxs)(`div`,{className:`flexi-chip`,children:[(0,i.jsx)(`span`,{children:P.find(t=>t.key===e)?.header||e}),(0,i.jsx)(`button`,{type:`button`,onClick:()=>U(e),className:`flexi-icon-btn flexi-chip-remove`,children:(0,i.jsx)(t.X,{className:`flexi-icon-xs`})})]},e))]})}),(0,i.jsx)(`div`,{className:`flexi-table-wrap`,style:g,children:(0,i.jsxs)(`table`,{className:p(`flexi-table`,te&&`flexi-table--bordered`),style:ee,children:[(0,i.jsxs)(`colgroup`,{children:[l&&O.length>0&&(0,i.jsx)(`col`,{style:{width:`48px`}}),L.map(e=>(0,i.jsx)(`col`,{style:e.style},e.key)),s&&(0,i.jsx)(`col`,{style:{width:`100px`}})]}),(0,i.jsx)(`thead`,{className:`flexi-thead`,children:W.map((e,n)=>(0,i.jsxs)(`tr`,{className:`flexi-header-row`,children:[n===0&&l&&O.length>0&&(0,i.jsx)(`th`,{rowSpan:W.length,className:`flexi-group-spacer-th`,style:{position:`sticky`,top:0,left:0,zIndex:35,backgroundColor:`rgb(248, 250, 252)`}}),e.map(({col:e,rowSpan:n,colSpan:a})=>{let o=(x[e.key]?.length||0)>0,s=!!F[e.key],c=Q(e.key,!0,e.headerStyle),u=!e.children||e.children.length===0,d=N.key===e.key,f=!!(l&&u);return(0,i.jsx)(`th`,{rowSpan:n,colSpan:a,...f?{draggable:!0,onDragStart:t=>V(t,e.key)}:{},className:p(`flexi-th`,f&&`flexi-th--draggable`,s&&`flexi-th--pinned`,e.className),style:c,children:(0,i.jsxs)(`div`,{className:`flexi-th-inner`,children:[(0,i.jsxs)(`div`,{className:p(`flexi-th-label`,e.sortable&&u&&`flexi-th-label--sortable`),onClick:()=>e.sortable&&u&&B(e.key),children:[(0,i.jsx)(`span`,{className:`flexi-th-text`,children:e.header}),u&&e.sortable&&(0,i.jsx)(`span`,{className:p(`flexi-sort-icon`,d&&`flexi-sort-icon--active`),children:d&&N.direction===`asc`?(0,i.jsx)(t.ArrowUp,{className:`flexi-icon-sm`}):d&&N.direction===`desc`?(0,i.jsx)(t.ArrowDown,{className:`flexi-icon-sm`}):(0,i.jsx)(t.ArrowUpDown,{className:`flexi-icon-sm`})})]}),(0,i.jsxs)(`div`,{className:`flexi-th-actions`,children:[u&&e.filterable&&(0,i.jsx)(`button`,{type:`button`,ref:t=>{t?D.current.set(e.key,t):D.current.delete(e.key)},onClick:t=>{t.stopPropagation(),w(``),b(y===e.key?null:e.key)},className:p(`flexi-icon-btn`,`flexi-filter-btn`,o&&`flexi-filter-btn--active`),children:(0,i.jsx)(t.Filter,{className:`flexi-icon-sm`})}),u&&(0,i.jsx)(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),oe(e.key)},className:p(`flexi-icon-btn`,`flexi-pin-btn`,s&&`flexi-pin-btn--pinned`),title:F[e.key]===`left`?`Pinned left (click to pin right)`:F[e.key]===`right`?`Pinned right (click to unpin)`:`Pin column left`,children:s?(0,i.jsx)(t.PinOff,{className:`flexi-icon-sm`}):(0,i.jsx)(t.Pin,{className:`flexi-icon-sm`})})]}),y===e.key&&u&&T&&R.current&&(0,r.createPortal)((0,i.jsxs)(`div`,{ref:z,className:`flexi-filter-dropdown`,style:{top:T.top,left:T.left,zIndex:9999},children:[(0,i.jsx)(`div`,{className:`flexi-filter-search`,children:(0,i.jsx)(`input`,{type:`text`,placeholder:`Search values...`,value:C,onChange:e=>w(e.target.value),className:`flexi-input`,onClick:e=>e.stopPropagation()})}),(0,i.jsx)(`div`,{className:`flexi-filter-list`,children:J.length===0?(0,i.jsx)(`div`,{className:`flexi-filter-empty`,children:`No results found`}):J.map((t,n)=>(0,i.jsxs)(`label`,{className:`flexi-filter-option`,children:[(0,i.jsx)(`input`,{type:`checkbox`,className:`flexi-checkbox`,checked:x[e.key]?.includes(t)||!1,onChange:()=>se(e.key,t)}),(0,i.jsx)(`span`,{className:`flexi-filter-option-text`,children:String(t)})]},n))}),o&&(0,i.jsx)(`div`,{className:`flexi-filter-footer`,children:(0,i.jsx)(`button`,{type:`button`,onClick:()=>q(e.key),className:`flexi-filter-clear`,children:`Clear Filter`})})]}),R.current)]})},e.key)}),n===0&&s&&(0,i.jsx)(`th`,{rowSpan:W.length,className:`flexi-actions-th`,style:{position:`sticky`,top:0,right:0,zIndex:35,backgroundColor:`rgb(248, 250, 252)`}})]},`header-row-${n}`))}),(0,i.jsx)(`tbody`,{className:`flexi-tbody`,children:c?(0,i.jsx)(`tr`,{children:(0,i.jsx)(`td`,{colSpan:$,className:`flexi-empty-cell`,children:`Loading records...`})}):Z.length===0?(0,i.jsx)(`tr`,{children:(0,i.jsx)(`td`,{colSpan:$,className:`flexi-empty-cell`,children:`No records found matching criteria.`})}):Z.map((e,t)=>ue(e,t))}),_.length>0&&(0,i.jsx)(`tbody`,{className:`flexi-tbody flexi-tbody--pinned-bottom`,children:_.map((e,t)=>de(e,t))})]})})]});function ue(e,n){if(e.isGroupRow){let r=A[e.path]!==!1;return(0,i.jsxs)(`tr`,{className:`flexi-group-row`,children:[(0,i.jsx)(`td`,{className:`flexi-group-cell`,style:{position:`sticky`,left:0,zIndex:20,backgroundColor:`rgba(248, 250, 252, 0.9)`,paddingLeft:`${e.depth*12+16}px`},children:(0,i.jsxs)(`button`,{type:`button`,onClick:()=>ce(e.path),className:`flexi-group-toggle`,children:[r?(0,i.jsx)(t.ChevronDown,{className:`flexi-icon-md flexi-icon-muted`}):(0,i.jsx)(t.ChevronRight,{className:`flexi-icon-md flexi-icon-muted`}),(0,i.jsx)(`span`,{className:`flexi-group-value`,children:e.groupValue}),(0,i.jsx)(`span`,{className:`flexi-group-count`,children:e.totalItemsCount})]})}),(0,i.jsx)(`td`,{colSpan:$-1,className:`flexi-group-filler`})]},`group-header-${e.path}-${n}`)}let r=ae(e);return(0,i.jsxs)(`tr`,{className:`flexi-row`,children:[l&&O?.length>0&&(0,i.jsx)(`td`,{className:`flexi-row-indent-cell`,style:{position:`sticky`,left:0,zIndex:10}}),L?.map(t=>{let n=e[t.key],r=Q(t.key,!1,t.style);return(0,i.jsx)(`td`,{className:p(`flexi-cell`,!!F[t.key]&&`flexi-cell--pinned`,t.className),style:r,children:t.render?t.render(n,e):(0,i.jsx)(`span`,{className:`flexi-cell-text`,children:n})},t.key)}),s&&(0,i.jsx)(`td`,{className:`flexi-actions-cell`,style:{position:`sticky`,right:0},children:(0,i.jsx)(`div`,{className:`flexi-actions-inner`,children:s(e)})})]},r??`row-${n}`)}function de(e,t){let n=typeof v==`function`?v(e,t):v,r={position:`sticky`,bottom:`${le[t]}px`,background:`#`,zIndex:45};return(0,i.jsxs)(`tr`,{className:p(`flexi-row`,`flexi-row--pinned-bottom`,n),style:r,children:[l&&O?.length>0&&(0,i.jsx)(`td`,{className:`flexi-row-indent-cell`,style:{position:`sticky`,left:0,zIndex:10}}),L?.map(t=>{let n=e[t.key],r=Q(t.key,!1,t.style),a=!!F[t.key],o=t.pinnedRender??t.render;return(0,i.jsx)(`td`,{className:p(`flexi-cell`,a&&`flexi-cell--pinned`,t.className),style:r,children:o?o(n,e):(0,i.jsx)(`span`,{className:`flexi-cell-text`,children:n})},t.key)}),s&&(0,i.jsx)(`td`,{className:`flexi-actions-cell`,style:{position:`sticky`,right:0},children:(0,i.jsx)(`div`,{className:`flexi-actions-inner`,children:s(e)})})]},`pinned-bottom-row-${t}`)}}e.DataTable=h});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("lucide-react"),require("react"),require("react-dom"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`lucide-react`,`react`,`react-dom`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.FlexiDataGrid={},e.LucideReact,e.React,e.ReactDOM,e.JSX))})(this,function(e,t,n,r,i){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var a=Object.create,o=Object.defineProperty,s=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty,d=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=c(t),a=0,l=i.length,d;a<l;a++)d=i[a],!u.call(e,d)&&d!==n&&o(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=s(t,d))||r.enumerable});return e};n=((e,t,n)=>(n=e==null?{}:a(l(e)),d(t||!e||!e.__esModule?o(n,`default`,{value:e,enumerable:!0}):n,e)))(n,1);var f=e=>{let t=[];return e.forEach(e=>{e.children&&e.children.length>0?t.push(...f(e.children)):t.push(e)}),t},p=(...e)=>e.filter(Boolean).join(` `),ee=e=>{if(e===!0)return`left`;if(e===`left`||e===`right`)return e},te=(e,t,n)=>{let r=e=>{let n=t[e];return n===`left`?0:n===`right`?2:1},i=e=>e.map((e,t)=>({col:e,idx:t})).sort((e,t)=>{let i=r(e.col.key)-r(t.col.key);return i===0?(n[e.col.key]??e.idx)-(n[t.col.key]??t.idx):i}).map(({col:e})=>e.children&&e.children.length>0?{...e,children:i(e.children)}:e);return i(e)},ne=48,re=150,ie=60;function m({columns:e,data:a,rowKey:o,actions:s,isLoading:c,groupBy:l=!1,defaultGroupBy:u=[],onPinChange:d,onGroupChange:m,containerStyle:ae,tableStyle:oe,bordered:se=!1,pinnedBottomRowData:h=[],pinnedRowClassName:g,rowHeight:_=ne,overscan:v=8,onColumnResize:ce,onColumnReorder:le,rowClassRules:y,onRowClick:b}){let[x,ue]=(0,n.useState)(null),[S,de]=(0,n.useState)({}),[C,w]=(0,n.useState)(``),[T,fe]=(0,n.useState)(null),E=(0,n.useRef)(new Map),[D,pe]=(0,n.useState)(u),[O,me]=(0,n.useState)({}),[he,k]=(0,n.useState)(!1),[A,ge]=(0,n.useState)({key:null,direction:null}),[j,_e]=(0,n.useState)({}),[M,ve]=(0,n.useState)({}),N=(0,n.useRef)(null),P=(0,n.useRef)(!1),F=(0,n.useRef)(null),I=(0,n.useMemo)(()=>f(e),[e]),[L,ye]=(0,n.useState)(()=>{let e={};return I.forEach(t=>{let n=ee(t.pinned);n&&(e[t.key]=n)}),e}),R=(0,n.useMemo)(()=>te(e,L,M),[e,L,M]),z=(0,n.useMemo)(()=>{let e=f(R),t=l?D:[];return e.filter(e=>!t.includes(e.key))},[R,D,l]),B=(0,n.useRef)(null),V=(0,n.useRef)(null);(0,n.useEffect)(()=>{function e(e){let t=e.target,n=x?E.current.get(x):null;V.current&&!V.current.contains(t)&&!(n&&n.contains(t))&&(ue(null),w(``))}return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)},[x]),(0,n.useEffect)(()=>{if(!x)return;let e=()=>{let e=E.current.get(x),t=B.current;if(!e||!t)return;let n=e.getBoundingClientRect(),r=t.getBoundingClientRect();fe({top:n.bottom-r.top+4,left:n.left-r.left})};return e(),window.addEventListener(`scroll`,e,!0),window.addEventListener(`resize`,e),()=>{window.removeEventListener(`scroll`,e,!0),window.removeEventListener(`resize`,e)}},[x]);let be=e=>typeof o==`function`?o(e):String(e[o]),xe=(e,t)=>{if(!y)return;let n;for(let r in y)y[r](e,t)&&(n=n?`${n} ${r}`:r);return n},Se=e=>{ye(t=>{let n=t[e],r=n?n===`left`?`right`:void 0:`left`,i={...t};return r?i[e]=r:delete i[e],d&&d(e,!!r,r),i})},Ce=e=>{let t=`asc`;A.key===e&&(t=A.direction===`asc`?`desc`:A.direction===`desc`?null:`asc`),ge({key:t?e:null,direction:t})},we=(e,t,n)=>{if(P.current){e.preventDefault();return}N.current=t,n&&e.dataTransfer.setData(`text/plain`,t),e.dataTransfer.effectAllowed=`move`},Te=(e,t,n)=>{let r=e.map(e=>e.key);if(r.includes(t)&&r.includes(n))return e;for(let r of e)if(r.children&&r.children.length>0){let e=Te(r.children,t,n);if(e)return e}return null},Ee=(t,n)=>{t.preventDefault(),t.stopPropagation();let r=N.current;if(N.current=null,!r||r===n)return;let i=Te(R,r,n);if(!i)return;let a=i.map(e=>e.key),o=a.indexOf(r),s=a.indexOf(n);a.splice(s,0,a.splice(o,1)[0]);let c={...M};a.forEach((e,t)=>{c[e]=t}),ve(c),le&&le(f(te(e,L,c)).map(e=>e.key))},De=(e,t)=>{e.preventDefault(),e.stopPropagation(),P.current=!0,F.current={key:t.key,startX:e.clientX,startWidth:U(t)};let n=t.minWidth??ie,r=t.maxWidth,i=e=>{let t=F.current;if(!t)return;let i=t.startWidth+(e.clientX-t.startX);i=Math.max(n,i),r&&(i=Math.min(r,i)),_e(e=>e[t.key]===i?e:{...e,[t.key]:i})},a=()=>{let e=F.current;F.current=null,window.removeEventListener(`mousemove`,i),window.removeEventListener(`mouseup`,a),requestAnimationFrame(()=>{P.current=!1}),e&&ce&&_e(t=>(t[e.key]!==void 0&&ce(e.key,t[e.key]),t))};window.addEventListener(`mousemove`,i),window.addEventListener(`mouseup`,a)},Oe=e=>{e.preventDefault(),k(!1);let t=e.dataTransfer.getData(`text/plain`);if(t&&!D.includes(t)){let e=[...D,t];pe(e),m&&m(e)}},ke=e=>{let t=D.filter(t=>t!==e);pe(t),me({}),m&&m(t)},H=(0,n.useMemo)(()=>{let e=t=>{let n=0;return t.forEach(t=>{n=t.children&&t.children.length>0?Math.max(n,1+e(t.children)):Math.max(n,1)}),n},t=e(R),n=Array.from({length:t},()=>[]),r=e=>!e.children||e.children.length===0?D.includes(e.key)&&l?0:1:e.children.reduce((e,t)=>e+r(t),0),i=l?D:[],a=(e,o)=>{e.forEach(e=>{if(i.includes(e.key))return;let s=r(e);s!==0&&(e.children&&e.children.length>0?(n[o].push({col:e,rowSpan:1,colSpan:s}),a(e.children,o+1)):n[o].push({col:e,rowSpan:t-o,colSpan:1}))})};return a(R,0),n.filter(e=>e.length>0)},[R,D,l]),U=e=>{if(j[e.key]!==void 0)return j[e.key];let t=e.style?.width||e.headerStyle?.width||`${re}px`;return typeof t==`number`?t:parseInt(String(t),10)||re},Ae=(0,n.useMemo)(()=>{let e={},t=0;l&&D.length>0&&(t+=48),z.forEach(n=>{L[n.key]===`left`&&(e[n.key]={side:`left`,offset:t},t+=U(n))});let n=s?100:0;for(let t=z.length-1;t>=0;t--){let r=z[t];L[r.key]===`right`&&(e[r.key]={side:`right`,offset:n},n+=U(r))}return e},[z,L,D,l,s,j]),je=(e,t)=>{de(n=>{let r=n[e]||[],i=r.includes(t)?r.filter(e=>e!==t):[...r,t],a={...n,[e]:i};return a[e].length===0&&delete a[e],a})},Me=e=>{de(t=>{let n={...t};return delete n[e],n})},W=(0,n.useMemo)(()=>{let e=new Map;return I.forEach(t=>e.set(t.key,t)),e},[I]),G=(0,n.useMemo)(()=>{if(!x)return[];let e=W.get(x),t=a.map(t=>e?.getValue?e.getValue(t):t[x]);return Array.from(new Set(t)).filter(e=>e!=null)},[a,x,W]),Ne=(0,n.useMemo)(()=>{if(!C.trim())return G;let e=C.toLowerCase();return G.filter(t=>String(t).toLowerCase().includes(e))},[G,C]),K=(0,n.useMemo)(()=>{let e=Object.entries(S).filter(([,e])=>e&&e.length>0),t=e.length===0?a:a.filter(t=>e.every(([e,n])=>{let r=W.get(e),i=r?.getValue?r.getValue(t):t[e];return n.includes(i)}));if(A.key&&A.direction){let{key:e,direction:n}=A,r=W.get(e);t=[...t].sort((t,i)=>{let a=r?.getValue?r.getValue(t):t[e],o=r?.getValue?r.getValue(i):i[e];if(a===o)return 0;if(a==null)return 1;if(o==null)return-1;let s=0;return s=typeof a==`number`&&typeof o==`number`?a-o:String(a).localeCompare(String(o),void 0,{numeric:!0,sensitivity:`base`}),n===`asc`?s:-s})}return t},[a,S,A,W]),q=(0,n.useMemo)(()=>{if(!l||D.length===0)return K;let e=(t,n,r=``)=>{if(n>=D.length)return t;let i=D[n],a=W.get(i),o={};return t.forEach(e=>{let t=a?.getValue?a.getValue(e):e[i],n=String(t??`N/A`);o[n]||(o[n]=[]),o[n].push(e)}),Object.entries(o).map(([t,a])=>{let o=r?`${r}➔${t}`:t;return{isGroupRow:!0,groupKey:i,groupValue:t,path:o,depth:n,children:e(a,n+1,o),totalItemsCount:a.length}})};return e(K,0)},[K,D,l,W]),Pe=e=>{me(t=>{let n=t[e]!==!1;return{...t,[e]:!n}})},J=(0,n.useMemo)(()=>{if(!l||D.length===0)return q;let e=[],t=n=>{n.forEach(n=>{n.isGroupRow?(e.push(n),O[n.path]!==!1&&t(n.children)):e.push(n)})};return t(q),e},[q,O,D,l]),Fe=(0,n.useRef)(null),[Ie,Le]=(0,n.useState)(0),[Y,Re]=(0,n.useState)(0);(0,n.useEffect)(()=>{let e=Fe.current;if(!e)return;let t=()=>Le(e.scrollTop);Re(e.clientHeight),Le(e.scrollTop),e.addEventListener(`scroll`,t,{passive:!0});let n;return typeof ResizeObserver<`u`&&(n=new ResizeObserver(()=>Re(e.clientHeight)),n.observe(e)),()=>{e.removeEventListener(`scroll`,t),n?.disconnect()}},[]);let X=J.length,{startIndex:Z,endIndex:ze,topSpacerHeight:Q,bottomSpacerHeight:Be}=(0,n.useMemo)(()=>{if(Y===0)return{startIndex:0,endIndex:X,topSpacerHeight:0,bottomSpacerHeight:0};let e=Math.floor(Ie/_),t=Math.ceil(Y/_),n=Math.max(0,e-v),r=Math.min(X,e+t+v);return{startIndex:n,endIndex:r,topSpacerHeight:n*_,bottomSpacerHeight:(X-r)*_}},[Ie,Y,X,_,v]),Ve=(0,n.useMemo)(()=>J.slice(Z,ze),[J,Z,ze]),He=(e,t=!1,n)=>{let r=Ae[e];if(!r)return n||{};let i=r.side===`right`;return{position:`sticky`,[i?`right`:`left`]:`${r.offset}px`,...t?{top:0}:{},zIndex:t?30:20,background:`#f8fafc`,boxShadow:i?`-2px 0 5px -2px rgba(0,0,0,0.1)`:`2px 0 5px -2px rgba(0,0,0,0.1)`,...n}},Ue=(0,n.useMemo)(()=>h.map((e,t)=>(h.length-1-t)*48),[h]),$=z.length+ +!!s+(l&&D.length>0?1:0);return(0,i.jsxs)(`div`,{ref:B,className:`flexi-root`,children:[l&&(0,i.jsx)(`div`,{onDragOver:e=>{e.preventDefault(),k(!0)},onDragLeave:()=>k(!1),onDrop:Oe,className:p(`flexi-groupzone`,he&&`flexi-groupzone--dragover`),children:D.length===0?(0,i.jsx)(`span`,{className:`flexi-groupzone-hint`,children:`Drag a column header here to group your records by that field`}):(0,i.jsxs)(`div`,{className:`flexi-groupzone-chips`,children:[(0,i.jsx)(`span`,{className:`flexi-groupzone-label`,children:`Grouped By:`}),D.map(e=>(0,i.jsxs)(`div`,{className:`flexi-chip`,children:[(0,i.jsx)(`span`,{children:I.find(t=>t.key===e)?.header||e}),(0,i.jsx)(`button`,{type:`button`,onClick:()=>ke(e),className:`flexi-icon-btn flexi-chip-remove`,children:(0,i.jsx)(t.X,{className:`flexi-icon-xs`})})]},e))]})}),(0,i.jsx)(`div`,{ref:Fe,className:`flexi-table-wrap`,style:ae,children:(0,i.jsxs)(`table`,{className:p(`flexi-table`,se&&`flexi-table--bordered`),style:oe,children:[(0,i.jsxs)(`colgroup`,{children:[l&&D.length>0&&(0,i.jsx)(`col`,{style:{width:`48px`}}),z.map(e=>(0,i.jsx)(`col`,{style:{...e.style,width:U(e)}},e.key)),s&&(0,i.jsx)(`col`,{style:{width:`100px`}})]}),(0,i.jsx)(`thead`,{className:`flexi-thead`,children:H.map((e,n)=>(0,i.jsxs)(`tr`,{className:`flexi-header-row`,children:[n===0&&l&&D.length>0&&(0,i.jsx)(`th`,{rowSpan:H.length,className:`flexi-group-spacer-th`,style:{position:`sticky`,top:0,left:0,zIndex:35,backgroundColor:`rgb(248, 250, 252)`}}),e.map(({col:e,rowSpan:n,colSpan:a})=>{let o=(S[e.key]?.length||0)>0,s=!!L[e.key],c=He(e.key,!0,e.headerStyle),u=!e.children||e.children.length===0,d=A.key===e.key,f=!!(l&&u),ee=u&&e.resizable!==!1;return(0,i.jsxs)(`th`,{rowSpan:n,colSpan:a,draggable:!0,onDragStart:t=>we(t,e.key,u),onDragOver:e=>e.preventDefault(),onDrop:t=>Ee(t,e.key),className:p(`flexi-th`,`flexi-th--draggable`,f&&`flexi-th--group-draggable`,s&&`flexi-th--pinned`,e.className,e.headerClassName),style:c,children:[(0,i.jsxs)(`div`,{className:`flexi-th-inner`,children:[(0,i.jsxs)(`div`,{className:p(`flexi-th-label`,e.sortable&&u&&`flexi-th-label--sortable`),onClick:()=>e.sortable&&u&&Ce(e.key),children:[(0,i.jsx)(`span`,{className:`flexi-th-text`,children:e.header}),u&&e.sortable&&(0,i.jsx)(`span`,{className:p(`flexi-sort-icon`,d&&`flexi-sort-icon--active`),children:d&&A.direction===`asc`?(0,i.jsx)(t.ArrowUp,{className:`flexi-icon-sm`}):d&&A.direction===`desc`?(0,i.jsx)(t.ArrowDown,{className:`flexi-icon-sm`}):(0,i.jsx)(t.ArrowUpDown,{className:`flexi-icon-sm`})})]}),(0,i.jsxs)(`div`,{className:`flexi-th-actions`,children:[u&&e.filterable&&(0,i.jsx)(`button`,{type:`button`,ref:t=>{t?E.current.set(e.key,t):E.current.delete(e.key)},onClick:t=>{t.stopPropagation(),w(``),ue(x===e.key?null:e.key)},className:p(`flexi-icon-btn`,`flexi-filter-btn`,o&&`flexi-filter-btn--active`),children:(0,i.jsx)(t.Filter,{className:`flexi-icon-sm`})}),u&&(0,i.jsx)(`button`,{type:`button`,onClick:t=>{t.stopPropagation(),Se(e.key)},className:p(`flexi-icon-btn`,`flexi-pin-btn`,s&&`flexi-pin-btn--pinned`),title:L[e.key]===`left`?`Pinned left (click to pin right)`:L[e.key]===`right`?`Pinned right (click to unpin)`:`Pin column left`,children:s?(0,i.jsx)(t.PinOff,{className:`flexi-icon-sm`}):(0,i.jsx)(t.Pin,{className:`flexi-icon-sm`})})]}),x===e.key&&u&&T&&B.current&&(0,r.createPortal)((0,i.jsxs)(`div`,{ref:V,className:`flexi-filter-dropdown`,style:{top:T.top,left:T.left,zIndex:9999},children:[(0,i.jsx)(`div`,{className:`flexi-filter-search`,children:(0,i.jsx)(`input`,{type:`text`,placeholder:`Search values...`,value:C,onChange:e=>w(e.target.value),className:`flexi-input`,onClick:e=>e.stopPropagation()})}),(0,i.jsx)(`div`,{className:`flexi-filter-list`,children:Ne.length===0?(0,i.jsx)(`div`,{className:`flexi-filter-empty`,children:`No results found`}):Ne.map((t,n)=>(0,i.jsxs)(`label`,{className:`flexi-filter-option`,children:[(0,i.jsx)(`input`,{type:`checkbox`,className:`flexi-checkbox`,checked:S[e.key]?.includes(t)||!1,onChange:()=>je(e.key,t)}),(0,i.jsx)(`span`,{className:`flexi-filter-option-text`,children:String(t)})]},n))}),o&&(0,i.jsx)(`div`,{className:`flexi-filter-footer`,children:(0,i.jsx)(`button`,{type:`button`,onClick:()=>Me(e.key),className:`flexi-filter-clear`,children:`Clear Filter`})})]}),B.current)]}),ee&&(0,i.jsx)(`div`,{className:`flexi-th-resizer`,onMouseDown:t=>De(t,e),onClick:e=>e.stopPropagation(),onDragStart:e=>e.preventDefault()})]},e.key)}),n===0&&s&&(0,i.jsx)(`th`,{rowSpan:H.length,className:`flexi-actions-th`,style:{position:`sticky`,top:0,right:0,zIndex:35,backgroundColor:`rgb(248, 250, 252)`}})]},`header-row-${n}`))}),(0,i.jsx)(`tbody`,{className:`flexi-tbody`,children:c?(0,i.jsx)(`tr`,{children:(0,i.jsx)(`td`,{colSpan:$,className:`flexi-empty-cell`,children:`Loading records...`})}):J.length===0?(0,i.jsx)(`tr`,{children:(0,i.jsx)(`td`,{colSpan:$,className:`flexi-empty-cell`,children:`No records found matching criteria.`})}):(0,i.jsxs)(i.Fragment,{children:[Q>0&&(0,i.jsx)(`tr`,{"aria-hidden":`true`,style:{height:Q},children:(0,i.jsx)(`td`,{colSpan:$,style:{padding:0,border:`none`,height:Q}})}),Ve.map((e,t)=>We(e,Z+t)),Be>0&&(0,i.jsx)(`tr`,{"aria-hidden":`true`,style:{height:Be},children:(0,i.jsx)(`td`,{colSpan:$,style:{padding:0,border:`none`,height:Be}})})]})}),h.length>0&&(0,i.jsx)(`tbody`,{className:`flexi-tbody flexi-tbody--pinned-bottom`,children:h.map((e,t)=>Ge(e,t))})]})})]});function We(e,n){if(e.isGroupRow){let r=O[e.path]!==!1;return(0,i.jsxs)(`tr`,{className:`flexi-group-row`,children:[(0,i.jsx)(`td`,{className:`flexi-group-cell`,style:{position:`sticky`,left:0,zIndex:20,backgroundColor:`rgba(248, 250, 252, 0.9)`,paddingLeft:`${e.depth*12+16}px`},children:(0,i.jsxs)(`button`,{type:`button`,onClick:()=>Pe(e.path),className:`flexi-group-toggle`,children:[r?(0,i.jsx)(t.ChevronDown,{className:`flexi-icon-md flexi-icon-muted`}):(0,i.jsx)(t.ChevronRight,{className:`flexi-icon-md flexi-icon-muted`}),(0,i.jsx)(`span`,{className:`flexi-group-value`,children:e.groupValue}),(0,i.jsx)(`span`,{className:`flexi-group-count`,children:e.totalItemsCount})]})}),(0,i.jsx)(`td`,{colSpan:$-1,className:`flexi-group-filler`})]},`group-header-${e.path}-${n}`)}let r=be(e);return(0,i.jsxs)(`tr`,{className:p(`flexi-row`,b&&`flexi-row--clickable`,xe(e,n)),onClick:b?t=>b(e,n,t):void 0,children:[l&&D?.length>0&&(0,i.jsx)(`td`,{className:`flexi-row-indent-cell`,style:{position:`sticky`,left:0,zIndex:10}}),z?.map(t=>{let n=e[t.key],r=He(t.key,!1,t.style);return(0,i.jsx)(`td`,{className:p(`flexi-cell`,!!L[t.key]&&`flexi-cell--pinned`,t.className),style:r,children:t.render?t.render(n,e):(0,i.jsx)(`span`,{className:`flexi-cell-text`,children:n})},t.key)}),s&&(0,i.jsx)(`td`,{className:`flexi-actions-cell`,style:{position:`sticky`,right:0},children:(0,i.jsx)(`div`,{className:`flexi-actions-inner`,children:s(e)})})]},r??`row-${n}`)}function Ge(e,t){let n=typeof g==`function`?g(e,t):g,r={position:`sticky`,bottom:`${Ue[t]}px`,background:`#`,zIndex:45};return(0,i.jsxs)(`tr`,{className:p(`flexi-row`,`flexi-row--pinned-bottom`,n),style:r,children:[l&&D?.length>0&&(0,i.jsx)(`td`,{className:`flexi-row-indent-cell`,style:{position:`sticky`,left:0,zIndex:10}}),z?.map(t=>{let n=e[t.key],r=He(t.key,!1,t.style),a=!!L[t.key],o=t.pinnedRender??t.render;return(0,i.jsx)(`td`,{className:p(`flexi-cell`,a&&`flexi-cell--pinned`,t.className),style:r,children:o?o(n,e):(0,i.jsx)(`span`,{className:`flexi-cell-text`,children:n})},t.key)}),s&&(0,i.jsx)(`td`,{className:`flexi-actions-cell`,style:{position:`sticky`,right:0},children:(0,i.jsx)(`div`,{className:`flexi-actions-inner`,children:s(e)})})]},`pinned-bottom-row-${t}`)}}e.DataTable=m});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flexi-datagrid",
3
- "version": "1.2.4",
3
+ "version": "1.2.6",
4
4
  "description": "A powerful universal datagrid with tree-grouping, column pinning, and drag-and-drop.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.umd.js",