@zvndev/yable-react 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,21 +1,24 @@
1
1
  'use strict';
2
2
 
3
3
  var yableCore = require('@zvndev/yable-core');
4
- var React3 = require('react');
4
+ var React4 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
+ var reactDom = require('react-dom');
6
7
  var rowDragging = require('@zvndev/yable-core/features/rowDragging');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
10
- var React3__default = /*#__PURE__*/_interopDefault(React3);
11
+ var React4__default = /*#__PURE__*/_interopDefault(React4);
11
12
 
12
13
  // src/index.ts
13
- var YableContext = React3.createContext({});
14
+ var YableContext = React4.createContext({});
14
15
  function useYableDefaults() {
15
- return React3.useContext(YableContext);
16
+ return React4.useContext(YableContext);
16
17
  }
17
18
  function YableProvider({
18
19
  children,
20
+ config,
21
+ tableProfile,
19
22
  defaultColumnDef,
20
23
  striped,
21
24
  stickyHeader,
@@ -34,12 +37,86 @@ function YableProvider({
34
37
  if (direction !== void 0) tableProps.direction = direction;
35
38
  if (ariaLabel !== void 0) tableProps.ariaLabel = ariaLabel;
36
39
  const value = {
40
+ config,
41
+ tableProfile,
37
42
  tableProps: Object.keys(tableProps).length > 0 ? tableProps : void 0,
38
43
  defaultColumnDef
39
44
  };
40
45
  return /* @__PURE__ */ jsxRuntime.jsx(YableContext.Provider, { value, children });
41
46
  }
42
47
 
48
+ // src/config.ts
49
+ function createYableConfig(config) {
50
+ return config;
51
+ }
52
+ function resolveYableProfile(config, profileName = "default") {
53
+ const base = pickProfileFields(config);
54
+ const named = profileName === "default" ? void 0 : config?.profiles?.[profileName];
55
+ return {
56
+ name: profileName,
57
+ table: { ...base.table, ...named?.table },
58
+ columns: {
59
+ default: { ...base.columns?.default, ...named?.columns?.default },
60
+ byId: { ...base.columns?.byId, ...named?.columns?.byId }
61
+ },
62
+ rows: { ...base.rows, ...named?.rows },
63
+ cells: {
64
+ default: { ...base.cells?.default, ...named?.cells?.default },
65
+ named: { ...base.cells?.named, ...named?.cells?.named },
66
+ byColumn: { ...base.cells?.byColumn, ...named?.cells?.byColumn }
67
+ }
68
+ };
69
+ }
70
+ function getYableDefaultColumnDef(profile) {
71
+ const next = {
72
+ ...profile?.columns?.default
73
+ };
74
+ return Object.keys(next).length > 0 ? next : void 0;
75
+ }
76
+ function applyYableConfigToColumns(columns, profile) {
77
+ if (!profile) return columns;
78
+ return columns.map((columnDef) => applyColumnConfig(columnDef, profile));
79
+ }
80
+ function applyColumnConfig(columnDef, profile) {
81
+ const columnId = getColumnId(columnDef);
82
+ const explicit = columnDef;
83
+ const cellNames = normalizeCellConfigNames(explicit.cellConfig);
84
+ const namedCellConfig = cellNames.reduce(
85
+ (acc, name) => ({ ...acc, ...profile.cells?.named?.[name] }),
86
+ {}
87
+ );
88
+ const defaultCell = profile.cells?.default;
89
+ const columnCell = columnId ? profile.cells?.byColumn?.[columnId] : void 0;
90
+ const columnConfig = columnId ? profile.columns?.byId?.[columnId] : void 0;
91
+ const children = "columns" in columnDef && columnDef.columns ? { columns: columnDef.columns.map((child) => applyColumnConfig(child, profile)) } : void 0;
92
+ return {
93
+ ...defaultCell,
94
+ ...namedCellConfig,
95
+ ...columnCell,
96
+ ...columnConfig,
97
+ ...columnDef,
98
+ ...children
99
+ };
100
+ }
101
+ function pickProfileFields(config) {
102
+ if (!config) return {};
103
+ return {
104
+ table: config.table,
105
+ columns: config.columns,
106
+ rows: config.rows,
107
+ cells: config.cells
108
+ };
109
+ }
110
+ function getColumnId(columnDef) {
111
+ if ("id" in columnDef && columnDef.id) return String(columnDef.id);
112
+ if ("accessorKey" in columnDef && columnDef.accessorKey) return String(columnDef.accessorKey);
113
+ return void 0;
114
+ }
115
+ function normalizeCellConfigNames(value) {
116
+ if (!value) return [];
117
+ return Array.isArray(value) ? value : [value];
118
+ }
119
+
43
120
  // src/useTable.ts
44
121
  function shallowEqual(a, b) {
45
122
  if (a === b) return true;
@@ -54,17 +131,32 @@ function shallowEqual(a, b) {
54
131
  }
55
132
  function useTable(options) {
56
133
  const providerDefaults = useYableDefaults();
57
- const optionsWithDefaults = React3.useMemo(() => {
58
- if (!providerDefaults.defaultColumnDef) return options;
134
+ const optionsWithDefaults = React4.useMemo(() => {
135
+ const profile = resolveYableProfile(
136
+ options.config ?? providerDefaults.config,
137
+ options.configProfile ?? providerDefaults.tableProfile
138
+ );
139
+ const profileDefaultColumnDef = getYableDefaultColumnDef(profile);
140
+ const configuredColumns = applyYableConfigToColumns(options.columns, profile);
141
+ const defaultColumnDef = {
142
+ ...profileDefaultColumnDef,
143
+ ...providerDefaults.defaultColumnDef,
144
+ ...options.defaultColumnDef
145
+ };
59
146
  return {
60
147
  ...options,
61
- defaultColumnDef: {
62
- ...providerDefaults.defaultColumnDef,
63
- ...options.defaultColumnDef
64
- }
148
+ columns: configuredColumns,
149
+ rowClassName: options.rowClassName ?? profile.rows?.className,
150
+ rowStyle: options.rowStyle ?? profile.rows?.style,
151
+ defaultColumnDef: Object.keys(defaultColumnDef).length > 0 ? defaultColumnDef : void 0
65
152
  };
66
- }, [options, providerDefaults.defaultColumnDef]);
67
- const [state, setState] = React3.useState(() => ({
153
+ }, [
154
+ options,
155
+ providerDefaults.config,
156
+ providerDefaults.defaultColumnDef,
157
+ providerDefaults.tableProfile
158
+ ]);
159
+ const [state, setState] = React4.useState(() => ({
68
160
  sorting: [],
69
161
  columnFilters: [],
70
162
  globalFilter: "",
@@ -101,26 +193,26 @@ function useTable(options) {
101
193
  ...options.initialState,
102
194
  ...options.state
103
195
  }));
104
- const stateRef = React3.useRef(state);
196
+ const stateRef = React4.useRef(state);
105
197
  stateRef.current = state;
106
- const prevOptionsRef = React3.useRef(optionsWithDefaults);
107
- const stableOptions = React3.useMemo(() => {
198
+ const prevOptionsRef = React4.useRef(optionsWithDefaults);
199
+ const stableOptions = React4.useMemo(() => {
108
200
  if (shallowEqual(prevOptionsRef.current, optionsWithDefaults)) {
109
201
  return prevOptionsRef.current;
110
202
  }
111
203
  prevOptionsRef.current = optionsWithDefaults;
112
204
  return optionsWithDefaults;
113
205
  }, [optionsWithDefaults]);
114
- const onStateChangeRef = React3.useRef(options.onStateChange);
206
+ const onStateChangeRef = React4.useRef(options.onStateChange);
115
207
  onStateChangeRef.current = options.onStateChange;
116
- const resolvedState = React3.useMemo(
208
+ const resolvedState = React4.useMemo(
117
209
  () => ({
118
210
  ...state,
119
211
  ...stableOptions.state
120
212
  }),
121
213
  [state, stableOptions.state]
122
214
  );
123
- const onStateChange = React3.useCallback((updater) => {
215
+ const onStateChange = React4.useCallback((updater) => {
124
216
  const latest = onStateChangeRef.current;
125
217
  if (latest) {
126
218
  latest(updater);
@@ -128,7 +220,7 @@ function useTable(options) {
128
220
  setState((prev) => yableCore.functionalUpdate(updater, prev));
129
221
  }
130
222
  }, []);
131
- const resolvedOptions = React3.useMemo(
223
+ const resolvedOptions = React4.useMemo(
132
224
  () => ({
133
225
  ...stableOptions,
134
226
  state: resolvedState,
@@ -136,7 +228,7 @@ function useTable(options) {
136
228
  }),
137
229
  [stableOptions, resolvedState, onStateChange]
138
230
  );
139
- const tableRef = React3.useRef(null);
231
+ const tableRef = React4.useRef(null);
140
232
  if (!tableRef.current) {
141
233
  tableRef.current = yableCore.createTable(resolvedOptions);
142
234
  } else {
@@ -149,7 +241,33 @@ function useTable(options) {
149
241
  })
150
242
  );
151
243
  }
152
- React3.useEffect(() => {
244
+ React4.useEffect(() => {
245
+ const table = tableRef.current;
246
+ if (!table) return;
247
+ const unsubscribers = [
248
+ options.onCellClick && table.events.on("cell:click", options.onCellClick),
249
+ options.onCellDoubleClick && table.events.on("cell:dblclick", options.onCellDoubleClick),
250
+ options.onCellContextMenu && table.events.on("cell:contextmenu", options.onCellContextMenu),
251
+ options.onRowClick && table.events.on("row:click", options.onRowClick),
252
+ options.onRowDoubleClick && table.events.on("row:dblclick", options.onRowDoubleClick),
253
+ options.onRowContextMenu && table.events.on("row:contextmenu", options.onRowContextMenu),
254
+ options.onHeaderClick && table.events.on("header:click", options.onHeaderClick),
255
+ options.onHeaderContextMenu && table.events.on("header:contextmenu", options.onHeaderContextMenu)
256
+ ].filter((unsubscribe) => Boolean(unsubscribe));
257
+ return () => {
258
+ unsubscribers.forEach((unsubscribe) => unsubscribe());
259
+ };
260
+ }, [
261
+ options.onCellClick,
262
+ options.onCellContextMenu,
263
+ options.onCellDoubleClick,
264
+ options.onHeaderClick,
265
+ options.onHeaderContextMenu,
266
+ options.onRowClick,
267
+ options.onRowContextMenu,
268
+ options.onRowDoubleClick
269
+ ]);
270
+ React4.useEffect(() => {
153
271
  return () => {
154
272
  if (tableRef.current) {
155
273
  tableRef.current.events.removeAllListeners();
@@ -158,6 +276,195 @@ function useTable(options) {
158
276
  }, []);
159
277
  return tableRef.current;
160
278
  }
279
+ function useServerTable({
280
+ fetchData,
281
+ updateRow,
282
+ initialRows = [],
283
+ initialCursor = null,
284
+ initialHasMore = true,
285
+ initialRowCount,
286
+ initialPageCount,
287
+ initialSorting = [],
288
+ initialColumnFilters = [],
289
+ initialGlobalFilter = "",
290
+ initialPagination = { pageIndex: 0, pageSize: 50 },
291
+ autoLoad = true,
292
+ getRowId,
293
+ ...tableOptions
294
+ }) {
295
+ const [rows, setRows] = React4.useState(initialRows);
296
+ const [cursor, setCursor] = React4.useState(initialCursor);
297
+ const [hasMore, setHasMore] = React4.useState(initialHasMore);
298
+ const [rowCount, setRowCount] = React4.useState(initialRowCount);
299
+ const [pageCount, setPageCount] = React4.useState(initialPageCount);
300
+ const [sorting, setSorting] = React4.useState(initialSorting);
301
+ const [columnFilters, setColumnFilters] = React4.useState(initialColumnFilters);
302
+ const [globalFilter, setGlobalFilter] = React4.useState(initialGlobalFilter);
303
+ const [pagination, setPagination] = React4.useState(initialPagination);
304
+ const [loading, setLoading] = React4.useState(false);
305
+ const [error, setError] = React4.useState(null);
306
+ const abortRef = React4.useRef(null);
307
+ const cursorRef = React4.useRef(cursor);
308
+ const fetchDataRef = React4.useRef(fetchData);
309
+ const updateRowRef = React4.useRef(updateRow);
310
+ const resolveRowId = React4.useCallback(
311
+ (row, index) => getRowId?.(row, index) ?? String(row.id ?? index),
312
+ [getRowId]
313
+ );
314
+ const runFetch = React4.useCallback(
315
+ async (mode) => {
316
+ abortRef.current?.abort();
317
+ const abort = new AbortController();
318
+ abortRef.current = abort;
319
+ setLoading(true);
320
+ setError(null);
321
+ try {
322
+ const result = await fetchDataRef.current({
323
+ sorting,
324
+ columnFilters,
325
+ globalFilter,
326
+ pagination,
327
+ cursor: mode === "append" ? cursorRef.current : null,
328
+ signal: abort.signal
329
+ });
330
+ if (abort.signal.aborted) return;
331
+ setRows((prev) => mode === "append" ? [...prev, ...result.rows] : result.rows);
332
+ setCursor(result.cursor ?? null);
333
+ setHasMore((prev) => result.hasMore ?? prev);
334
+ setRowCount((prev) => result.rowCount ?? prev);
335
+ setPageCount((prev) => result.pageCount ?? prev);
336
+ } catch (nextError) {
337
+ if (!abort.signal.aborted) setError(nextError);
338
+ } finally {
339
+ if (!abort.signal.aborted) setLoading(false);
340
+ }
341
+ },
342
+ [columnFilters, globalFilter, pagination, sorting]
343
+ );
344
+ const refresh = React4.useCallback(() => runFetch("replace"), [runFetch]);
345
+ const loadMore = React4.useCallback(async () => {
346
+ if (!hasMore || loading) return;
347
+ await runFetch("append");
348
+ }, [hasMore, loading, runFetch]);
349
+ const patchRow = React4.useCallback(
350
+ async (rowId, patch) => {
351
+ const previousRow = rows.find((row, index) => resolveRowId(row, index) === rowId);
352
+ setRows(
353
+ (prev) => prev.map((row, index) => resolveRowId(row, index) === rowId ? { ...row, ...patch } : row)
354
+ );
355
+ if (!updateRowRef.current) return;
356
+ const abort = new AbortController();
357
+ try {
358
+ const result = await updateRowRef.current({
359
+ rowId,
360
+ patch,
361
+ previousRow,
362
+ signal: abort.signal
363
+ });
364
+ if (!result) return;
365
+ setRows(
366
+ (prev) => prev.map(
367
+ (row, index) => resolveRowId(row, index) === rowId ? { ...row, ...result } : row
368
+ )
369
+ );
370
+ } catch (nextError) {
371
+ setError(nextError);
372
+ if (previousRow) {
373
+ setRows(
374
+ (prev) => prev.map((row, index) => resolveRowId(row, index) === rowId ? previousRow : row)
375
+ );
376
+ }
377
+ }
378
+ },
379
+ [resolveRowId, rows]
380
+ );
381
+ React4.useEffect(() => {
382
+ fetchDataRef.current = fetchData;
383
+ }, [fetchData]);
384
+ React4.useEffect(() => {
385
+ updateRowRef.current = updateRow;
386
+ }, [updateRow]);
387
+ React4.useEffect(() => {
388
+ if (!autoLoad) return;
389
+ void refresh();
390
+ }, [autoLoad, refresh]);
391
+ React4.useEffect(() => {
392
+ cursorRef.current = cursor;
393
+ }, [cursor]);
394
+ React4.useEffect(() => () => abortRef.current?.abort(), []);
395
+ const table = useTable({
396
+ ...tableOptions,
397
+ data: rows,
398
+ getRowId: resolveRowId,
399
+ manualSorting: true,
400
+ manualFiltering: true,
401
+ manualPagination: true,
402
+ rowCount,
403
+ pageCount,
404
+ state: {
405
+ sorting,
406
+ columnFilters,
407
+ globalFilter,
408
+ pagination
409
+ },
410
+ onSortingChange: (updater) => {
411
+ setSorting((prev) => yableCore.functionalUpdate(updater, prev));
412
+ setCursor(null);
413
+ setHasMore(true);
414
+ },
415
+ onColumnFiltersChange: (updater) => {
416
+ setColumnFilters((prev) => yableCore.functionalUpdate(updater, prev));
417
+ setCursor(null);
418
+ setHasMore(true);
419
+ },
420
+ onGlobalFilterChange: (updater) => {
421
+ setGlobalFilter((prev) => yableCore.functionalUpdate(updater, prev));
422
+ setCursor(null);
423
+ setHasMore(true);
424
+ },
425
+ onPaginationChange: (updater) => {
426
+ setPagination((prev) => yableCore.functionalUpdate(updater, prev));
427
+ setCursor(null);
428
+ setHasMore(true);
429
+ }
430
+ });
431
+ return React4.useMemo(
432
+ () => ({
433
+ table,
434
+ rows,
435
+ loading,
436
+ error,
437
+ cursor,
438
+ hasMore,
439
+ rowCount,
440
+ pageCount,
441
+ sorting,
442
+ columnFilters,
443
+ globalFilter,
444
+ pagination,
445
+ refresh,
446
+ loadMore,
447
+ updateRow: patchRow
448
+ }),
449
+ [
450
+ table,
451
+ rows,
452
+ loading,
453
+ error,
454
+ cursor,
455
+ hasMore,
456
+ rowCount,
457
+ pageCount,
458
+ sorting,
459
+ columnFilters,
460
+ globalFilter,
461
+ pagination,
462
+ refresh,
463
+ loadMore,
464
+ patchRow
465
+ ]
466
+ );
467
+ }
161
468
  var DEFAULT_PERSISTED_KEYS = [
162
469
  "columnVisibility",
163
470
  "columnOrder",
@@ -221,25 +528,25 @@ function useTablePersistence(options) {
221
528
  version = 0,
222
529
  storage: customStorage
223
530
  } = options;
224
- const storage = React3.useMemo(() => resolveStorage(customStorage), [customStorage]);
225
- const initialState = React3.useMemo(
531
+ const storage = React4.useMemo(() => resolveStorage(customStorage), [customStorage]);
532
+ const initialState = React4.useMemo(
226
533
  () => readState(storage, key, version, persistedKeys),
227
534
  // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally read only on mount
228
535
  []
229
536
  );
230
- const [state, setState] = React3.useState(initialState);
231
- const timerRef = React3.useRef(null);
232
- const keyRef = React3.useRef(key);
537
+ const [state, setState] = React4.useState(initialState);
538
+ const timerRef = React4.useRef(null);
539
+ const keyRef = React4.useRef(key);
233
540
  keyRef.current = key;
234
- const versionRef = React3.useRef(version);
541
+ const versionRef = React4.useRef(version);
235
542
  versionRef.current = version;
236
- const persistedKeysRef = React3.useRef(persistedKeys);
543
+ const persistedKeysRef = React4.useRef(persistedKeys);
237
544
  persistedKeysRef.current = persistedKeys;
238
- const debounceRef = React3.useRef(debounceMs);
545
+ const debounceRef = React4.useRef(debounceMs);
239
546
  debounceRef.current = debounceMs;
240
- const storageRef = React3.useRef(storage);
547
+ const storageRef = React4.useRef(storage);
241
548
  storageRef.current = storage;
242
- const onStateChange = React3.useCallback((updater) => {
549
+ const onStateChange = React4.useCallback((updater) => {
243
550
  setState((prev) => {
244
551
  const next = yableCore.functionalUpdate(updater, prev);
245
552
  if (timerRef.current !== null) {
@@ -256,14 +563,14 @@ function useTablePersistence(options) {
256
563
  return next;
257
564
  });
258
565
  }, []);
259
- React3.useEffect(() => {
566
+ React4.useEffect(() => {
260
567
  return () => {
261
568
  if (timerRef.current !== null) {
262
569
  clearTimeout(timerRef.current);
263
570
  }
264
571
  };
265
572
  }, []);
266
- const clearPersistedState = React3.useCallback(() => {
573
+ const clearPersistedState = React4.useCallback(() => {
267
574
  const s = storageRef.current;
268
575
  if (s) {
269
576
  try {
@@ -292,10 +599,10 @@ function useVirtualization({
292
599
  }) {
293
600
  const hasPretextHeights = !!(pretextHeights && pretextPrefixSums && pretextHeights.length >= totalRows);
294
601
  const isFixedHeight = typeof rowHeight === "number" && !hasPretextHeights;
295
- const heightCacheRef = React3.useRef(/* @__PURE__ */ new Map());
296
- const heightCacheVersionRef = React3.useRef(0);
297
- const [heightCacheVersion, setHeightCacheVersion] = React3.useState(0);
298
- const getRowHeight = React3.useCallback(
602
+ const heightCacheRef = React4.useRef(/* @__PURE__ */ new Map());
603
+ const heightCacheVersionRef = React4.useRef(0);
604
+ const [heightCacheVersion, setHeightCacheVersion] = React4.useState(0);
605
+ const getRowHeight = React4.useCallback(
299
606
  (index) => {
300
607
  if (hasPretextHeights) return pretextHeights[index];
301
608
  if (isFixedHeight) return rowHeight;
@@ -309,9 +616,9 @@ function useVirtualization({
309
616
  // eslint-disable-next-line react-hooks/exhaustive-deps
310
617
  [rowHeight, isFixedHeight, hasPretextHeights, pretextHeights, heightCacheVersion]
311
618
  );
312
- const [scrollState, setScrollState] = React3.useState({ scrollTop: 0, containerHeight: 0 });
313
- const rafRef = React3.useRef(null);
314
- React3.useEffect(() => {
619
+ const [scrollState, setScrollState] = React4.useState({ scrollTop: 0, containerHeight: 0 });
620
+ const rafRef = React4.useRef(null);
621
+ React4.useEffect(() => {
315
622
  const container = containerRef.current;
316
623
  if (!container) return;
317
624
  setScrollState({
@@ -354,25 +661,25 @@ function useVirtualization({
354
661
  resizeObserver.disconnect();
355
662
  }
356
663
  };
357
- }, [containerRef]);
358
- React3.useEffect(() => {
664
+ }, [containerRef, totalRows]);
665
+ React4.useEffect(() => {
359
666
  if (!isFixedHeight) {
360
667
  heightCacheRef.current.clear();
361
668
  }
362
669
  }, [totalRows, isFixedHeight]);
363
- React3.useEffect(() => {
670
+ React4.useEffect(() => {
364
671
  if (!isFixedHeight && columnSizingHash !== void 0) {
365
672
  heightCacheRef.current.clear();
366
673
  heightCacheVersionRef.current += 1;
367
674
  setHeightCacheVersion(heightCacheVersionRef.current);
368
675
  }
369
676
  }, [columnSizingHash]);
370
- const invalidateRowHeights = React3.useCallback(() => {
677
+ const invalidateRowHeights = React4.useCallback(() => {
371
678
  heightCacheRef.current.clear();
372
679
  heightCacheVersionRef.current += 1;
373
680
  setHeightCacheVersion(heightCacheVersionRef.current);
374
681
  }, []);
375
- const scrollTo = React3.useCallback(
682
+ const scrollTo = React4.useCallback(
376
683
  (index) => {
377
684
  const container = containerRef.current;
378
685
  if (!container || totalRows === 0) return;
@@ -399,7 +706,7 @@ function useVirtualization({
399
706
  pretextPrefixSums
400
707
  ]
401
708
  );
402
- const totalHeight = React3.useMemo(() => {
709
+ const totalHeight = React4.useMemo(() => {
403
710
  if (totalRows === 0) return 0;
404
711
  if (hasPretextHeights && pretextPrefixSums) return pretextPrefixSums[totalRows];
405
712
  if (isFixedHeight) return totalRows * rowHeight;
@@ -545,15 +852,21 @@ function useColumnVirtualization({
545
852
  containerRef,
546
853
  columns,
547
854
  overscan = 2,
548
- enabled = true
855
+ enabled = true,
856
+ sizingKey
549
857
  }) {
550
- const [scrollState, setScrollState] = React3.useState({
858
+ const [scrollState, setScrollState] = React4.useState({
551
859
  scrollLeft: 0,
552
860
  containerWidth: 0
553
861
  });
554
- const rafRef = React3.useRef(null);
555
- const sizes = React3.useMemo(() => columns.map((column) => column.getSize()), [columns]);
556
- const offsets = React3.useMemo(() => {
862
+ const rafRef = React4.useRef(null);
863
+ const sizes = React4.useMemo(
864
+ () => columns.map((column) => column.getSize()),
865
+ // `sizingKey` is an explicit invalidation hook for stable Column objects whose getSize value changed.
866
+ // eslint-disable-next-line react-hooks/exhaustive-deps
867
+ [columns, sizingKey]
868
+ );
869
+ const offsets = React4.useMemo(() => {
557
870
  const next = new Array(columns.length + 1);
558
871
  next[0] = 0;
559
872
  for (let i = 0; i < columns.length; i++) {
@@ -562,7 +875,7 @@ function useColumnVirtualization({
562
875
  return next;
563
876
  }, [columns.length, sizes]);
564
877
  const totalWidth = offsets[offsets.length - 1] ?? 0;
565
- React3.useEffect(() => {
878
+ React4.useEffect(() => {
566
879
  const container = containerRef.current;
567
880
  if (!container) return;
568
881
  setScrollState({
@@ -609,7 +922,7 @@ function useColumnVirtualization({
609
922
  resizeObserver?.disconnect();
610
923
  };
611
924
  }, [containerRef]);
612
- const scrollToIndex = React3.useCallback(
925
+ const scrollToIndex = React4.useCallback(
613
926
  (index) => {
614
927
  const container = containerRef.current;
615
928
  if (!container || columns.length === 0) return;
@@ -697,12 +1010,12 @@ function usePretextMeasurement({
697
1010
  minRowHeight = 32,
698
1011
  enabled = true
699
1012
  }) {
700
- const [pretext, setPretext] = React3.useState(null);
701
- const [ready, setReady] = React3.useState(false);
702
- const prepareTimeRef = React3.useRef(0);
703
- const layoutTimeRef = React3.useRef(0);
1013
+ const [pretext, setPretext] = React4.useState(null);
1014
+ const [ready, setReady] = React4.useState(false);
1015
+ const prepareTimeRef = React4.useRef(0);
1016
+ const layoutTimeRef = React4.useRef(0);
704
1017
  const columnWidthsKey = columns.map((c) => `${c.columnId}:${c.width}`).join("|");
705
- React3.useEffect(() => {
1018
+ React4.useEffect(() => {
706
1019
  if (!enabled) return;
707
1020
  let cancelled = false;
708
1021
  loadPretext().then((mod) => {
@@ -712,8 +1025,8 @@ function usePretextMeasurement({
712
1025
  cancelled = true;
713
1026
  };
714
1027
  }, [enabled]);
715
- const preparedCacheRef = React3.useRef(/* @__PURE__ */ new Map());
716
- const preparedCells = React3.useMemo(() => {
1028
+ const preparedCacheRef = React4.useRef(/* @__PURE__ */ new Map());
1029
+ const preparedCells = React4.useMemo(() => {
717
1030
  if (!pretext || !enabled || data.length === 0 || columns.length === 0) return null;
718
1031
  const cache = preparedCacheRef.current;
719
1032
  const start = performance.now();
@@ -740,7 +1053,7 @@ function usePretextMeasurement({
740
1053
  data,
741
1054
  columns.map((c) => `${c.columnId}:${c.font}:${c.fixedHeight ? "F" : "T"}`).join("|")
742
1055
  ]);
743
- const measurement = React3.useMemo(() => {
1056
+ const measurement = React4.useMemo(() => {
744
1057
  if (!pretext || !preparedCells) {
745
1058
  return { rowHeights: null, prefixSums: null, totalHeight: 0 };
746
1059
  }
@@ -781,7 +1094,7 @@ function usePretextMeasurement({
781
1094
  totalHeight: prefixSums[data.length]
782
1095
  };
783
1096
  }, [pretext, preparedCells, columnWidthsKey, minRowHeight, data.length]);
784
- React3.useEffect(() => {
1097
+ React4.useEffect(() => {
785
1098
  if (measurement.rowHeights) setReady(true);
786
1099
  }, [measurement.rowHeights]);
787
1100
  return {
@@ -830,7 +1143,7 @@ function CellCurrency({
830
1143
  }) {
831
1144
  const raw = context.getValue();
832
1145
  const num = typeof raw === "number" ? raw : Number(raw);
833
- const formatter = React3.useMemo(
1146
+ const formatter = React4.useMemo(
834
1147
  () => new Intl.NumberFormat(locale, {
835
1148
  style: "currency",
836
1149
  currency,
@@ -907,7 +1220,7 @@ function CellNumeric({
907
1220
  }) {
908
1221
  const raw = context.getValue();
909
1222
  const num = typeof raw === "number" ? raw : Number(raw);
910
- const formatter = React3.useMemo(
1223
+ const formatter = React4.useMemo(
911
1224
  () => new Intl.NumberFormat(locale, {
912
1225
  minimumFractionDigits: decimals,
913
1226
  maximumFractionDigits: decimals
@@ -1130,12 +1443,12 @@ function getRegisteredCellTypes() {
1130
1443
 
1131
1444
  // src/hooks/useAutoMeasurements.ts
1132
1445
  var NON_DATA_COLUMN_IDS = /* @__PURE__ */ new Set(["select", "expand", "drag", "actions"]);
1133
- function getColumnId(col) {
1446
+ function getColumnId2(col) {
1134
1447
  const id = col.id ?? col.accessorKey;
1135
1448
  return typeof id === "string" ? id : void 0;
1136
1449
  }
1137
1450
  function defaultShouldMeasure(col) {
1138
- const id = getColumnId(col);
1451
+ const id = getColumnId2(col);
1139
1452
  if (!id) return false;
1140
1453
  if (id.startsWith("_")) return false;
1141
1454
  if (NON_DATA_COLUMN_IDS.has(id)) return false;
@@ -1160,11 +1473,11 @@ function useAutoMeasurements({
1160
1473
  getColumnWidth = defaultGetColumnWidth,
1161
1474
  shouldMeasureColumn = defaultShouldMeasure
1162
1475
  }) {
1163
- const widthKey = columns.map((c) => `${getColumnId(c) ?? "?"}:${getColumnWidth(c)}`).join("|");
1164
- return React3.useMemo(() => {
1476
+ const widthKey = columns.map((c) => `${getColumnId2(c) ?? "?"}:${getColumnWidth(c)}`).join("|");
1477
+ return React4.useMemo(() => {
1165
1478
  const result = [];
1166
1479
  for (const col of columns) {
1167
- const id = getColumnId(col);
1480
+ const id = getColumnId2(col);
1168
1481
  if (!id) continue;
1169
1482
  if (!shouldMeasureColumn(col)) continue;
1170
1483
  const recipe = resolveMeasureRecipe(col, defaultRecipe);
@@ -1198,7 +1511,7 @@ function useTableRowHeights({
1198
1511
  defaultRecipe,
1199
1512
  getColumnWidth
1200
1513
  });
1201
- const accessorMap = React3.useMemo(() => {
1514
+ const accessorMap = React4.useMemo(() => {
1202
1515
  const map = /* @__PURE__ */ new Map();
1203
1516
  for (const col of columns) {
1204
1517
  const id = col.id ?? col.accessorKey;
@@ -1215,7 +1528,7 @@ function useTableRowHeights({
1215
1528
  }
1216
1529
  return map;
1217
1530
  }, [columns]);
1218
- const getCellText = React3.useMemo(
1531
+ const getCellText = React4.useMemo(
1219
1532
  () => (row, columnId) => {
1220
1533
  const get = accessorMap.get(columnId);
1221
1534
  if (!get) return "";
@@ -1234,10 +1547,10 @@ function useTableRowHeights({
1234
1547
  });
1235
1548
  return { ...result, measurements };
1236
1549
  }
1237
- var TableContext = React3.createContext(null);
1550
+ var TableContext = React4.createContext(null);
1238
1551
  var TableProvider = TableContext.Provider;
1239
1552
  function useTableContext() {
1240
- const ctx = React3.useContext(TableContext);
1553
+ const ctx = React4.useContext(TableContext);
1241
1554
  if (!ctx) {
1242
1555
  throw new Error(
1243
1556
  "[yable E001] useTableContext must be used within a <Table> component. Did you forget to pass the `table` prop?"
@@ -1298,7 +1611,7 @@ function formatValue(value) {
1298
1611
  return JSON.stringify(value);
1299
1612
  }
1300
1613
  function SetFilter({ column, className }) {
1301
- const [open, setOpen] = React3.useState(false);
1614
+ const [open, setOpen] = React4.useState(false);
1302
1615
  const filterValue = column.getFilterValue();
1303
1616
  const selectedValues = Array.isArray(filterValue) ? filterValue : filterValue == null || filterValue === "" ? [] : [filterValue];
1304
1617
  const facetedUniqueValues = column.getFacetedUniqueValues();
@@ -1483,22 +1796,176 @@ function FloatingFilter({ column }) {
1483
1796
  }
1484
1797
  ) });
1485
1798
  }
1486
- var DRAG_MIME = "application/yable-column";
1799
+ var REORDER_TRANSITION = "transform 180ms cubic-bezier(0.2, 0, 0, 1)";
1800
+ function transformAt(i, d) {
1801
+ if (i === d.fromIndex) return 0;
1802
+ if (d.toIndex > d.fromIndex) return i > d.fromIndex && i < d.toIndex ? -d.width : 0;
1803
+ return i >= d.toIndex && i < d.fromIndex ? d.width : 0;
1804
+ }
1487
1805
  function TableHeader({
1488
1806
  table,
1489
1807
  floatingFilters = false
1490
1808
  }) {
1491
1809
  const headerGroups = table.getHeaderGroups();
1492
1810
  const visibleColumns = table.getVisibleLeafColumns();
1493
- return /* @__PURE__ */ jsxRuntime.jsxs("thead", { className: "yable-thead", children: [
1494
- headerGroups.map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsxRuntime.jsx(HeaderCell, { header, table }, header.id)) }, headerGroup.id)),
1495
- floatingFilters && visibleColumns.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row yable-header-row--filters", children: visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(FloatingFilterCell, { column }, `${column.id}-filter`)) })
1811
+ const theadRef = React4.useRef(null);
1812
+ const reorderEndRef = React4.useRef(0);
1813
+ const [drag, setDrag] = React4.useState(null);
1814
+ const commitReorder = React4.useCallback(
1815
+ (d) => {
1816
+ if (d.toIndex === d.fromIndex || d.toIndex === d.fromIndex + 1) return;
1817
+ const order = table.getState().columnOrder;
1818
+ const base = order && order.length > 0 ? [...order] : d.layout.map((l) => l.id);
1819
+ const targetId = d.toIndex < d.layout.length ? d.layout[d.toIndex].id : null;
1820
+ const next = base.filter((id) => id !== d.columnId);
1821
+ let insertAt = targetId ? next.indexOf(targetId) : next.length;
1822
+ if (insertAt === -1) insertAt = next.length;
1823
+ next.splice(insertAt, 0, d.columnId);
1824
+ table.setColumnOrder(next);
1825
+ },
1826
+ [table]
1827
+ );
1828
+ const beginReorder = React4.useCallback(
1829
+ (e, columnId) => {
1830
+ if (e.button !== 0) return;
1831
+ const thead = theadRef.current;
1832
+ if (!thead) return;
1833
+ const startX = e.clientX;
1834
+ const startY = e.clientY;
1835
+ const layout = [];
1836
+ let top = 0;
1837
+ let height = 0;
1838
+ for (const c of visibleColumns) {
1839
+ const th = thead.querySelector(`th[data-column-id="${CSS.escape(c.id)}"]`);
1840
+ if (!th) return;
1841
+ const r = th.getBoundingClientRect();
1842
+ layout.push({ id: c.id, left: r.left, width: r.width });
1843
+ if (c.id === columnId) {
1844
+ top = r.top;
1845
+ height = r.height;
1846
+ }
1847
+ }
1848
+ const fromIndex = layout.findIndex((l) => l.id === columnId);
1849
+ if (fromIndex < 0) return;
1850
+ const src = layout[fromIndex];
1851
+ const bodyRoot = thead.closest("table");
1852
+ const applyBody = (d) => {
1853
+ if (!bodyRoot) return;
1854
+ visibleColumns.forEach((col, i) => {
1855
+ if (col.getIsPinned()) return;
1856
+ const tx = transformAt(i, d);
1857
+ bodyRoot.querySelectorAll(`td[data-column-id="${CSS.escape(col.id)}"]`).forEach((td) => {
1858
+ td.style.transition = REORDER_TRANSITION;
1859
+ td.style.opacity = i === d.fromIndex ? "0" : "";
1860
+ td.style.transform = i !== d.fromIndex && tx ? `translateX(${tx}px)` : "";
1861
+ });
1862
+ });
1863
+ };
1864
+ const clearBody = () => {
1865
+ bodyRoot?.querySelectorAll("td[data-column-id]").forEach((td) => {
1866
+ td.style.transform = "";
1867
+ td.style.transition = "";
1868
+ td.style.opacity = "";
1869
+ });
1870
+ };
1871
+ let started = false;
1872
+ let latest = {
1873
+ columnId,
1874
+ fromIndex,
1875
+ toIndex: fromIndex,
1876
+ pointerX: startX,
1877
+ grabOffsetX: startX - src.left,
1878
+ width: src.width,
1879
+ top,
1880
+ height,
1881
+ layout
1882
+ };
1883
+ const computeToIndex = (x) => {
1884
+ let t = layout.findIndex((l) => x < l.left + l.width / 2);
1885
+ if (t === -1) t = layout.length;
1886
+ return t;
1887
+ };
1888
+ const onMove = (ev) => {
1889
+ if (!started) {
1890
+ if (Math.abs(ev.clientX - startX) < 4 && Math.abs(ev.clientY - startY) < 4) return;
1891
+ started = true;
1892
+ table.setColumnDragActive(true);
1893
+ document.body.style.userSelect = "none";
1894
+ document.body.style.cursor = "grabbing";
1895
+ }
1896
+ latest = { ...latest, pointerX: ev.clientX, toIndex: computeToIndex(ev.clientX) };
1897
+ setDrag(latest);
1898
+ applyBody(latest);
1899
+ };
1900
+ const finish = () => {
1901
+ window.removeEventListener("pointermove", onMove);
1902
+ window.removeEventListener("pointerup", finish);
1903
+ window.removeEventListener("pointercancel", finish);
1904
+ if (started) {
1905
+ commitReorder(latest);
1906
+ reorderEndRef.current = Date.now();
1907
+ table.setColumnDragActive(false);
1908
+ document.body.style.userSelect = "";
1909
+ document.body.style.cursor = "";
1910
+ clearBody();
1911
+ }
1912
+ setDrag(null);
1913
+ };
1914
+ window.addEventListener("pointermove", onMove);
1915
+ window.addEventListener("pointerup", finish);
1916
+ window.addEventListener("pointercancel", finish);
1917
+ },
1918
+ [visibleColumns, table, commitReorder]
1919
+ );
1920
+ const transformFor = React4.useCallback(
1921
+ (columnId) => {
1922
+ if (!drag) return 0;
1923
+ const i = visibleColumns.findIndex((c) => c.id === columnId);
1924
+ if (i < 0) return 0;
1925
+ return transformAt(i, drag);
1926
+ },
1927
+ [drag, visibleColumns]
1928
+ );
1929
+ const dragColumn = drag ? visibleColumns.find((c) => c.id === drag.columnId) : null;
1930
+ return /* @__PURE__ */ jsxRuntime.jsxs("thead", { className: "yable-thead", ref: theadRef, children: [
1931
+ headerGroups.map((headerGroup) => /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row", children: headerGroup.headers.map((header) => /* @__PURE__ */ jsxRuntime.jsx(
1932
+ HeaderCell,
1933
+ {
1934
+ header,
1935
+ table,
1936
+ onReorderPointerDown: beginReorder,
1937
+ dragTransform: transformFor(header.column.id),
1938
+ isDragSource: drag?.columnId === header.column.id,
1939
+ dragActive: drag !== null,
1940
+ reorderEndRef
1941
+ },
1942
+ header.id
1943
+ )) }, headerGroup.id)),
1944
+ floatingFilters && visibleColumns.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-header-row yable-header-row--filters", children: visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx(FloatingFilterCell, { column }, `${column.id}-filter`)) }),
1945
+ drag && dragColumn && typeof document !== "undefined" && reactDom.createPortal(
1946
+ /* @__PURE__ */ jsxRuntime.jsx(
1947
+ "div",
1948
+ {
1949
+ className: "yable-col-drag-ghost",
1950
+ "aria-hidden": "true",
1951
+ style: {
1952
+ position: "fixed",
1953
+ top: drag.top,
1954
+ left: drag.pointerX - drag.grabOffsetX,
1955
+ width: drag.width,
1956
+ height: drag.height
1957
+ },
1958
+ children: typeof dragColumn.columnDef.header === "string" ? dragColumn.columnDef.header : dragColumn.id
1959
+ }
1960
+ ),
1961
+ document.body
1962
+ )
1496
1963
  ] });
1497
1964
  }
1498
1965
  function FloatingFilterCell({
1499
1966
  column
1500
1967
  }) {
1501
- const style = React3.useMemo(() => {
1968
+ const style = React4.useMemo(() => {
1502
1969
  const next = {
1503
1970
  width: column.getSize(),
1504
1971
  minWidth: column.columnDef.minSize,
@@ -1521,7 +1988,12 @@ function FloatingFilterCell({
1521
1988
  }
1522
1989
  function HeaderCell({
1523
1990
  header,
1524
- table
1991
+ table,
1992
+ onReorderPointerDown,
1993
+ dragTransform,
1994
+ isDragSource,
1995
+ dragActive,
1996
+ reorderEndRef
1525
1997
  }) {
1526
1998
  const column = header.column;
1527
1999
  const canSort = column.getCanSort();
@@ -1529,27 +2001,29 @@ function HeaderCell({
1529
2001
  const sortIndex = column.getSortIndex();
1530
2002
  const canResize = column.getCanResize();
1531
2003
  const canReorder = column.getCanReorder() && !header.isPlaceholder;
2004
+ const pinned = column.getIsPinned();
1532
2005
  const headerContent = header.isPlaceholder ? null : typeof column.columnDef.header === "function" ? column.columnDef.header(header.getContext()) : column.columnDef.header ?? header.id;
1533
- const style = React3.useMemo(() => {
2006
+ const style = React4.useMemo(() => {
1534
2007
  const s = {
1535
2008
  width: header.getSize(),
1536
2009
  minWidth: column.columnDef.minSize,
1537
2010
  maxWidth: column.columnDef.maxSize
1538
2011
  };
1539
- const pinned2 = column.getIsPinned();
1540
- if (pinned2) {
2012
+ if (pinned) {
1541
2013
  s.position = "sticky";
1542
- if (pinned2 === "left") {
2014
+ if (pinned === "left") {
1543
2015
  s.left = header.getStart("left");
1544
2016
  } else {
1545
2017
  s.right = header.getStart("right");
1546
2018
  }
1547
2019
  }
2020
+ if (!pinned && !isDragSource && dragTransform !== 0) {
2021
+ s.transform = `translateX(${dragTransform}px)`;
2022
+ }
1548
2023
  return s;
1549
- }, [header, column]);
1550
- const pinned = column.getIsPinned();
1551
- const lastResizeEndRef = React3.useRef(0);
1552
- const startResize = React3.useCallback(
2024
+ }, [header, column, pinned, isDragSource, dragTransform]);
2025
+ const lastResizeEndRef = React4.useRef(0);
2026
+ const startResize = React4.useCallback(
1553
2027
  (e) => {
1554
2028
  e.stopPropagation();
1555
2029
  const onEnd = () => {
@@ -1564,125 +2038,63 @@ function HeaderCell({
1564
2038
  },
1565
2039
  [header]
1566
2040
  );
1567
- const handleResizeClick = React3.useCallback((e) => {
2041
+ const handleResizeClick = React4.useCallback((e) => {
1568
2042
  e.stopPropagation();
1569
2043
  }, []);
1570
- const [dragOver, setDragOver] = React3.useState(null);
1571
- const handleDragStart = React3.useCallback(
1572
- (e) => {
1573
- if (!canReorder) return;
1574
- e.stopPropagation();
1575
- e.dataTransfer.effectAllowed = "move";
1576
- try {
1577
- e.dataTransfer.setData(DRAG_MIME, column.id);
1578
- e.dataTransfer.setData("text/plain", column.id);
1579
- } catch {
1580
- }
1581
- table.setColumnDragActive(true);
1582
- },
1583
- [canReorder, column.id, table]
1584
- );
1585
- const handleDragOver = React3.useCallback(
2044
+ const handleContentPointerDown = React4.useCallback(
1586
2045
  (e) => {
1587
- if (!canReorder) return;
1588
- const types = e.dataTransfer.types;
1589
- let isYableDrag = false;
1590
- for (let i = 0; i < types.length; i++) {
1591
- if (types[i] === DRAG_MIME) {
1592
- isYableDrag = true;
1593
- break;
1594
- }
1595
- }
1596
- if (!isYableDrag) return;
1597
- e.preventDefault();
1598
- e.dataTransfer.dropEffect = "move";
1599
- const rect = e.currentTarget.getBoundingClientRect();
1600
- const midpoint = rect.left + rect.width / 2;
1601
- setDragOver(e.clientX < midpoint ? "left" : "right");
2046
+ if (!canReorder || pinned) return;
2047
+ onReorderPointerDown(e, column.id);
1602
2048
  },
1603
- [canReorder]
2049
+ [canReorder, pinned, onReorderPointerDown, column.id]
1604
2050
  );
1605
- const handleDragLeave = React3.useCallback((e) => {
1606
- const next = e.relatedTarget;
1607
- if (next && e.currentTarget.contains(next)) return;
1608
- setDragOver(null);
1609
- }, []);
1610
- const handleDragEnd = React3.useCallback(() => {
1611
- setDragOver(null);
1612
- table.setColumnDragActive(false);
1613
- }, [table]);
1614
- const handleDrop = React3.useCallback(
1615
- (e) => {
1616
- if (!canReorder) return;
1617
- e.preventDefault();
1618
- e.stopPropagation();
1619
- const sourceId = e.dataTransfer.getData(DRAG_MIME);
1620
- const rect = e.currentTarget.getBoundingClientRect();
1621
- const insertAfter = e.clientX >= rect.left + rect.width / 2;
1622
- setDragOver(null);
1623
- table.setColumnDragActive(false);
1624
- if (!sourceId || sourceId === column.id) return;
1625
- const state = table.getState();
1626
- const allLeafs = table.getAllLeafColumns();
1627
- const baseOrder = state.columnOrder && state.columnOrder.length > 0 ? state.columnOrder : allLeafs.map((c) => c.id);
1628
- const next = [];
1629
- const seen = /* @__PURE__ */ new Set();
1630
- for (const id of baseOrder) {
1631
- if (allLeafs.some((c) => c.id === id)) {
1632
- next.push(id);
1633
- seen.add(id);
1634
- }
1635
- }
1636
- for (const c of allLeafs) {
1637
- if (!seen.has(c.id)) {
1638
- next.push(c.id);
1639
- seen.add(c.id);
1640
- }
1641
- }
1642
- const fromIdx = next.indexOf(sourceId);
1643
- if (fromIdx === -1) return;
1644
- next.splice(fromIdx, 1);
1645
- let toIdx = next.indexOf(column.id);
1646
- if (toIdx === -1) return;
1647
- if (insertAfter) toIdx += 1;
1648
- next.splice(toIdx, 0, sourceId);
1649
- table.setColumnOrder(next);
1650
- },
1651
- [canReorder, column.id, table]
1652
- );
1653
- const handleHeaderClick = React3.useCallback(
2051
+ const handleHeaderClick = React4.useCallback(
1654
2052
  (e) => {
2053
+ table.events.emit("header:click", {
2054
+ column,
2055
+ header,
2056
+ originalEvent: e
2057
+ });
1655
2058
  if (!canSort) return;
1656
2059
  if (Date.now() - lastResizeEndRef.current < 250) return;
2060
+ if (Date.now() - reorderEndRef.current < 250) return;
1657
2061
  const handler = column.getToggleSortingHandler();
1658
2062
  if (handler) handler(e);
1659
2063
  },
1660
- [canSort, column]
2064
+ [canSort, column, header, table.events, reorderEndRef]
2065
+ );
2066
+ const handleHeaderContextMenu = React4.useCallback(
2067
+ (e) => {
2068
+ table.events.emit("header:contextmenu", {
2069
+ column,
2070
+ header,
2071
+ originalEvent: e
2072
+ });
2073
+ },
2074
+ [column, header, table.events]
1661
2075
  );
1662
2076
  return /* @__PURE__ */ jsxRuntime.jsxs(
1663
2077
  "th",
1664
2078
  {
1665
2079
  className: "yable-th",
1666
2080
  style,
2081
+ "data-column-id": column.id,
1667
2082
  "data-sortable": canSort || void 0,
1668
2083
  "data-pinned": pinned || void 0,
1669
- "data-reorderable": canReorder || void 0,
1670
- "data-drag-over": dragOver || void 0,
2084
+ "data-reorderable": canReorder && !pinned || void 0,
2085
+ "data-reordering": dragActive && !pinned || void 0,
2086
+ "data-drag-source": isDragSource || void 0,
1671
2087
  "aria-sort": sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : canSort ? "none" : void 0,
1672
2088
  role: "columnheader",
1673
2089
  colSpan: header.colSpan,
1674
2090
  onClick: handleHeaderClick,
1675
- onDragOver: canReorder ? handleDragOver : void 0,
1676
- onDragLeave: canReorder ? handleDragLeave : void 0,
1677
- onDrop: canReorder ? handleDrop : void 0,
2091
+ onContextMenu: handleHeaderContextMenu,
1678
2092
  children: [
1679
2093
  /* @__PURE__ */ jsxRuntime.jsxs(
1680
2094
  "div",
1681
2095
  {
1682
2096
  className: "yable-th-content",
1683
- draggable: canReorder || void 0,
1684
- onDragStart: canReorder ? handleDragStart : void 0,
1685
- onDragEnd: canReorder ? handleDragEnd : void 0,
2097
+ onPointerDown: canReorder && !pinned ? handleContentPointerDown : void 0,
1686
2098
  children: [
1687
2099
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: headerContent }),
1688
2100
  canSort && /* @__PURE__ */ jsxRuntime.jsx(SortIndicator, { direction: sortDirection, index: sortIndex > 0 ? sortIndex : void 0 })
@@ -1781,19 +2193,46 @@ function CellStatusBadge(props) {
1781
2193
  }
1782
2194
  );
1783
2195
  }
2196
+ function FillHandle({
2197
+ rowIndex,
2198
+ columnIndex,
2199
+ onMouseDown
2200
+ }) {
2201
+ const handleMouseDown = React4.useCallback(
2202
+ (e) => {
2203
+ e.preventDefault();
2204
+ e.stopPropagation();
2205
+ onMouseDown(rowIndex, columnIndex, e);
2206
+ },
2207
+ [rowIndex, columnIndex, onMouseDown]
2208
+ );
2209
+ return /* @__PURE__ */ jsxRuntime.jsx(
2210
+ "div",
2211
+ {
2212
+ className: "yable-fill-handle",
2213
+ onMouseDown: handleMouseDown,
2214
+ role: "presentation",
2215
+ "aria-hidden": "true",
2216
+ title: "Drag to fill",
2217
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-fill-handle-dot" })
2218
+ }
2219
+ );
2220
+ }
1784
2221
  function TableCell({
1785
2222
  cell,
1786
2223
  table,
1787
2224
  rowIndex,
1788
2225
  columnIndex,
1789
2226
  isFocused,
1790
- isTabStop
2227
+ isTabStop,
2228
+ onFillHandleMouseDown
1791
2229
  }) {
1792
2230
  const column = cell.column;
1793
2231
  const isEditing = cell.getIsEditing();
1794
2232
  const isAlwaysEditable = cell.getIsAlwaysEditable();
1795
2233
  const pinned = column.getIsPinned();
1796
2234
  const keyboardNavigationEnabled = table.options.enableKeyboardNavigation !== false;
2235
+ const cellSelectionEnabled = table.options.enableCellSelection !== false && column.columnDef.enableCellSelection !== false;
1797
2236
  const style = {
1798
2237
  width: column.getSize(),
1799
2238
  minWidth: column.columnDef.minSize,
@@ -1835,7 +2274,7 @@ function TableCell({
1835
2274
  } else {
1836
2275
  content = overrideValue !== void 0 ? overrideValue : cell.renderValue();
1837
2276
  }
1838
- const handleClick = React3.useCallback(
2277
+ const handleClick = React4.useCallback(
1839
2278
  (e) => {
1840
2279
  table.events.emit("cell:click", {
1841
2280
  cell,
@@ -1849,7 +2288,7 @@ function TableCell({
1849
2288
  },
1850
2289
  [cell, column, isAlwaysEditable, isEditing, isMultiCellSelection, table]
1851
2290
  );
1852
- const handleDoubleClick = React3.useCallback(
2291
+ const handleDoubleClick = React4.useCallback(
1853
2292
  (e) => {
1854
2293
  table.events.emit("cell:dblclick", {
1855
2294
  cell,
@@ -1860,7 +2299,7 @@ function TableCell({
1860
2299
  },
1861
2300
  [table, cell]
1862
2301
  );
1863
- const handleContextMenu = React3.useCallback(
2302
+ const handleContextMenu = React4.useCallback(
1864
2303
  (e) => {
1865
2304
  table.events.emit("cell:contextmenu", {
1866
2305
  cell,
@@ -1871,13 +2310,14 @@ function TableCell({
1871
2310
  },
1872
2311
  [table, cell]
1873
2312
  );
1874
- const handleFocus = React3.useCallback(() => {
2313
+ const handleFocus = React4.useCallback(() => {
1875
2314
  if (!keyboardNavigationEnabled) return;
1876
2315
  table.setFocusedCell({ rowIndex, columnIndex });
1877
2316
  }, [columnIndex, keyboardNavigationEnabled, rowIndex, table]);
1878
- const handleMouseDown = React3.useCallback(
2317
+ const handleMouseDown = React4.useCallback(
1879
2318
  (e) => {
1880
2319
  if (e.button !== 0) return;
2320
+ if (!cellSelectionEnabled) return;
1881
2321
  const clickTarget = e.target;
1882
2322
  if (isInteractiveClickTarget(clickTarget)) return;
1883
2323
  e.preventDefault();
@@ -1885,13 +2325,14 @@ function TableCell({
1885
2325
  table.startCellRangeSelection({ rowIndex, columnIndex }, { extend: e.shiftKey });
1886
2326
  e.currentTarget.focus({ preventScroll: true });
1887
2327
  },
1888
- [columnIndex, rowIndex, table]
2328
+ [cellSelectionEnabled, columnIndex, rowIndex, table]
1889
2329
  );
1890
- const handleMouseEnter = React3.useCallback(() => {
2330
+ const handleMouseEnter = React4.useCallback(() => {
2331
+ if (!cellSelectionEnabled) return;
1891
2332
  if (!table.getState().cellSelection?.isDragging) return;
1892
2333
  table.updateCellRangeSelection({ rowIndex, columnIndex });
1893
- }, [columnIndex, rowIndex, table]);
1894
- const handleMouseUp = React3.useCallback(() => {
2334
+ }, [cellSelectionEnabled, columnIndex, rowIndex, table]);
2335
+ const handleMouseUp = React4.useCallback(() => {
1895
2336
  if (!table.getState().cellSelection?.isDragging) return;
1896
2337
  table.endCellRangeSelection();
1897
2338
  }, [table]);
@@ -1900,6 +2341,7 @@ function TableCell({
1900
2341
  const cellStyleDef = column.columnDef.cellStyle;
1901
2342
  const userStyle = typeof cellStyleDef === "function" ? cellStyleDef(cell.getContext()) : cellStyleDef;
1902
2343
  const mergedStyle = userStyle ? { ...style, ...userStyle } : style;
2344
+ const showFillHandle = isFocused && Boolean(table.options.enableFillHandle) && onFillHandleMouseDown != null;
1903
2345
  const classNames = [
1904
2346
  "yable-td",
1905
2347
  isFocused && "yable-cell--focused",
@@ -1953,6 +2395,14 @@ function TableCell({
1953
2395
  onRetry: () => void table.retryCommit(cell.row.id, column.id),
1954
2396
  onDismiss: () => table.dismissCommit(cell.row.id, column.id)
1955
2397
  }
2398
+ ),
2399
+ showFillHandle && onFillHandleMouseDown && /* @__PURE__ */ jsxRuntime.jsx(
2400
+ FillHandle,
2401
+ {
2402
+ rowIndex,
2403
+ columnIndex,
2404
+ onMouseDown: onFillHandleMouseDown
2405
+ }
1956
2406
  )
1957
2407
  ]
1958
2408
  }
@@ -1965,7 +2415,7 @@ function isInteractiveClickTarget(element) {
1965
2415
  );
1966
2416
  return interactive !== null;
1967
2417
  }
1968
- var ErrorBoundary = class extends React3__default.default.Component {
2418
+ var ErrorBoundary = class extends React4__default.default.Component {
1969
2419
  constructor(props) {
1970
2420
  super(props);
1971
2421
  this.state = { hasError: false, error: null };
@@ -2011,7 +2461,7 @@ var ErrorBoundary = class extends React3__default.default.Component {
2011
2461
  return this.props.children;
2012
2462
  }
2013
2463
  };
2014
- var CellErrorBoundary = class extends React3__default.default.Component {
2464
+ var CellErrorBoundary = class extends React4__default.default.Component {
2015
2465
  constructor(props) {
2016
2466
  super(props);
2017
2467
  this.state = { hasError: false, error: null };
@@ -2054,10 +2504,38 @@ var CellErrorBoundary = class extends React3__default.default.Component {
2054
2504
  return this.props.children;
2055
2505
  }
2056
2506
  };
2507
+ function MasterDetail({
2508
+ row,
2509
+ table,
2510
+ colSpan,
2511
+ renderDetailPanel,
2512
+ animationClass
2513
+ }) {
2514
+ const renderer = renderDetailPanel ?? table.options.renderDetailPanel;
2515
+ if (!renderer) return null;
2516
+ const content = renderer(row);
2517
+ if (content == null) return null;
2518
+ const classes = [
2519
+ "yable-detail-row",
2520
+ "yable-detail-row--animated",
2521
+ animationClass
2522
+ ].filter(Boolean).join(" ");
2523
+ return /* @__PURE__ */ jsxRuntime.jsx(
2524
+ "tr",
2525
+ {
2526
+ className: classes,
2527
+ "data-detail-for": row.id,
2528
+ role: "row",
2529
+ "aria-label": `Details for row ${row.id}`,
2530
+ children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "yable-detail-cell", colSpan, role: "cell", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-detail-panel", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-detail-panel-inner", children: content }) }) })
2531
+ }
2532
+ );
2533
+ }
2057
2534
  function TableBody({
2058
2535
  table,
2059
2536
  clickableRows,
2060
- colgroup
2537
+ colgroup,
2538
+ onFillHandleMouseDown
2061
2539
  }) {
2062
2540
  const rows = table.getRowModel().rows;
2063
2541
  const visibleColumns = table.getVisibleLeafColumns();
@@ -2067,16 +2545,17 @@ function TableBody({
2067
2545
  range: null,
2068
2546
  isDragging: false
2069
2547
  };
2548
+ const pendingValues = table.getState().editing.pendingValues ?? {};
2070
2549
  const options = table.options;
2071
2550
  const enableVirtualization = options.enableVirtualization ?? false;
2072
- const scrollContainerRef = React3.useRef(null);
2551
+ const scrollContainerRef = React4.useRef(null);
2073
2552
  const rowHeight = options.rowHeight ?? 40;
2074
2553
  const overscan = options.overscan ?? 5;
2075
2554
  const estimateRowHeight = options.estimateRowHeight;
2076
2555
  const pretextHeights = options.pretextHeights ?? null;
2077
2556
  const pretextPrefixSums = options.pretextPrefixSums ?? null;
2078
2557
  const columnSizing = table.getState().columnSizing;
2079
- const columnSizingHash = React3.useMemo(() => {
2558
+ const columnSizingHash = React4.useMemo(() => {
2080
2559
  const entries = Object.entries(columnSizing);
2081
2560
  if (entries.length === 0) return 0;
2082
2561
  let h = 0;
@@ -2099,7 +2578,7 @@ function TableBody({
2099
2578
  columnSizingHash
2100
2579
  });
2101
2580
  const cellSelectionKey = cellSelection.range ? `${cellSelection.range.start.rowIndex}:${cellSelection.range.start.columnIndex}:${cellSelection.range.end.rowIndex}:${cellSelection.range.end.columnIndex}:${cellSelection.isDragging ? "dragging" : "idle"}` : `none:${cellSelection.isDragging ? "dragging" : "idle"}`;
2102
- React3.useEffect(() => {
2581
+ React4.useEffect(() => {
2103
2582
  const handleWindowMouseUp = () => {
2104
2583
  if (table.getState().cellSelection?.isDragging) {
2105
2584
  table.endCellRangeSelection();
@@ -2110,24 +2589,41 @@ function TableBody({
2110
2589
  window.removeEventListener("mouseup", handleWindowMouseUp);
2111
2590
  };
2112
2591
  }, [table]);
2592
+ const renderRow = (row, rowIndex, pinnedPosition) => /* @__PURE__ */ jsxRuntime.jsx(
2593
+ MemoizedTableRow,
2594
+ {
2595
+ row,
2596
+ table,
2597
+ rowIndex,
2598
+ visibleColumns,
2599
+ isSelected: row.getIsSelected(),
2600
+ isExpanded: row.getIsExpanded(),
2601
+ activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
2602
+ focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
2603
+ hasFocusedCell: focusedCell !== null,
2604
+ cellSelectionKey,
2605
+ pendingValuesKey: getPendingValuesKey(pendingValues[row.id]),
2606
+ clickable: clickableRows,
2607
+ pinnedPosition,
2608
+ onFillHandleMouseDown
2609
+ },
2610
+ row.id
2611
+ );
2113
2612
  if (!enableVirtualization) {
2114
- return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2115
- MemoizedTableRow,
2116
- {
2117
- row,
2118
- table,
2119
- rowIndex,
2120
- visibleColumns,
2121
- isSelected: row.getIsSelected(),
2122
- isExpanded: row.getIsExpanded(),
2123
- activeColumnId: activeCell?.rowId === row.id ? activeCell.columnId : void 0,
2124
- focusedColumnIndex: focusedCell?.rowIndex === rowIndex ? focusedCell.columnIndex : null,
2125
- hasFocusedCell: focusedCell !== null,
2126
- cellSelectionKey,
2127
- clickable: clickableRows
2128
- },
2129
- row.id
2130
- )) });
2613
+ const rowPinning = table.getState().rowPinning;
2614
+ const hasPinnedRows = (rowPinning.top?.length ?? 0) > 0 || (rowPinning.bottom?.length ?? 0) > 0;
2615
+ if (hasPinnedRows) {
2616
+ const topRows = table.getTopRows();
2617
+ const centerRows = table.getCenterRows();
2618
+ const bottomRows = table.getBottomRows();
2619
+ let visualIndex = 0;
2620
+ return /* @__PURE__ */ jsxRuntime.jsxs("tbody", { className: "yable-tbody", children: [
2621
+ topRows.map((row) => renderRow(row, visualIndex++, "top")),
2622
+ centerRows.map((row) => renderRow(row, visualIndex++)),
2623
+ bottomRows.map((row) => renderRow(row, visualIndex++, "bottom"))
2624
+ ] });
2625
+ }
2626
+ return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "yable-tbody", children: rows.map((row, rowIndex) => renderRow(row, rowIndex)) });
2131
2627
  }
2132
2628
  const hasPretextData = !!(pretextHeights && pretextPrefixSums);
2133
2629
  const fixedRowHeight = typeof rowHeight === "number" && !hasPretextData ? rowHeight : void 0;
@@ -2176,7 +2672,9 @@ function TableBody({
2176
2672
  focusedColumnIndex: focusedCell?.rowIndex === vRow.index ? focusedCell.columnIndex : null,
2177
2673
  hasFocusedCell: focusedCell !== null,
2178
2674
  cellSelectionKey,
2675
+ pendingValuesKey: getPendingValuesKey(pendingValues[row.id]),
2179
2676
  clickable: clickableRows,
2677
+ onFillHandleMouseDown,
2180
2678
  virtualStyle: {
2181
2679
  position: "absolute",
2182
2680
  top: 0,
@@ -2208,13 +2706,19 @@ function TableRowInner({
2208
2706
  focusedColumnIndex,
2209
2707
  hasFocusedCell,
2210
2708
  cellSelectionKey: _cellSelectionKey,
2709
+ pendingValuesKey: _pendingValuesKey,
2211
2710
  clickable,
2212
- virtualStyle
2711
+ pinnedPosition,
2712
+ virtualStyle,
2713
+ onFillHandleMouseDown
2213
2714
  }) {
2214
2715
  const allCells = row.getAllCells();
2215
2716
  const visibleCells = visibleColumns.map((column) => allCells.find((cell) => cell.column.id === column.id)).filter((cell) => cell != null);
2216
- const handleClick = React3.useCallback(
2717
+ const handleClick = React4.useCallback(
2217
2718
  (e) => {
2719
+ if (table.options.enableRowClickSelection && row.getCanSelect() && !isInteractiveClickTarget2(e.target)) {
2720
+ row.toggleSelected();
2721
+ }
2218
2722
  if (clickable) {
2219
2723
  table.events.emit("row:click", {
2220
2724
  row,
@@ -2222,9 +2726,9 @@ function TableRowInner({
2222
2726
  });
2223
2727
  }
2224
2728
  },
2225
- [clickable, table.events, row]
2729
+ [clickable, table, row]
2226
2730
  );
2227
- const handleDoubleClick = React3.useCallback(
2731
+ const handleDoubleClick = React4.useCallback(
2228
2732
  (e) => {
2229
2733
  table.events.emit("row:dblclick", {
2230
2734
  row,
@@ -2233,7 +2737,7 @@ function TableRowInner({
2233
2737
  },
2234
2738
  [table.events, row]
2235
2739
  );
2236
- const handleContextMenu = React3.useCallback(
2740
+ const handleContextMenu = React4.useCallback(
2237
2741
  (e) => {
2238
2742
  table.events.emit("row:contextmenu", {
2239
2743
  row,
@@ -2244,15 +2748,26 @@ function TableRowInner({
2244
2748
  );
2245
2749
  const selectionEnabled = Boolean(table.options.enableRowSelection);
2246
2750
  const expansionEnabled = Boolean(table.options.enableExpanding);
2751
+ const rowClassNameDef = table.options.rowClassName;
2752
+ const userRowClassName = typeof rowClassNameDef === "function" ? rowClassNameDef(row) : rowClassNameDef;
2753
+ const rowStyleDef = table.options.rowStyle;
2754
+ const userRowStyle = typeof rowStyleDef === "function" ? rowStyleDef(row) : rowStyleDef;
2755
+ const mergedRowStyle = userRowStyle ? { ...virtualStyle, ...userRowStyle } : virtualStyle;
2756
+ const rowClassName = [
2757
+ "yable-tr",
2758
+ pinnedPosition && `yable-tr--pinned-${pinnedPosition}`,
2759
+ userRowClassName
2760
+ ].filter(Boolean).join(" ");
2247
2761
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2248
2762
  /* @__PURE__ */ jsxRuntime.jsx(
2249
2763
  "tr",
2250
2764
  {
2251
- className: "yable-tr",
2252
- style: virtualStyle,
2765
+ className: rowClassName,
2766
+ style: mergedRowStyle,
2253
2767
  "data-selected": isSelected || void 0,
2254
2768
  "data-expanded": isExpanded || void 0,
2255
2769
  "data-clickable": clickable || void 0,
2770
+ "data-pinned-row": pinnedPosition,
2256
2771
  "data-row-id": row.id,
2257
2772
  "data-row-index": rowIndex,
2258
2773
  "aria-selected": selectionEnabled ? isSelected : void 0,
@@ -2275,7 +2790,8 @@ function TableRowInner({
2275
2790
  rowIndex,
2276
2791
  columnIndex,
2277
2792
  isFocused,
2278
- isTabStop
2793
+ isTabStop,
2794
+ onFillHandleMouseDown
2279
2795
  }
2280
2796
  )
2281
2797
  },
@@ -2284,7 +2800,7 @@ function TableRowInner({
2284
2800
  })
2285
2801
  }
2286
2802
  ),
2287
- isExpanded && /* @__PURE__ */ jsxRuntime.jsx("tr", { className: "yable-expand-row", children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "yable-td", colSpan: visibleColumns.length, children: typeof row._renderExpanded === "function" ? row._renderExpanded() : null }) })
2803
+ isExpanded && /* @__PURE__ */ jsxRuntime.jsx(MasterDetail, { row, table, colSpan: visibleColumns.length })
2288
2804
  ] });
2289
2805
  }
2290
2806
  function areRowPropsEqual(prev, next) {
@@ -2295,10 +2811,12 @@ function areRowPropsEqual(prev, next) {
2295
2811
  if (prev.isSelected !== next.isSelected) return false;
2296
2812
  if (prev.isExpanded !== next.isExpanded) return false;
2297
2813
  if (prev.clickable !== next.clickable) return false;
2814
+ if (prev.pinnedPosition !== next.pinnedPosition) return false;
2298
2815
  if (prev.activeColumnId !== next.activeColumnId) return false;
2299
2816
  if (prev.focusedColumnIndex !== next.focusedColumnIndex) return false;
2300
2817
  if (prev.hasFocusedCell !== next.hasFocusedCell) return false;
2301
2818
  if (prev.cellSelectionKey !== next.cellSelectionKey) return false;
2819
+ if (prev.pendingValuesKey !== next.pendingValuesKey) return false;
2302
2820
  if (prev.virtualStyle !== next.virtualStyle) {
2303
2821
  if (!prev.virtualStyle || !next.virtualStyle) return false;
2304
2822
  if (prev.virtualStyle.transform !== next.virtualStyle.transform) return false;
@@ -2307,7 +2825,17 @@ function areRowPropsEqual(prev, next) {
2307
2825
  if (prev.table !== next.table) return false;
2308
2826
  return true;
2309
2827
  }
2310
- var MemoizedTableRow = React3__default.default.memo(TableRowInner, areRowPropsEqual);
2828
+ var MemoizedTableRow = React4__default.default.memo(TableRowInner, areRowPropsEqual);
2829
+ function getPendingValuesKey(values) {
2830
+ if (!values) return "";
2831
+ return Object.keys(values).sort().map((key) => `${key}:${String(values[key])}`).join("|");
2832
+ }
2833
+ function isInteractiveClickTarget2(target) {
2834
+ if (!(target instanceof HTMLElement)) return false;
2835
+ return Boolean(
2836
+ target.closest('input, textarea, select, button, a[href], [contenteditable="true"]')
2837
+ );
2838
+ }
2311
2839
  function TableFooter({ table }) {
2312
2840
  const footerGroups = table.getFooterGroups();
2313
2841
  if (!footerGroups.length) return null;
@@ -2515,8 +3043,8 @@ function StatusDivider() {
2515
3043
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "yable-status-bar-divider", "aria-hidden": "true" });
2516
3044
  }
2517
3045
  function PanelGroup({ children }) {
2518
- const items = React3__default.default.Children.toArray(children).filter(Boolean);
2519
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: items.map((child, i) => /* @__PURE__ */ jsxRuntime.jsxs(React3__default.default.Fragment, { children: [
3046
+ const items = React4__default.default.Children.toArray(children).filter(Boolean);
3047
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: items.map((child, i) => /* @__PURE__ */ jsxRuntime.jsxs(React4__default.default.Fragment, { children: [
2520
3048
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx(StatusDivider, {}),
2521
3049
  child
2522
3050
  ] }, i)) });
@@ -2595,53 +3123,97 @@ function StatusBar({
2595
3123
  ] });
2596
3124
  }
2597
3125
  function SearchIcon() {
2598
- return /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "yable-sidebar-search-icon", width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: [
2599
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "6.25", cy: "6.25", r: "4.25", stroke: "currentColor", strokeWidth: "1.5" }),
2600
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.5 9.5L12.5 12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
2601
- ] });
3126
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3127
+ "svg",
3128
+ {
3129
+ className: "yable-sidebar-search-icon",
3130
+ width: "13",
3131
+ height: "13",
3132
+ viewBox: "0 0 14 14",
3133
+ fill: "none",
3134
+ "aria-hidden": "true",
3135
+ children: [
3136
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "6.25", cy: "6.25", r: "4.25", stroke: "currentColor", strokeWidth: "1.5" }),
3137
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.5 9.5L12.5 12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
3138
+ ]
3139
+ }
3140
+ );
2602
3141
  }
2603
3142
  function VisibilityIcon({ visible }) {
2604
3143
  if (visible) {
2605
3144
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: [
2606
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z", stroke: "currentColor", strokeWidth: "1.2", strokeLinejoin: "round" }),
3145
+ /* @__PURE__ */ jsxRuntime.jsx(
3146
+ "path",
3147
+ {
3148
+ d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z",
3149
+ stroke: "currentColor",
3150
+ strokeWidth: "1.2",
3151
+ strokeLinejoin: "round"
3152
+ }
3153
+ ),
2607
3154
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "2", stroke: "currentColor", strokeWidth: "1.2" })
2608
3155
  ] });
2609
3156
  }
2610
3157
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: [
2611
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z", stroke: "currentColor", strokeWidth: "1.2", strokeLinejoin: "round", opacity: "0.3" }),
2612
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "2", y1: "2", x2: "12", y2: "12", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", opacity: "0.5" })
3158
+ /* @__PURE__ */ jsxRuntime.jsx(
3159
+ "path",
3160
+ {
3161
+ d: "M1 7s2.5-4 6-4 6 4 6 4-2.5 4-6 4-6-4-6-4z",
3162
+ stroke: "currentColor",
3163
+ strokeWidth: "1.2",
3164
+ strokeLinejoin: "round",
3165
+ opacity: "0.3"
3166
+ }
3167
+ ),
3168
+ /* @__PURE__ */ jsxRuntime.jsx(
3169
+ "line",
3170
+ {
3171
+ x1: "2",
3172
+ y1: "2",
3173
+ x2: "12",
3174
+ y2: "12",
3175
+ stroke: "currentColor",
3176
+ strokeWidth: "1.2",
3177
+ strokeLinecap: "round",
3178
+ opacity: "0.5"
3179
+ }
3180
+ )
2613
3181
  ] });
2614
3182
  }
2615
- function ColumnsPanel({
2616
- table
2617
- }) {
2618
- const [search, setSearch] = React3.useState("");
2619
- const [draggedId, setDraggedId] = React3.useState(null);
2620
- const columns = table.getAllLeafColumns();
3183
+ function ColumnsPanel({ table }) {
3184
+ const [search, setSearch] = React4.useState("");
3185
+ const [draggedId, setDraggedId] = React4.useState(null);
3186
+ const allColumns = table.getAllLeafColumns();
3187
+ const columnOrder = table.getState().columnOrder;
3188
+ const columns = columnOrder && columnOrder.length > 0 ? [...allColumns].sort((a, b) => {
3189
+ const ia = columnOrder.indexOf(a.id);
3190
+ const ib = columnOrder.indexOf(b.id);
3191
+ return (ia === -1 ? Number.MAX_SAFE_INTEGER : ia) - (ib === -1 ? Number.MAX_SAFE_INTEGER : ib);
3192
+ }) : allColumns;
2621
3193
  const visibleCount = columns.filter((c) => c.getIsVisible()).length;
2622
3194
  const filteredColumns = search ? columns.filter((col) => {
2623
3195
  const header = typeof col.columnDef.header === "string" ? col.columnDef.header : col.id;
2624
3196
  return header.toLowerCase().includes(search.toLowerCase());
2625
3197
  }) : columns;
2626
- const handleToggleAll = React3.useCallback(
3198
+ const handleToggleAll = React4.useCallback(
2627
3199
  (visible) => {
2628
3200
  table.toggleAllColumnsVisible(visible);
2629
3201
  },
2630
3202
  [table]
2631
3203
  );
2632
- const handleDragStart = React3.useCallback((e, columnId) => {
3204
+ const handleDragStart = React4.useCallback((e, columnId) => {
2633
3205
  setDraggedId(columnId);
2634
3206
  e.dataTransfer.effectAllowed = "move";
2635
3207
  e.dataTransfer.setData("text/plain", columnId);
2636
3208
  }, []);
2637
- const handleDragOver = React3.useCallback((e) => {
3209
+ const handleDragOver = React4.useCallback((e) => {
2638
3210
  e.preventDefault();
2639
3211
  e.dataTransfer.dropEffect = "move";
2640
3212
  }, []);
2641
- const handleDragEnd = React3.useCallback(() => {
3213
+ const handleDragEnd = React4.useCallback(() => {
2642
3214
  setDraggedId(null);
2643
3215
  }, []);
2644
- const handleDrop = React3.useCallback(
3216
+ const handleDrop = React4.useCallback(
2645
3217
  (e, targetId) => {
2646
3218
  e.preventDefault();
2647
3219
  if (!draggedId || draggedId === targetId) return;
@@ -2766,7 +3338,7 @@ function FiltersPanel({
2766
3338
  const globalFilter = table.getState().globalFilter;
2767
3339
  const hasFilters = columnFilters.length > 0 || Boolean(globalFilter);
2768
3340
  const filterCount = columnFilters.length + (globalFilter ? 1 : 0);
2769
- const handleRemoveColumnFilter = React3.useCallback(
3341
+ const handleRemoveColumnFilter = React4.useCallback(
2770
3342
  (columnId) => {
2771
3343
  table.setColumnFilters(
2772
3344
  (prev) => prev.filter((f) => f.id !== columnId)
@@ -2774,7 +3346,7 @@ function FiltersPanel({
2774
3346
  },
2775
3347
  [table]
2776
3348
  );
2777
- const handleClearAll = React3.useCallback(() => {
3349
+ const handleClearAll = React4.useCallback(() => {
2778
3350
  table.resetColumnFilters(true);
2779
3351
  table.resetGlobalFilter(true);
2780
3352
  }, [table]);
@@ -2868,8 +3440,8 @@ function Sidebar({
2868
3440
  activePanel,
2869
3441
  onPanelChange
2870
3442
  }) {
2871
- const sidebarRef = React3.useRef(null);
2872
- const handleKeyDown = React3.useCallback(
3443
+ const sidebarRef = React4.useRef(null);
3444
+ const handleKeyDown = React4.useCallback(
2873
3445
  (e) => {
2874
3446
  if (e.key === "Escape" && open) {
2875
3447
  onClose();
@@ -2877,7 +3449,7 @@ function Sidebar({
2877
3449
  },
2878
3450
  [open, onClose]
2879
3451
  );
2880
- React3.useEffect(() => {
3452
+ React4.useEffect(() => {
2881
3453
  document.addEventListener("keydown", handleKeyDown);
2882
3454
  return () => document.removeEventListener("keydown", handleKeyDown);
2883
3455
  }, [handleKeyDown]);
@@ -2959,11 +3531,11 @@ function Sidebar({
2959
3531
  );
2960
3532
  }
2961
3533
  function ContextMenuItem({ item, onClose }) {
2962
- const [submenuOpen, setSubmenuOpen] = React3.useState(false);
2963
- const itemRef = React3.useRef(null);
2964
- const submenuRef = React3.useRef(null);
2965
- const timerRef = React3.useRef(void 0);
2966
- React3.useEffect(() => {
3534
+ const [submenuOpen, setSubmenuOpen] = React4.useState(false);
3535
+ const itemRef = React4.useRef(null);
3536
+ const submenuRef = React4.useRef(null);
3537
+ const timerRef = React4.useRef(void 0);
3538
+ React4.useEffect(() => {
2967
3539
  return () => clearTimeout(timerRef.current);
2968
3540
  }, []);
2969
3541
  if (item.separator) {
@@ -3044,10 +3616,11 @@ function ContextMenu({
3044
3616
  y,
3045
3617
  onClose,
3046
3618
  table,
3619
+ targetColumnId,
3047
3620
  customItems
3048
3621
  }) {
3049
- const menuRef = React3.useRef(null);
3050
- React3.useEffect(() => {
3622
+ const menuRef = React4.useRef(null);
3623
+ React4.useEffect(() => {
3051
3624
  if (!menuRef.current) return;
3052
3625
  const rect = menuRef.current.getBoundingClientRect();
3053
3626
  const vw = window.innerWidth;
@@ -3059,11 +3632,11 @@ function ContextMenu({
3059
3632
  menuRef.current.style.top = `${y - rect.height}px`;
3060
3633
  }
3061
3634
  }, [x, y]);
3062
- React3.useEffect(() => {
3635
+ React4.useEffect(() => {
3063
3636
  const firstItem = menuRef.current?.querySelector('[role="menuitem"]');
3064
3637
  firstItem?.focus();
3065
3638
  }, []);
3066
- const handleKeyDown = React3.useCallback(
3639
+ const handleKeyDown = React4.useCallback(
3067
3640
  (e) => {
3068
3641
  if (e.key === "Escape") {
3069
3642
  onClose();
@@ -3087,6 +3660,17 @@ function ContextMenu({
3087
3660
  },
3088
3661
  [onClose]
3089
3662
  );
3663
+ const resolveSortColumn = () => {
3664
+ if (targetColumnId) {
3665
+ const column = table.getColumn(targetColumnId);
3666
+ if (column) return column;
3667
+ }
3668
+ const focused = table.getFocusedCell();
3669
+ if (focused) {
3670
+ return table.getVisibleLeafColumns()[focused.columnIndex];
3671
+ }
3672
+ return void 0;
3673
+ };
3090
3674
  const defaultItems = [
3091
3675
  {
3092
3676
  id: "copy",
@@ -3135,14 +3719,14 @@ function ContextMenu({
3135
3719
  id: "sort-asc",
3136
3720
  label: "Sort Ascending",
3137
3721
  action: () => {
3138
- table.setSorting([]);
3722
+ resolveSortColumn()?.toggleSorting(false);
3139
3723
  }
3140
3724
  },
3141
3725
  {
3142
3726
  id: "sort-desc",
3143
3727
  label: "Sort Descending",
3144
3728
  action: () => {
3145
- table.setSorting([]);
3729
+ resolveSortColumn()?.toggleSorting(true);
3146
3730
  }
3147
3731
  },
3148
3732
  {
@@ -3230,24 +3814,27 @@ function ContextMenu({
3230
3814
  ] });
3231
3815
  }
3232
3816
  function useContextMenu() {
3233
- const [isOpen, setIsOpen] = React3.useState(false);
3234
- const [x, setX] = React3.useState(0);
3235
- const [y, setY] = React3.useState(0);
3236
- const [targetTable, setTargetTable] = React3.useState(null);
3237
- const open = React3.useCallback(
3238
- (clientX, clientY, table) => {
3817
+ const [isOpen, setIsOpen] = React4.useState(false);
3818
+ const [x, setX] = React4.useState(0);
3819
+ const [y, setY] = React4.useState(0);
3820
+ const [targetTable, setTargetTable] = React4.useState(null);
3821
+ const [targetColumnId, setTargetColumnId] = React4.useState(void 0);
3822
+ const open = React4.useCallback(
3823
+ (clientX, clientY, table, columnId) => {
3239
3824
  setX(clientX);
3240
3825
  setY(clientY);
3241
3826
  setTargetTable(table);
3827
+ setTargetColumnId(columnId);
3242
3828
  setIsOpen(true);
3243
3829
  },
3244
3830
  []
3245
3831
  );
3246
- const close = React3.useCallback(() => {
3832
+ const close = React4.useCallback(() => {
3247
3833
  setIsOpen(false);
3248
3834
  setTargetTable(null);
3835
+ setTargetColumnId(void 0);
3249
3836
  }, []);
3250
- React3.useEffect(() => {
3837
+ React4.useEffect(() => {
3251
3838
  if (!isOpen) return;
3252
3839
  const handleKeyDown = (e) => {
3253
3840
  if (e.key === "Escape") close();
@@ -3260,7 +3847,7 @@ function useContextMenu() {
3260
3847
  document.removeEventListener("click", handleClick);
3261
3848
  };
3262
3849
  }, [isOpen, close]);
3263
- return { isOpen, x, y, targetTable, open, close };
3850
+ return { isOpen, x, y, targetTable, targetColumnId, open, close };
3264
3851
  }
3265
3852
  function useKeyboardNavigation(table, options = {}) {
3266
3853
  const {
@@ -3271,7 +3858,7 @@ function useKeyboardNavigation(table, options = {}) {
3271
3858
  const activeCell = table.getState().editing.activeCell;
3272
3859
  const focusedRowIndex = focusedCell?.rowIndex ?? null;
3273
3860
  const focusedColumnIndex = focusedCell?.columnIndex ?? null;
3274
- const focusCellElement = React3.useCallback(
3861
+ const focusCellElement = React4.useCallback(
3275
3862
  (container, cell) => {
3276
3863
  const element = getCellElement(container, cell);
3277
3864
  if (!element) return false;
@@ -3286,7 +3873,7 @@ function useKeyboardNavigation(table, options = {}) {
3286
3873
  },
3287
3874
  []
3288
3875
  );
3289
- const handleKeyDown = React3.useCallback(
3876
+ const handleKeyDown = React4.useCallback(
3290
3877
  (event) => {
3291
3878
  if (!enabled || table.options.enableKeyboardNavigation === false) return;
3292
3879
  const target = event.target;
@@ -3360,7 +3947,7 @@ function useKeyboardNavigation(table, options = {}) {
3360
3947
  },
3361
3948
  [activeCell, containerRef, enabled, table]
3362
3949
  );
3363
- React3.useEffect(() => {
3950
+ React4.useEffect(() => {
3364
3951
  if (!enabled || table.options.enableKeyboardNavigation === false) return;
3365
3952
  const container = containerRef?.current;
3366
3953
  if (!container) return;
@@ -3369,7 +3956,7 @@ function useKeyboardNavigation(table, options = {}) {
3369
3956
  container.removeEventListener("keydown", handleKeyDown);
3370
3957
  };
3371
3958
  }, [containerRef, enabled, handleKeyDown, table.options.enableKeyboardNavigation]);
3372
- React3.useEffect(() => {
3959
+ React4.useEffect(() => {
3373
3960
  if (!enabled || table.options.enableKeyboardNavigation === false) return;
3374
3961
  if (focusedRowIndex === null || focusedColumnIndex === null) return;
3375
3962
  if (activeCell) return;
@@ -3460,6 +4047,85 @@ function isEditableTarget(element) {
3460
4047
  }
3461
4048
  return element.isContentEditable;
3462
4049
  }
4050
+ function useFillHandle(table, options = {}) {
4051
+ const { enabled = true } = options;
4052
+ const [dragState, setDragState] = React4.useState({
4053
+ isDragging: false,
4054
+ sourceCell: null,
4055
+ currentCell: null
4056
+ });
4057
+ const dragRef = React4.useRef(dragState);
4058
+ dragRef.current = dragState;
4059
+ const onFillHandleMouseDown = React4.useCallback(
4060
+ (rowIndex, columnIndex, e) => {
4061
+ if (!enabled) return;
4062
+ e.preventDefault();
4063
+ e.stopPropagation();
4064
+ setDragState({
4065
+ isDragging: true,
4066
+ sourceCell: { rowIndex, columnIndex },
4067
+ currentCell: { rowIndex, columnIndex }
4068
+ });
4069
+ },
4070
+ [enabled]
4071
+ );
4072
+ React4.useEffect(() => {
4073
+ if (!dragState.isDragging) return;
4074
+ const handleMouseMove = (e) => {
4075
+ const target = document.elementFromPoint(e.clientX, e.clientY);
4076
+ if (!target) return;
4077
+ const td = target.closest("td[data-column-id]");
4078
+ const tr = target.closest("tr[data-row-id]");
4079
+ if (!td || !tr) return;
4080
+ const columnId = td.getAttribute("data-column-id");
4081
+ const rowId = tr.getAttribute("data-row-id");
4082
+ if (!columnId || !rowId) return;
4083
+ const rows = table.getRowModel().rows;
4084
+ const columns = table.getVisibleLeafColumns();
4085
+ const rowIndex = rows.findIndex((r) => r.id === rowId);
4086
+ const columnIndex = columns.findIndex((c) => c.id === columnId);
4087
+ if (rowIndex === -1 || columnIndex === -1) return;
4088
+ setDragState((prev) => ({
4089
+ ...prev,
4090
+ currentCell: { rowIndex, columnIndex }
4091
+ }));
4092
+ };
4093
+ const handleMouseUp = () => {
4094
+ const current = dragRef.current;
4095
+ if (current.sourceCell && current.currentCell) {
4096
+ const source = current.sourceCell;
4097
+ const target = current.currentCell;
4098
+ if (source.rowIndex !== target.rowIndex || source.columnIndex !== target.columnIndex) {
4099
+ const sourceRange = {
4100
+ startRow: source.rowIndex,
4101
+ startCol: source.columnIndex,
4102
+ endRow: source.rowIndex,
4103
+ endCol: source.columnIndex
4104
+ };
4105
+ const targetRange = {
4106
+ startRow: Math.min(source.rowIndex, target.rowIndex),
4107
+ startCol: Math.min(source.columnIndex, target.columnIndex),
4108
+ endRow: Math.max(source.rowIndex, target.rowIndex),
4109
+ endCol: Math.max(source.columnIndex, target.columnIndex)
4110
+ };
4111
+ table.fillRange(sourceRange, targetRange);
4112
+ }
4113
+ }
4114
+ setDragState({
4115
+ isDragging: false,
4116
+ sourceCell: null,
4117
+ currentCell: null
4118
+ });
4119
+ };
4120
+ document.addEventListener("mousemove", handleMouseMove);
4121
+ document.addEventListener("mouseup", handleMouseUp);
4122
+ return () => {
4123
+ document.removeEventListener("mousemove", handleMouseMove);
4124
+ document.removeEventListener("mouseup", handleMouseUp);
4125
+ };
4126
+ }, [dragState.isDragging, table]);
4127
+ return { dragState, onFillHandleMouseDown };
4128
+ }
3463
4129
  function filterHeaderGroups(groups, visibleColumnIds) {
3464
4130
  return groups.map((group) => ({
3465
4131
  ...group,
@@ -3473,6 +4139,8 @@ function Table({
3473
4139
  bordered: borderedProp,
3474
4140
  compact: compactProp,
3475
4141
  theme: themeProp,
4142
+ config,
4143
+ configProfile,
3476
4144
  clickableRows,
3477
4145
  footer,
3478
4146
  loading,
@@ -3490,7 +4158,7 @@ function Table({
3490
4158
  statusBar,
3491
4159
  statusBarPanels,
3492
4160
  sidebar,
3493
- sidebarPanels = ["columns", "filters"],
4161
+ sidebarPanels,
3494
4162
  defaultSidebarPanel,
3495
4163
  floatingFilters,
3496
4164
  columnVirtualization,
@@ -3498,20 +4166,34 @@ function Table({
3498
4166
  ariaLabel: ariaLabelProp,
3499
4167
  ...rest
3500
4168
  }) {
3501
- const { tableProps: providerTableProps } = useYableDefaults();
3502
- const stickyHeader = stickyHeaderProp ?? providerTableProps?.stickyHeader;
3503
- const striped = stripedProp ?? providerTableProps?.striped;
3504
- const bordered = borderedProp ?? providerTableProps?.bordered;
3505
- const compact = compactProp ?? providerTableProps?.compact;
3506
- const theme = themeProp ?? providerTableProps?.theme;
3507
- const direction = directionProp ?? providerTableProps?.direction;
3508
- const ariaLabel = ariaLabelProp ?? providerTableProps?.ariaLabel;
3509
- const [sidebarOpen, setSidebarOpen] = React3.useState(false);
3510
- const [sidebarPanel, setSidebarPanel] = React3.useState(
3511
- defaultSidebarPanel ?? "columns"
4169
+ const providerDefaults = useYableDefaults();
4170
+ const { tableProps: providerTableProps } = providerDefaults;
4171
+ const profile = resolveYableProfile(
4172
+ config ?? providerDefaults.config,
4173
+ configProfile ?? providerDefaults.tableProfile
4174
+ );
4175
+ const profileTableProps = profile.table;
4176
+ const stickyHeader = stickyHeaderProp ?? profileTableProps?.stickyHeader ?? providerTableProps?.stickyHeader;
4177
+ const striped = stripedProp ?? profileTableProps?.striped ?? providerTableProps?.striped;
4178
+ const bordered = borderedProp ?? profileTableProps?.bordered ?? providerTableProps?.bordered;
4179
+ const compact = compactProp ?? profileTableProps?.compact ?? providerTableProps?.compact;
4180
+ const theme = themeProp ?? profileTableProps?.theme ?? providerTableProps?.theme;
4181
+ const direction = directionProp ?? profileTableProps?.direction ?? providerTableProps?.direction;
4182
+ const ariaLabel = ariaLabelProp ?? profileTableProps?.ariaLabel ?? providerTableProps?.ariaLabel;
4183
+ const resolvedClickableRows = clickableRows ?? profileTableProps?.clickableRows;
4184
+ const resolvedStatusBar = statusBar ?? profileTableProps?.statusBar;
4185
+ const resolvedSidebar = sidebar ?? profileTableProps?.sidebar;
4186
+ const resolvedSidebarPanels = sidebarPanels ?? profileTableProps?.sidebarPanels ?? ["columns", "filters"];
4187
+ const resolvedDefaultSidebarPanel = defaultSidebarPanel ?? profileTableProps?.defaultSidebarPanel;
4188
+ const resolvedFloatingFilters = floatingFilters ?? profileTableProps?.floatingFilters;
4189
+ const resolvedColumnVirtualization = columnVirtualization ?? profileTableProps?.columnVirtualization;
4190
+ const resolvedColumnVirtualizationOverscan = columnVirtualizationOverscan ?? profileTableProps?.columnVirtualizationOverscan;
4191
+ const [sidebarOpen, setSidebarOpen] = React4.useState(false);
4192
+ const [sidebarPanel, setSidebarPanel] = React4.useState(
4193
+ resolvedDefaultSidebarPanel ?? "columns"
3512
4194
  );
3513
- const containerRef = React3.useRef(null);
3514
- const horizontalScrollRef = React3.useRef(null);
4195
+ const containerRef = React4.useRef(null);
4196
+ const horizontalScrollRef = React4.useRef(null);
3515
4197
  const isRtl = direction === "rtl";
3516
4198
  const classNames = [
3517
4199
  "yable",
@@ -3532,14 +4214,16 @@ function Table({
3532
4214
  const allVisibleColumns = table.getVisibleLeafColumns();
3533
4215
  const hasPinnedColumns = table.getLeftVisibleLeafColumns().length > 0 || table.getRightVisibleLeafColumns().length > 0;
3534
4216
  const hasGroupedHeaders = table.getHeaderGroups().length > 1;
3535
- const canVirtualizeColumns = Boolean(columnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
4217
+ const canVirtualizeColumns = Boolean(resolvedColumnVirtualization) && !hasPinnedColumns && !hasGroupedHeaders && allVisibleColumns.length > 0;
4218
+ const allVisibleColumnSizeSignature = allVisibleColumns.map((column) => `${column.id}:${column.getSize()}`).join("|");
3536
4219
  const columnVirtualState = useColumnVirtualization({
3537
4220
  containerRef: horizontalScrollRef,
3538
4221
  columns: allVisibleColumns,
3539
- overscan: columnVirtualizationOverscan ?? 2,
3540
- enabled: canVirtualizeColumns
4222
+ overscan: resolvedColumnVirtualizationOverscan ?? 2,
4223
+ enabled: canVirtualizeColumns,
4224
+ sizingKey: allVisibleColumnSizeSignature
3541
4225
  });
3542
- const renderTable = React3.useMemo(() => {
4226
+ const renderTable = React4.useMemo(() => {
3543
4227
  if (!canVirtualizeColumns || !columnVirtualState.isVirtualized) {
3544
4228
  return table;
3545
4229
  }
@@ -3565,13 +4249,16 @@ function Table({
3565
4249
  const showColumnVirtualizationShell = canVirtualizeColumns;
3566
4250
  const contextMenu = useContextMenu();
3567
4251
  useKeyboardNavigation(table, { containerRef });
3568
- const [announcement, setAnnouncement] = React3.useState("");
3569
- const prevSortingRef = React3.useRef(table.getState().sorting);
3570
- const prevFilterCountRef = React3.useRef(rows.length);
3571
- const prevHasFiltersRef = React3.useRef(isFiltered);
3572
- const prevPaginationRef = React3.useRef(table.getState().pagination);
3573
- const isFirstRenderRef = React3.useRef(true);
3574
- React3.useEffect(() => {
4252
+ const { onFillHandleMouseDown } = useFillHandle(table, {
4253
+ enabled: Boolean(table.options.enableFillHandle)
4254
+ });
4255
+ const [announcement, setAnnouncement] = React4.useState("");
4256
+ const prevSortingRef = React4.useRef(table.getState().sorting);
4257
+ const prevFilterCountRef = React4.useRef(rows.length);
4258
+ const prevHasFiltersRef = React4.useRef(isFiltered);
4259
+ const prevPaginationRef = React4.useRef(table.getState().pagination);
4260
+ const isFirstRenderRef = React4.useRef(true);
4261
+ React4.useEffect(() => {
3575
4262
  if (isFirstRenderRef.current) {
3576
4263
  isFirstRenderRef.current = false;
3577
4264
  return;
@@ -3609,21 +4296,22 @@ function Table({
3609
4296
  }
3610
4297
  }
3611
4298
  });
3612
- const handleContextMenu = React3.useCallback(
4299
+ const handleContextMenu = React4.useCallback(
3613
4300
  (e) => {
3614
4301
  e.preventDefault();
3615
- contextMenu.open(e.clientX, e.clientY, table);
4302
+ const targetEl = e.target?.closest?.("[data-column-id]");
4303
+ const targetColumnId = targetEl?.getAttribute("data-column-id") ?? void 0;
4304
+ contextMenu.open(e.clientX, e.clientY, table, targetColumnId);
3616
4305
  },
3617
4306
  [contextMenu, table]
3618
4307
  );
3619
- const enableRowVirtualization = renderTable.options.enableVirtualization ?? false;
3620
4308
  const visibleLeafColumns = renderTable.getVisibleLeafColumns();
3621
- const columnSizing = renderTable.getState().columnSizing;
3622
- const colgroup = React3.useMemo(() => {
3623
- if (visibleLeafColumns.length === 0) return null;
3624
- return /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: visibleLeafColumns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: col.getSize() } }, col.id)) });
3625
- }, [visibleLeafColumns, columnSizing]);
3626
- const outerTableStyle = React3.useMemo(() => {
4309
+ const visibleColumnTotalSize = visibleLeafColumns.reduce(
4310
+ (sum, column) => sum + column.getSize(),
4311
+ 0
4312
+ );
4313
+ const colgroup = visibleLeafColumns.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx("colgroup", { children: visibleLeafColumns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: col.getSize() } }, col.id)) });
4314
+ const outerTableStyle = React4.useMemo(() => {
3627
4315
  if (columnVirtualState.isVirtualized) {
3628
4316
  return {
3629
4317
  width: columnVirtualState.visibleWidth,
@@ -3632,15 +4320,15 @@ function Table({
3632
4320
  tableLayout: "fixed"
3633
4321
  };
3634
4322
  }
3635
- if (enableRowVirtualization) {
3636
- return { tableLayout: "fixed" };
3637
- }
3638
- return void 0;
4323
+ return {
4324
+ minWidth: visibleColumnTotalSize || void 0,
4325
+ tableLayout: "fixed"
4326
+ };
3639
4327
  }, [
3640
4328
  columnVirtualState.isVirtualized,
3641
4329
  columnVirtualState.visibleWidth,
3642
4330
  columnVirtualState.startOffset,
3643
- enableRowVirtualization
4331
+ visibleColumnTotalSize
3644
4332
  ]);
3645
4333
  const tableNode = /* @__PURE__ */ jsxRuntime.jsxs(
3646
4334
  "table",
@@ -3649,9 +4337,17 @@ function Table({
3649
4337
  style: outerTableStyle,
3650
4338
  "data-column-virtualized": columnVirtualState.isVirtualized || void 0,
3651
4339
  children: [
3652
- enableRowVirtualization && colgroup,
3653
- /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { table: renderTable, floatingFilters }),
3654
- /* @__PURE__ */ jsxRuntime.jsx(TableBody, { table: renderTable, clickableRows, colgroup }),
4340
+ colgroup,
4341
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { table: renderTable, floatingFilters: resolvedFloatingFilters }),
4342
+ /* @__PURE__ */ jsxRuntime.jsx(
4343
+ TableBody,
4344
+ {
4345
+ table: renderTable,
4346
+ clickableRows: resolvedClickableRows,
4347
+ colgroup,
4348
+ onFillHandleMouseDown
4349
+ }
4350
+ ),
3655
4351
  footer && /* @__PURE__ */ jsxRuntime.jsx(TableFooter, { table: renderTable })
3656
4352
  ]
3657
4353
  }
@@ -3717,18 +4413,43 @@ function Table({
3717
4413
  }
3718
4414
  ))
3719
4415
  ] }),
3720
- sidebar && /* @__PURE__ */ jsxRuntime.jsx(
4416
+ resolvedSidebar && !sidebarOpen && /* @__PURE__ */ jsxRuntime.jsx(
4417
+ "button",
4418
+ {
4419
+ type: "button",
4420
+ className: "yable-sidebar-trigger",
4421
+ "aria-label": "Open tool panel",
4422
+ title: "Open tool panel",
4423
+ onClick: () => setSidebarOpen(true),
4424
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
4425
+ /* @__PURE__ */ jsxRuntime.jsx(
4426
+ "rect",
4427
+ {
4428
+ x: "3",
4429
+ y: "4",
4430
+ width: "18",
4431
+ height: "16",
4432
+ rx: "2",
4433
+ stroke: "currentColor",
4434
+ strokeWidth: "2"
4435
+ }
4436
+ ),
4437
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14", y1: "4", x2: "14", y2: "20", stroke: "currentColor", strokeWidth: "2" })
4438
+ ] })
4439
+ }
4440
+ ),
4441
+ resolvedSidebar && /* @__PURE__ */ jsxRuntime.jsx(
3721
4442
  Sidebar,
3722
4443
  {
3723
4444
  table,
3724
4445
  open: sidebarOpen,
3725
4446
  onClose: () => setSidebarOpen(false),
3726
- panels: sidebarPanels,
4447
+ panels: resolvedSidebarPanels,
3727
4448
  activePanel: sidebarPanel,
3728
4449
  onPanelChange: setSidebarPanel
3729
4450
  }
3730
4451
  ),
3731
- statusBar && /* @__PURE__ */ jsxRuntime.jsx(StatusBar, { table, panels: statusBarPanels }),
4452
+ resolvedStatusBar && /* @__PURE__ */ jsxRuntime.jsx(StatusBar, { table, panels: statusBarPanels }),
3732
4453
  children,
3733
4454
  contextMenu.isOpen && /* @__PURE__ */ jsxRuntime.jsx(
3734
4455
  ContextMenu,
@@ -3736,7 +4457,8 @@ function Table({
3736
4457
  x: contextMenu.x,
3737
4458
  y: contextMenu.y,
3738
4459
  onClose: contextMenu.close,
3739
- table
4460
+ table,
4461
+ targetColumnId: contextMenu.targetColumnId
3740
4462
  }
3741
4463
  ),
3742
4464
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3947,12 +4669,12 @@ function GlobalFilter({
3947
4669
  }) {
3948
4670
  const locale = yableCore.getDefaultLocale();
3949
4671
  const resolvedPlaceholder = placeholder ?? locale.searchPlaceholder;
3950
- const [value, setValue] = React3.useState(
4672
+ const [value, setValue] = React4.useState(
3951
4673
  table.getState().globalFilter ?? ""
3952
4674
  );
3953
- const timerRef = React3.useRef(void 0);
3954
- const inputRef = React3.useRef(null);
3955
- const handleChange = React3.useCallback(
4675
+ const timerRef = React4.useRef(void 0);
4676
+ const inputRef = React4.useRef(null);
4677
+ const handleChange = React4.useCallback(
3956
4678
  (e) => {
3957
4679
  const newValue = e.target.value;
3958
4680
  setValue(newValue);
@@ -3967,13 +4689,13 @@ function GlobalFilter({
3967
4689
  },
3968
4690
  [table, debounce]
3969
4691
  );
3970
- const handleClear = React3.useCallback(() => {
4692
+ const handleClear = React4.useCallback(() => {
3971
4693
  setValue("");
3972
4694
  table.setGlobalFilter("");
3973
4695
  clearTimeout(timerRef.current);
3974
4696
  inputRef.current?.focus();
3975
4697
  }, [table]);
3976
- const handleKeyDown = React3.useCallback(
4698
+ const handleKeyDown = React4.useCallback(
3977
4699
  (e) => {
3978
4700
  if (e.key === "Escape" && value) {
3979
4701
  e.preventDefault();
@@ -3982,10 +4704,10 @@ function GlobalFilter({
3982
4704
  },
3983
4705
  [value, handleClear]
3984
4706
  );
3985
- React3.useEffect(() => {
4707
+ React4.useEffect(() => {
3986
4708
  return () => clearTimeout(timerRef.current);
3987
4709
  }, []);
3988
- React3.useEffect(() => {
4710
+ React4.useEffect(() => {
3989
4711
  const externalValue = table.getState().globalFilter ?? "";
3990
4712
  if (externalValue !== value) {
3991
4713
  setValue(externalValue);
@@ -4030,7 +4752,7 @@ function CellInput({
4030
4752
  className
4031
4753
  }) {
4032
4754
  const { table, row, column, cell } = context;
4033
- const inputRef = React3.useRef(null);
4755
+ const inputRef = React4.useRef(null);
4034
4756
  const isEditing = cell.getIsEditing();
4035
4757
  const isAlwaysEditable = cell.getIsAlwaysEditable();
4036
4758
  const pending = table.getPendingValue(row.id, column.id);
@@ -4055,7 +4777,7 @@ function CellInput({
4055
4777
  }
4056
4778
  }
4057
4779
  };
4058
- React3.useEffect(() => {
4780
+ React4.useEffect(() => {
4059
4781
  if ((isEditing || autoFocus) && inputRef.current) {
4060
4782
  inputRef.current.focus();
4061
4783
  inputRef.current.select();
@@ -4091,8 +4813,8 @@ function CellSelect({
4091
4813
  const isAlwaysEditable = cell.getIsAlwaysEditable();
4092
4814
  const pending = table.getPendingValue(row.id, column.id);
4093
4815
  const currentValue = pending !== void 0 ? pending : cell.getValue();
4094
- const commitTimerRef = React3.useRef(null);
4095
- React3.useEffect(() => {
4816
+ const commitTimerRef = React4.useRef(null);
4817
+ React4.useEffect(() => {
4096
4818
  return () => {
4097
4819
  if (commitTimerRef.current !== null) {
4098
4820
  clearTimeout(commitTimerRef.current);
@@ -4173,7 +4895,7 @@ function CellDatePicker({
4173
4895
  className
4174
4896
  }) {
4175
4897
  const { table, row, column, cell } = context;
4176
- const inputRef = React3.useRef(null);
4898
+ const inputRef = React4.useRef(null);
4177
4899
  const isEditing = cell.getIsEditing();
4178
4900
  const isAlwaysEditable = cell.getIsAlwaysEditable();
4179
4901
  const pending = table.getPendingValue(row.id, column.id);
@@ -4187,7 +4909,7 @@ function CellDatePicker({
4187
4909
  table.commitEdit();
4188
4910
  }
4189
4911
  };
4190
- React3.useEffect(() => {
4912
+ React4.useEffect(() => {
4191
4913
  if (isEditing && inputRef.current) {
4192
4914
  inputRef.current.focus();
4193
4915
  }
@@ -4222,7 +4944,7 @@ function formatDateValue(value, type) {
4222
4944
  }
4223
4945
  function useClipboard(table, options = {}) {
4224
4946
  const { enabled = true, containerRef, onCopy, onCut, onPaste, ...clipboardOptions } = options;
4225
- const handleCopy = React3.useCallback(
4947
+ const handleCopy = React4.useCallback(
4226
4948
  (e) => {
4227
4949
  if (isEditableTarget2(e.target)) return;
4228
4950
  e.preventDefault();
@@ -4234,7 +4956,7 @@ function useClipboard(table, options = {}) {
4234
4956
  },
4235
4957
  [table, clipboardOptions, onCopy]
4236
4958
  );
4237
- const handleCut = React3.useCallback(
4959
+ const handleCut = React4.useCallback(
4238
4960
  (e) => {
4239
4961
  if (isEditableTarget2(e.target)) return;
4240
4962
  e.preventDefault();
@@ -4246,7 +4968,7 @@ function useClipboard(table, options = {}) {
4246
4968
  },
4247
4969
  [table, clipboardOptions, onCut]
4248
4970
  );
4249
- const handlePaste = React3.useCallback(
4971
+ const handlePaste = React4.useCallback(
4250
4972
  (e) => {
4251
4973
  if (isEditableTarget2(e.target)) return;
4252
4974
  e.preventDefault();
@@ -4291,7 +5013,7 @@ function useClipboard(table, options = {}) {
4291
5013
  },
4292
5014
  [table, clipboardOptions, onPaste]
4293
5015
  );
4294
- React3.useEffect(() => {
5016
+ React4.useEffect(() => {
4295
5017
  if (!enabled) return;
4296
5018
  const container = containerRef?.current ?? document;
4297
5019
  container.addEventListener("copy", handleCopy);
@@ -4313,110 +5035,6 @@ function isEditableTarget2(el) {
4313
5035
  if (el.isContentEditable) return true;
4314
5036
  return false;
4315
5037
  }
4316
- function useFillHandle(table, options = {}) {
4317
- const { enabled = true } = options;
4318
- const [dragState, setDragState] = React3.useState({
4319
- isDragging: false,
4320
- sourceCell: null,
4321
- currentCell: null
4322
- });
4323
- const dragRef = React3.useRef(dragState);
4324
- dragRef.current = dragState;
4325
- const onFillHandleMouseDown = React3.useCallback(
4326
- (rowIndex, columnIndex, e) => {
4327
- if (!enabled) return;
4328
- e.preventDefault();
4329
- e.stopPropagation();
4330
- setDragState({
4331
- isDragging: true,
4332
- sourceCell: { rowIndex, columnIndex },
4333
- currentCell: { rowIndex, columnIndex }
4334
- });
4335
- },
4336
- [enabled]
4337
- );
4338
- React3.useEffect(() => {
4339
- if (!dragState.isDragging) return;
4340
- const handleMouseMove = (e) => {
4341
- const target = document.elementFromPoint(e.clientX, e.clientY);
4342
- if (!target) return;
4343
- const td = target.closest("td[data-column-id]");
4344
- const tr = target.closest("tr[data-row-id]");
4345
- if (!td || !tr) return;
4346
- const columnId = td.getAttribute("data-column-id");
4347
- const rowId = tr.getAttribute("data-row-id");
4348
- if (!columnId || !rowId) return;
4349
- const rows = table.getRowModel().rows;
4350
- const columns = table.getVisibleLeafColumns();
4351
- const rowIndex = rows.findIndex((r) => r.id === rowId);
4352
- const columnIndex = columns.findIndex((c) => c.id === columnId);
4353
- if (rowIndex === -1 || columnIndex === -1) return;
4354
- setDragState((prev) => ({
4355
- ...prev,
4356
- currentCell: { rowIndex, columnIndex }
4357
- }));
4358
- };
4359
- const handleMouseUp = () => {
4360
- const current = dragRef.current;
4361
- if (current.sourceCell && current.currentCell) {
4362
- const source = current.sourceCell;
4363
- const target = current.currentCell;
4364
- if (source.rowIndex !== target.rowIndex || source.columnIndex !== target.columnIndex) {
4365
- const sourceRange = {
4366
- startRow: source.rowIndex,
4367
- startCol: source.columnIndex,
4368
- endRow: source.rowIndex,
4369
- endCol: source.columnIndex
4370
- };
4371
- const targetRange = {
4372
- startRow: Math.min(source.rowIndex, target.rowIndex),
4373
- startCol: Math.min(source.columnIndex, target.columnIndex),
4374
- endRow: Math.max(source.rowIndex, target.rowIndex),
4375
- endCol: Math.max(source.columnIndex, target.columnIndex)
4376
- };
4377
- table.fillRange(sourceRange, targetRange);
4378
- }
4379
- }
4380
- setDragState({
4381
- isDragging: false,
4382
- sourceCell: null,
4383
- currentCell: null
4384
- });
4385
- };
4386
- document.addEventListener("mousemove", handleMouseMove);
4387
- document.addEventListener("mouseup", handleMouseUp);
4388
- return () => {
4389
- document.removeEventListener("mousemove", handleMouseMove);
4390
- document.removeEventListener("mouseup", handleMouseUp);
4391
- };
4392
- }, [dragState.isDragging, table]);
4393
- return { dragState, onFillHandleMouseDown };
4394
- }
4395
- function FillHandle({
4396
- rowIndex,
4397
- columnIndex,
4398
- onMouseDown
4399
- }) {
4400
- const handleMouseDown = React3.useCallback(
4401
- (e) => {
4402
- e.preventDefault();
4403
- e.stopPropagation();
4404
- onMouseDown(rowIndex, columnIndex, e);
4405
- },
4406
- [rowIndex, columnIndex, onMouseDown]
4407
- );
4408
- return /* @__PURE__ */ jsxRuntime.jsx(
4409
- "div",
4410
- {
4411
- className: "yable-fill-handle",
4412
- onMouseDown: handleMouseDown,
4413
- role: "presentation",
4414
- "aria-hidden": "true",
4415
- title: "Drag to fill",
4416
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-fill-handle-dot" })
4417
- }
4418
- );
4419
- }
4420
5038
  function GripIcon() {
4421
5039
  return /* @__PURE__ */ jsxRuntime.jsxs(
4422
5040
  "svg",
@@ -4449,7 +5067,7 @@ function DragHandle({
4449
5067
  isDragging && "yable-row-drag-handle--dragging",
4450
5068
  className
4451
5069
  ].filter(Boolean).join(" ");
4452
- const handleDragStart = React3.useCallback(
5070
+ const handleDragStart = React4.useCallback(
4453
5071
  (e) => {
4454
5072
  if (e.dataTransfer && e.currentTarget instanceof HTMLElement) {
4455
5073
  e.dataTransfer.effectAllowed = "move";
@@ -4478,10 +5096,10 @@ function useRowDrag({
4478
5096
  onDataChange,
4479
5097
  onReorder
4480
5098
  }) {
4481
- const [dragState, setDragState] = React3.useState(rowDragging.getInitialRowDragState);
4482
- const dragRowIdRef = React3.useRef(null);
4483
- const dragRowIndexRef = React3.useRef(-1);
4484
- const getRowDragProps = React3.useCallback(
5099
+ const [dragState, setDragState] = React4.useState(rowDragging.getInitialRowDragState);
5100
+ const dragRowIdRef = React4.useRef(null);
5101
+ const dragRowIndexRef = React4.useRef(-1);
5102
+ const getRowDragProps = React4.useCallback(
4485
5103
  (rowId, rowIndex) => {
4486
5104
  return {
4487
5105
  draggable: true,
@@ -4580,7 +5198,7 @@ function useRowDrag({
4580
5198
  },
4581
5199
  [data, dragState, onDataChange, onReorder, table]
4582
5200
  );
4583
- const getDragHandleProps = React3.useCallback(
5201
+ const getDragHandleProps = React4.useCallback(
4584
5202
  (rowId) => ({
4585
5203
  onDragStart: (e) => {
4586
5204
  e.dataTransfer.effectAllowed = "move";
@@ -4607,7 +5225,7 @@ function TreeToggle({
4607
5225
  const isExpanded = row.getIsExpanded();
4608
5226
  const canToggle = showToggle !== void 0 ? showToggle : hasChildren;
4609
5227
  const indent = depth * indentWidth;
4610
- const handleClick = React3.useCallback(
5228
+ const handleClick = React4.useCallback(
4611
5229
  (e) => {
4612
5230
  e.stopPropagation();
4613
5231
  if (canToggle) {
@@ -4664,33 +5282,6 @@ function TreeToggle({
4664
5282
  }
4665
5283
  );
4666
5284
  }
4667
- function MasterDetail({
4668
- row,
4669
- table,
4670
- colSpan,
4671
- renderDetailPanel,
4672
- animationClass
4673
- }) {
4674
- const renderer = renderDetailPanel ?? table.options.renderDetailPanel;
4675
- if (!renderer) return null;
4676
- const content = renderer(row);
4677
- if (content == null) return null;
4678
- const classes = [
4679
- "yable-detail-row",
4680
- "yable-detail-row--animated",
4681
- animationClass
4682
- ].filter(Boolean).join(" ");
4683
- return /* @__PURE__ */ jsxRuntime.jsx(
4684
- "tr",
4685
- {
4686
- className: classes,
4687
- "data-detail-for": row.id,
4688
- role: "row",
4689
- "aria-label": `Details for row ${row.id}`,
4690
- children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "yable-detail-cell", colSpan, role: "cell", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-detail-panel", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "yable-detail-panel-inner", children: content }) }) })
4691
- }
4692
- );
4693
- }
4694
5285
  function ExpandIcon({
4695
5286
  isExpanded,
4696
5287
  onClick,
@@ -4704,7 +5295,7 @@ function ExpandIcon({
4704
5295
  className
4705
5296
  ].filter(Boolean).join(" ");
4706
5297
  const label = ariaLabel ?? (isExpanded ? "Collapse details" : "Expand details");
4707
- const handleClick = React3.useCallback(
5298
+ const handleClick = React4.useCallback(
4708
5299
  (e) => {
4709
5300
  e.stopPropagation();
4710
5301
  onClick(e);
@@ -4769,20 +5360,20 @@ function PivotConfigPanel({
4769
5360
  aggregationOptions = DEFAULT_AGGREGATION_OPTIONS,
4770
5361
  className
4771
5362
  }) {
4772
- const [dragSource, setDragSource] = React3.useState(null);
5363
+ const [dragSource, setDragSource] = React4.useState(null);
4773
5364
  const usedFields = /* @__PURE__ */ new Set([
4774
5365
  ...rowFields.map((f) => f.field),
4775
5366
  ...columnFields.map((f) => f.field),
4776
5367
  ...valueFields.map((f) => f.field)
4777
5368
  ]);
4778
5369
  const unplacedFields = availableFields.filter((f) => !usedFields.has(f.field));
4779
- const handleDragStart = React3.useCallback(
5370
+ const handleDragStart = React4.useCallback(
4780
5371
  (field, zone) => {
4781
5372
  setDragSource({ field, zone });
4782
5373
  },
4783
5374
  []
4784
5375
  );
4785
- const handleDrop = React3.useCallback(
5376
+ const handleDrop = React4.useCallback(
4786
5377
  (targetZone) => {
4787
5378
  if (!dragSource) return;
4788
5379
  const { field, zone: sourceZone } = dragSource;
@@ -4825,7 +5416,7 @@ function PivotConfigPanel({
4825
5416
  onValueFieldsChange
4826
5417
  ]
4827
5418
  );
4828
- const handleAggregationChange = React3.useCallback(
5419
+ const handleAggregationChange = React4.useCallback(
4829
5420
  (field, aggregation) => {
4830
5421
  onValueFieldsChange(
4831
5422
  valueFields.map(
@@ -4835,7 +5426,7 @@ function PivotConfigPanel({
4835
5426
  },
4836
5427
  [valueFields, onValueFieldsChange]
4837
5428
  );
4838
- const handleRemoveField = React3.useCallback(
5429
+ const handleRemoveField = React4.useCallback(
4839
5430
  (field, zone) => {
4840
5431
  if (zone === "rows") {
4841
5432
  onRowFieldsChange(rowFields.filter((f) => f.field !== field));
@@ -5025,8 +5616,8 @@ function Tooltip({
5025
5616
  content,
5026
5617
  customComponent
5027
5618
  }) {
5028
- const tooltipRef = React3.useRef(null);
5029
- React3.useEffect(() => {
5619
+ const tooltipRef = React4.useRef(null);
5620
+ React4.useEffect(() => {
5030
5621
  if (!visible || !tooltipRef.current) return;
5031
5622
  const el = tooltipRef.current;
5032
5623
  const rect = el.getBoundingClientRect();
@@ -5091,16 +5682,16 @@ function Tooltip({
5091
5682
  }
5092
5683
  function useTooltip(options = {}) {
5093
5684
  const { delay = 500, placement = "top", enabled = true } = options;
5094
- const [visible, setVisible] = React3.useState(false);
5095
- const [position, setPosition] = React3.useState({
5685
+ const [visible, setVisible] = React4.useState(false);
5686
+ const [position, setPosition] = React4.useState({
5096
5687
  x: 0,
5097
5688
  y: 0,
5098
5689
  placement
5099
5690
  });
5100
- const [content, setContent] = React3.useState("");
5101
- const timerRef = React3.useRef(void 0);
5102
- const targetRef = React3.useRef(null);
5103
- const show = React3.useCallback(
5691
+ const [content, setContent] = React4.useState("");
5692
+ const timerRef = React4.useRef(void 0);
5693
+ const targetRef = React4.useRef(null);
5694
+ const show = React4.useCallback(
5104
5695
  (target, tooltipContent) => {
5105
5696
  if (!enabled || !tooltipContent) return;
5106
5697
  targetRef.current = target;
@@ -5147,12 +5738,12 @@ function useTooltip(options = {}) {
5147
5738
  },
5148
5739
  [delay, placement, enabled]
5149
5740
  );
5150
- const hide = React3.useCallback(() => {
5741
+ const hide = React4.useCallback(() => {
5151
5742
  clearTimeout(timerRef.current);
5152
5743
  setVisible(false);
5153
5744
  targetRef.current = null;
5154
5745
  }, []);
5155
- React3.useEffect(() => {
5746
+ React4.useEffect(() => {
5156
5747
  return () => clearTimeout(timerRef.current);
5157
5748
  }, []);
5158
5749
  return {
@@ -5374,10 +5965,10 @@ function FlashCell({
5374
5965
  }
5375
5966
  function useCellFlash(table, options = {}) {
5376
5967
  const { duration = 700 } = options;
5377
- const [flashes, setFlashes] = React3.useState(/* @__PURE__ */ new Map());
5378
- const prevDataRef = React3.useRef([]);
5379
- const timersRef = React3.useRef(/* @__PURE__ */ new Map());
5380
- const clearFlash = React3.useCallback((key) => {
5968
+ const [flashes, setFlashes] = React4.useState(/* @__PURE__ */ new Map());
5969
+ const prevDataRef = React4.useRef([]);
5970
+ const timersRef = React4.useRef(/* @__PURE__ */ new Map());
5971
+ const clearFlash = React4.useCallback((key) => {
5381
5972
  setFlashes((prev) => {
5382
5973
  const next = new Map(prev);
5383
5974
  next.delete(key);
@@ -5385,7 +5976,7 @@ function useCellFlash(table, options = {}) {
5385
5976
  });
5386
5977
  timersRef.current.delete(key);
5387
5978
  }, []);
5388
- React3.useEffect(() => {
5979
+ React4.useEffect(() => {
5389
5980
  const currentData = table.options.data;
5390
5981
  const prevData = prevDataRef.current;
5391
5982
  if (prevData.length > 0 && currentData !== prevData) {
@@ -5414,14 +6005,14 @@ function useCellFlash(table, options = {}) {
5414
6005
  }
5415
6006
  prevDataRef.current = currentData;
5416
6007
  }, [table.options.data, table, duration, clearFlash]);
5417
- React3.useEffect(() => {
6008
+ React4.useEffect(() => {
5418
6009
  return () => {
5419
6010
  for (const timer of timersRef.current.values()) {
5420
6011
  clearTimeout(timer);
5421
6012
  }
5422
6013
  };
5423
6014
  }, []);
5424
- const getFlash = React3.useCallback(
6015
+ const getFlash = React4.useCallback(
5425
6016
  (rowId, columnId) => {
5426
6017
  return flashes.get(`${rowId}:${columnId}`);
5427
6018
  },
@@ -5431,9 +6022,9 @@ function useCellFlash(table, options = {}) {
5431
6022
  }
5432
6023
  function useRowAnimation(_table, options = {}) {
5433
6024
  const { enabled = false, duration = 250, easing = "ease" } = options;
5434
- const prevPositionsRef = React3.useRef(/* @__PURE__ */ new Map());
5435
- const animatingRef = React3.useRef(false);
5436
- const capturePositions = React3.useCallback(
6025
+ const prevPositionsRef = React4.useRef(/* @__PURE__ */ new Map());
6026
+ const animatingRef = React4.useRef(false);
6027
+ const capturePositions = React4.useCallback(
5437
6028
  (containerEl) => {
5438
6029
  if (!enabled || !containerEl) return;
5439
6030
  const positions = /* @__PURE__ */ new Map();
@@ -5451,7 +6042,7 @@ function useRowAnimation(_table, options = {}) {
5451
6042
  },
5452
6043
  [enabled]
5453
6044
  );
5454
- const animateRows = React3.useCallback(
6045
+ const animateRows = React4.useCallback(
5455
6046
  (containerEl) => {
5456
6047
  if (!enabled || !containerEl || animatingRef.current) return;
5457
6048
  const prevPositions = prevPositionsRef.current;
@@ -5573,8 +6164,8 @@ function sanitizeCSS(css) {
5573
6164
  }
5574
6165
  function usePrintLayout(_table, options = {}) {
5575
6166
  const { title, additionalCSS } = options;
5576
- const isPrintingRef = React3.useRef(false);
5577
- const preparePrint = React3.useCallback(() => {
6167
+ const isPrintingRef = React4.useRef(false);
6168
+ const preparePrint = React4.useCallback(() => {
5578
6169
  const yableEl = document.querySelector(".yable");
5579
6170
  if (yableEl) {
5580
6171
  yableEl.classList.add("yable-print-mode");
@@ -5616,23 +6207,23 @@ function usePrintLayout(_table, options = {}) {
5616
6207
  }
5617
6208
  function useTheme(options = {}) {
5618
6209
  const { defaultTheme = "default", defaultColorScheme = "auto" } = options;
5619
- const [theme, setThemeState] = React3.useState(defaultTheme);
5620
- const [colorScheme, setColorSchemeState] = React3.useState(defaultColorScheme);
5621
- const containerRef = React3.useRef(null);
5622
- const setTheme = React3.useCallback((newTheme) => {
6210
+ const [theme, setThemeState] = React4.useState(defaultTheme);
6211
+ const [colorScheme, setColorSchemeState] = React4.useState(defaultColorScheme);
6212
+ const containerRef = React4.useRef(null);
6213
+ const setTheme = React4.useCallback((newTheme) => {
5623
6214
  setThemeState(newTheme);
5624
6215
  }, []);
5625
- const setColorScheme = React3.useCallback((scheme) => {
6216
+ const setColorScheme = React4.useCallback((scheme) => {
5626
6217
  setColorSchemeState(scheme);
5627
6218
  }, []);
5628
- const toggleColorScheme = React3.useCallback(() => {
6219
+ const toggleColorScheme = React4.useCallback(() => {
5629
6220
  setColorSchemeState((prev) => {
5630
6221
  if (prev === "auto") return "dark";
5631
6222
  if (prev === "dark") return "light";
5632
6223
  return "auto";
5633
6224
  });
5634
6225
  }, []);
5635
- React3.useEffect(() => {
6226
+ React4.useEffect(() => {
5636
6227
  const target = containerRef.current ?? document.documentElement;
5637
6228
  if (colorScheme === "auto") {
5638
6229
  target.removeAttribute("data-yable-theme");
@@ -5640,8 +6231,8 @@ function useTheme(options = {}) {
5640
6231
  target.setAttribute("data-yable-theme", colorScheme);
5641
6232
  }
5642
6233
  }, [colorScheme]);
5643
- const [systemDark, setSystemDark] = React3.useState(false);
5644
- React3.useEffect(() => {
6234
+ const [systemDark, setSystemDark] = React4.useState(false);
6235
+ React4.useEffect(() => {
5645
6236
  const mq = window.matchMedia("(prefers-color-scheme: dark)");
5646
6237
  setSystemDark(mq.matches);
5647
6238
  const handler = (e) => setSystemDark(e.matches);
@@ -5663,10 +6254,11 @@ function selectColumn(options = {}) {
5663
6254
  const { id = "_select", size = 40, headerAriaLabel = "Select all rows" } = options;
5664
6255
  return {
5665
6256
  id,
5666
- header: ({ table }) => /* @__PURE__ */ jsxRuntime.jsx(
6257
+ header: ({ table }) => /* @__PURE__ */ jsxRuntime.jsx("label", { className: "yable-checkbox-hitbox", onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(
5667
6258
  "input",
5668
6259
  {
5669
6260
  type: "checkbox",
6261
+ className: "yable-checkbox",
5670
6262
  checked: table.getIsAllPageRowsSelected(),
5671
6263
  ref: (el) => {
5672
6264
  if (el)
@@ -5675,19 +6267,21 @@ function selectColumn(options = {}) {
5675
6267
  onChange: () => table.toggleAllPageRowsSelected(),
5676
6268
  "aria-label": headerAriaLabel
5677
6269
  }
5678
- ),
5679
- cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(
6270
+ ) }),
6271
+ cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx("label", { className: "yable-checkbox-hitbox", onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsx(
5680
6272
  "input",
5681
6273
  {
5682
6274
  type: "checkbox",
6275
+ className: "yable-checkbox",
5683
6276
  checked: row.getIsSelected(),
5684
6277
  disabled: !row.getCanSelect(),
5685
6278
  onChange: row.getToggleSelectedHandler(),
5686
- "aria-label": `Select row`
6279
+ "aria-label": "Select row"
5687
6280
  }
5688
- ),
6281
+ ) }),
5689
6282
  size,
5690
- enableSorting: false,
6283
+ enableSorting: true,
6284
+ sortingFn: (rowA, rowB) => Number(rowA.getIsSelected()) - Number(rowB.getIsSelected()),
5691
6285
  enableColumnFilter: false,
5692
6286
  enableResizing: false,
5693
6287
  enableReorder: false,
@@ -6020,11 +6614,15 @@ exports.Tooltip = Tooltip;
6020
6614
  exports.TreeToggle = TreeToggle;
6021
6615
  exports.YableProvider = YableProvider;
6022
6616
  exports.actionsColumn = actionsColumn;
6617
+ exports.applyYableConfigToColumns = applyYableConfigToColumns;
6618
+ exports.createYableConfig = createYableConfig;
6023
6619
  exports.expandColumn = expandColumn;
6024
6620
  exports.getMeasureRecipeForCellType = getMeasureRecipeForCellType;
6025
6621
  exports.getRegisteredCellTypes = getRegisteredCellTypes;
6622
+ exports.getYableDefaultColumnDef = getYableDefaultColumnDef;
6026
6623
  exports.mergeEditChanges = mergeEditChanges;
6027
6624
  exports.resolveMeasureRecipe = resolveMeasureRecipe;
6625
+ exports.resolveYableProfile = resolveYableProfile;
6028
6626
  exports.rowNumberColumn = rowNumberColumn;
6029
6627
  exports.selectColumn = selectColumn;
6030
6628
  exports.useAutoMeasurements = useAutoMeasurements;
@@ -6038,6 +6636,7 @@ exports.usePretextMeasurement = usePretextMeasurement;
6038
6636
  exports.usePrintLayout = usePrintLayout;
6039
6637
  exports.useRowAnimation = useRowAnimation;
6040
6638
  exports.useRowDrag = useRowDrag;
6639
+ exports.useServerTable = useServerTable;
6041
6640
  exports.useTable = useTable;
6042
6641
  exports.useTableContext = useTableContext;
6043
6642
  exports.useTablePersistence = useTablePersistence;