@forgedevstack/grid-table 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2806 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BREAKPOINTS: () => BREAKPOINTS,
24
+ BREAKPOINT_KEYS: () => BREAKPOINT_KEYS,
25
+ DEFAULT_COLUMN_WIDTH: () => DEFAULT_COLUMN_WIDTH,
26
+ DEFAULT_LIGHT_THEME: () => DEFAULT_LIGHT_THEME,
27
+ DEFAULT_PAGE_SIZE: () => DEFAULT_PAGE_SIZE,
28
+ DEFAULT_PAGE_SIZES: () => DEFAULT_PAGE_SIZES,
29
+ DEFAULT_TABLE_CONFIG: () => DEFAULT_TABLE_CONFIG,
30
+ DEFAULT_THEME: () => DEFAULT_THEME,
31
+ DEFAULT_TRANSLATIONS: () => DEFAULT_TRANSLATIONS,
32
+ DESKTOP_BREAKPOINT: () => DESKTOP_BREAKPOINT,
33
+ EmptyState: () => EmptyState,
34
+ GridBody: () => GridBody,
35
+ GridCell: () => GridCell,
36
+ GridHeader: () => GridHeader,
37
+ GridRow: () => GridRow,
38
+ GridTable: () => GridTable,
39
+ MAX_COLUMN_WIDTH: () => MAX_COLUMN_WIDTH,
40
+ MIN_COLUMN_WIDTH: () => MIN_COLUMN_WIDTH,
41
+ MOBILE_BREAKPOINT: () => MOBILE_BREAKPOINT,
42
+ MobileDrawer: () => MobileDrawer,
43
+ Pagination: () => Pagination,
44
+ RESPONSIVE_MODES: () => RESPONSIVE_MODES,
45
+ Skeleton: () => Skeleton,
46
+ TABLET_BREAKPOINT: () => TABLET_BREAKPOINT,
47
+ TableContext: () => TableContext,
48
+ TableProvider: () => TableProvider,
49
+ useBreakpoint: () => useBreakpoint,
50
+ useDragDrop: () => useDragDrop,
51
+ useFilter: () => useFilter,
52
+ usePagination: () => usePagination,
53
+ useSort: () => useSort,
54
+ useTable: () => useTable,
55
+ useTableContext: () => useTableContext
56
+ });
57
+ module.exports = __toCommonJS(index_exports);
58
+
59
+ // src/components/GridTable/GridTable.tsx
60
+ var import_react15 = require("react");
61
+
62
+ // src/context/TableContext.tsx
63
+ var import_react = require("react");
64
+
65
+ // src/constants/numbers.const.ts
66
+ var ZERO = 0;
67
+ var ONE = 1;
68
+ var FIVE = 5;
69
+ var TEN = 10;
70
+ var TWENTY = 20;
71
+ var FIFTY = 50;
72
+ var HUNDRED = 100;
73
+ var DEFAULT_PAGE_SIZE = TEN;
74
+ var DEFAULT_PAGE_SIZES = [TEN, TWENTY, FIFTY, HUNDRED];
75
+ var MIN_COLUMN_WIDTH = 50;
76
+ var DEFAULT_COLUMN_WIDTH = 150;
77
+ var MAX_COLUMN_WIDTH = 500;
78
+ var SKELETON_ROWS = FIVE;
79
+ var DEBOUNCE_DELAY = 300;
80
+ var DRAG_THRESHOLD = FIVE;
81
+ var MOBILE_BREAKPOINT = 640;
82
+ var TABLET_BREAKPOINT = 768;
83
+ var DESKTOP_BREAKPOINT = 1024;
84
+ var DRAWER_ANIMATION_DURATION = 300;
85
+ var DRAWER_OVERLAY_OPACITY = 0.5;
86
+
87
+ // src/constants/breakpoints.const.ts
88
+ var BREAKPOINTS = {
89
+ mobile: MOBILE_BREAKPOINT,
90
+ tablet: TABLET_BREAKPOINT,
91
+ desktop: DESKTOP_BREAKPOINT
92
+ };
93
+ var BREAKPOINT_KEYS = ["mobile", "tablet", "desktop"];
94
+ var RESPONSIVE_MODES = {
95
+ stack: "stack",
96
+ scroll: "scroll",
97
+ hide: "hide"
98
+ };
99
+ var DEFAULT_MOBILE_BREAKPOINT = "tablet";
100
+
101
+ // src/constants/defaults.const.ts
102
+ var DEFAULT_TRANSLATIONS = {
103
+ empty: "No data available",
104
+ loading: "Loading...",
105
+ search: "Search...",
106
+ filter: "Filter",
107
+ sort: "Sort",
108
+ sortAsc: "Sort ascending",
109
+ sortDesc: "Sort descending",
110
+ clearSort: "Clear sort",
111
+ clearFilter: "Clear filter",
112
+ clearAll: "Clear all",
113
+ apply: "Apply",
114
+ cancel: "Cancel",
115
+ columns: "Columns",
116
+ showColumns: "Show columns",
117
+ hideColumn: "Hide column",
118
+ resetColumns: "Reset columns",
119
+ rowsPerPage: "Rows per page",
120
+ of: "of",
121
+ page: "Page",
122
+ first: "First",
123
+ previous: "Previous",
124
+ next: "Next",
125
+ last: "Last",
126
+ selected: "selected",
127
+ dragToReorder: "Drag to reorder",
128
+ noResults: "No results found",
129
+ errorLoading: "Error loading data",
130
+ retry: "Retry"
131
+ };
132
+ var DEFAULT_THEME = {
133
+ mode: "dark",
134
+ colors: {
135
+ background: {
136
+ primary: "#1e1e1e",
137
+ secondary: "#2b2b2b",
138
+ tertiary: "#3c3c3c",
139
+ hover: "#4e4e4e"
140
+ },
141
+ text: {
142
+ primary: "#a9b7c6",
143
+ secondary: "#808080",
144
+ muted: "#606060"
145
+ },
146
+ border: {
147
+ default: "rgba(255, 255, 255, 0.08)",
148
+ hover: "rgba(255, 255, 255, 0.15)"
149
+ },
150
+ accent: {
151
+ primary: "#1890ff",
152
+ success: "#52c41a",
153
+ warning: "#faad14",
154
+ error: "#ff4d4f"
155
+ }
156
+ }
157
+ };
158
+ var DEFAULT_LIGHT_THEME = {
159
+ mode: "light",
160
+ colors: {
161
+ background: {
162
+ primary: "#ffffff",
163
+ secondary: "#f5f5f5",
164
+ tertiary: "#ebebeb",
165
+ hover: "#e0e0e0"
166
+ },
167
+ text: {
168
+ primary: "#262626",
169
+ secondary: "#595959",
170
+ muted: "#8c8c8c"
171
+ },
172
+ border: {
173
+ default: "rgba(0, 0, 0, 0.06)",
174
+ hover: "rgba(0, 0, 0, 0.1)"
175
+ },
176
+ accent: {
177
+ primary: "#1890ff",
178
+ success: "#52c41a",
179
+ warning: "#faad14",
180
+ error: "#ff4d4f"
181
+ }
182
+ }
183
+ };
184
+ var DEFAULT_TABLE_CONFIG = {
185
+ pageSize: DEFAULT_PAGE_SIZE,
186
+ pageSizes: DEFAULT_PAGE_SIZES,
187
+ columnWidth: DEFAULT_COLUMN_WIDTH,
188
+ mobileBreakpoint: DEFAULT_MOBILE_BREAKPOINT,
189
+ stickyHeader: true,
190
+ showPagination: true,
191
+ showFilter: true,
192
+ showSort: true,
193
+ enableDragDrop: true,
194
+ enableColumnResize: true,
195
+ enableRowSelection: false,
196
+ enableMultiSelect: false,
197
+ showColumnToggle: true,
198
+ showEmptyState: true,
199
+ showSkeleton: true,
200
+ skeletonRows: 5,
201
+ virtualize: false,
202
+ virtualizeThreshold: 100
203
+ };
204
+
205
+ // src/context/TableContext.tsx
206
+ var import_jsx_runtime = require("react/jsx-runtime");
207
+ function reducer(state, action) {
208
+ switch (action.type) {
209
+ case "SET_DATA":
210
+ return { ...state, data: action.payload, originalData: action.payload };
211
+ case "SET_LOADING":
212
+ return { ...state, loading: action.payload };
213
+ case "SET_ERROR":
214
+ return { ...state, error: action.payload };
215
+ case "SET_SORTING":
216
+ return { ...state, sorting: action.payload };
217
+ case "SET_FILTERS":
218
+ return { ...state, filters: action.payload };
219
+ case "SET_GLOBAL_FILTER":
220
+ return { ...state, globalFilter: action.payload };
221
+ case "SET_PAGE":
222
+ return { ...state, page: action.payload };
223
+ case "SET_PAGE_SIZE":
224
+ return { ...state, pageSize: action.payload, page: ONE };
225
+ case "SET_SELECTED_IDS":
226
+ return { ...state, selectedIds: action.payload };
227
+ case "SET_EXPANDED_IDS":
228
+ return { ...state, expandedIds: action.payload };
229
+ case "SET_COLUMN_STATES":
230
+ return { ...state, columnStates: action.payload };
231
+ case "SET_DRAGGING_COLUMN":
232
+ return { ...state, draggingColumnId: action.payload };
233
+ case "SET_RESIZING_COLUMN":
234
+ return { ...state, resizingColumnId: action.payload };
235
+ case "SET_ACTIVE_FILTER_COLUMN":
236
+ return { ...state, activeFilterColumnId: action.payload };
237
+ case "SET_CURRENT_BREAKPOINT":
238
+ return { ...state, currentBreakpoint: action.payload };
239
+ case "SET_MOBILE_DRAWER":
240
+ return {
241
+ ...state,
242
+ showMobileDrawer: action.payload.show,
243
+ mobileDrawerContent: action.payload.content
244
+ };
245
+ case "RESET":
246
+ return { ...state, ...action.payload };
247
+ default:
248
+ return state;
249
+ }
250
+ }
251
+ var TableContext = (0, import_react.createContext)(null);
252
+ function TableProvider({
253
+ children,
254
+ data,
255
+ columns,
256
+ loading = false,
257
+ error = null,
258
+ theme,
259
+ translations,
260
+ mobileBreakpoint = "tablet",
261
+ paginationConfig,
262
+ filterConfig: _filterConfig,
263
+ sortConfig: _sortConfig,
264
+ enableMultiSort = false,
265
+ getRowId,
266
+ onStateChange
267
+ }) {
268
+ var _a, _b;
269
+ const initialColumnStates = columns.map((col, index) => ({
270
+ id: col.id,
271
+ visible: !col.hidden,
272
+ width: typeof col.width === "number" ? col.width : DEFAULT_TABLE_CONFIG.columnWidth,
273
+ order: index,
274
+ pinned: col.sticky || null
275
+ }));
276
+ const mergedTheme = (0, import_react.useMemo)(
277
+ () => ({ ...DEFAULT_THEME, ...theme, colors: { ...DEFAULT_THEME.colors, ...theme == null ? void 0 : theme.colors } }),
278
+ [theme]
279
+ );
280
+ const mergedTranslations = (0, import_react.useMemo)(
281
+ () => ({ ...DEFAULT_TRANSLATIONS, ...translations }),
282
+ [translations]
283
+ );
284
+ const initialState = {
285
+ data,
286
+ originalData: data,
287
+ columns,
288
+ columnStates: initialColumnStates,
289
+ sorting: [],
290
+ filters: [],
291
+ globalFilter: "",
292
+ page: (_a = paginationConfig == null ? void 0 : paginationConfig.initialPage) != null ? _a : ONE,
293
+ pageSize: (_b = paginationConfig == null ? void 0 : paginationConfig.initialPageSize) != null ? _b : DEFAULT_TABLE_CONFIG.pageSize,
294
+ totalItems: data.length,
295
+ selectedIds: /* @__PURE__ */ new Set(),
296
+ expandedIds: /* @__PURE__ */ new Set(),
297
+ loading,
298
+ error,
299
+ theme: mergedTheme,
300
+ translations: mergedTranslations,
301
+ currentBreakpoint: "desktop",
302
+ mobileBreakpoint,
303
+ draggingColumnId: null,
304
+ resizingColumnId: null,
305
+ activeFilterColumnId: null,
306
+ showMobileDrawer: false,
307
+ mobileDrawerContent: null
308
+ };
309
+ const [state, dispatch] = (0, import_react.useReducer)(reducer, initialState);
310
+ (0, import_react.useEffect)(() => {
311
+ dispatch({ type: "SET_DATA", payload: data });
312
+ }, [data]);
313
+ (0, import_react.useEffect)(() => {
314
+ dispatch({ type: "SET_LOADING", payload: loading });
315
+ }, [loading]);
316
+ (0, import_react.useEffect)(() => {
317
+ dispatch({ type: "SET_ERROR", payload: error });
318
+ }, [error]);
319
+ (0, import_react.useEffect)(() => {
320
+ const handleResize = () => {
321
+ const width = window.innerWidth;
322
+ let breakpoint = "desktop";
323
+ if (width < MOBILE_BREAKPOINT) {
324
+ breakpoint = "mobile";
325
+ } else if (width < TABLET_BREAKPOINT) {
326
+ breakpoint = "tablet";
327
+ }
328
+ dispatch({ type: "SET_CURRENT_BREAKPOINT", payload: breakpoint });
329
+ };
330
+ handleResize();
331
+ window.addEventListener("resize", handleResize);
332
+ return () => window.removeEventListener("resize", handleResize);
333
+ }, []);
334
+ (0, import_react.useEffect)(() => {
335
+ onStateChange == null ? void 0 : onStateChange(state);
336
+ }, [state, onStateChange]);
337
+ const getRowIdFn = (0, import_react.useCallback)(
338
+ (row) => {
339
+ if (getRowId) return getRowId(row);
340
+ if ("id" in row) return row.id;
341
+ return data.indexOf(row);
342
+ },
343
+ [getRowId, data]
344
+ );
345
+ const actions = (0, import_react.useMemo)(
346
+ () => ({
347
+ setData: (newData) => dispatch({ type: "SET_DATA", payload: newData }),
348
+ setLoading: (value) => dispatch({ type: "SET_LOADING", payload: value }),
349
+ setError: (value) => dispatch({ type: "SET_ERROR", payload: value }),
350
+ setSorting: (columnId, direction) => {
351
+ const newSorting = enableMultiSort ? [...state.sorting.filter((s) => s.columnId !== columnId), { columnId, direction }] : direction ? [{ columnId, direction }] : [];
352
+ dispatch({ type: "SET_SORTING", payload: newSorting.filter((s) => s.direction !== null) });
353
+ },
354
+ toggleSorting: (columnId) => {
355
+ const current = state.sorting.find((s) => s.columnId === columnId);
356
+ let newDirection = "asc";
357
+ if ((current == null ? void 0 : current.direction) === "asc") newDirection = "desc";
358
+ else if ((current == null ? void 0 : current.direction) === "desc") newDirection = null;
359
+ actions.setSorting(columnId, newDirection);
360
+ },
361
+ clearSorting: () => dispatch({ type: "SET_SORTING", payload: [] }),
362
+ setFilter: (columnId, value, operator = "contains") => {
363
+ const newFilters = [
364
+ ...state.filters.filter((f) => f.columnId !== columnId),
365
+ { columnId, value, operator }
366
+ ];
367
+ dispatch({ type: "SET_FILTERS", payload: newFilters });
368
+ dispatch({ type: "SET_PAGE", payload: ONE });
369
+ },
370
+ removeFilter: (columnId) => {
371
+ const newFilters = state.filters.filter((f) => f.columnId !== columnId);
372
+ dispatch({ type: "SET_FILTERS", payload: newFilters });
373
+ },
374
+ clearFilters: () => {
375
+ dispatch({ type: "SET_FILTERS", payload: [] });
376
+ dispatch({ type: "SET_GLOBAL_FILTER", payload: "" });
377
+ },
378
+ setGlobalFilter: (value) => {
379
+ dispatch({ type: "SET_GLOBAL_FILTER", payload: value });
380
+ dispatch({ type: "SET_PAGE", payload: ONE });
381
+ },
382
+ setPage: (page) => dispatch({ type: "SET_PAGE", payload: page }),
383
+ setPageSize: (pageSize) => dispatch({ type: "SET_PAGE_SIZE", payload: pageSize }),
384
+ selectRow: (id) => {
385
+ const newSet = new Set(state.selectedIds);
386
+ newSet.add(id);
387
+ dispatch({ type: "SET_SELECTED_IDS", payload: newSet });
388
+ },
389
+ deselectRow: (id) => {
390
+ const newSet = new Set(state.selectedIds);
391
+ newSet.delete(id);
392
+ dispatch({ type: "SET_SELECTED_IDS", payload: newSet });
393
+ },
394
+ toggleRow: (id) => {
395
+ if (state.selectedIds.has(id)) {
396
+ actions.deselectRow(id);
397
+ } else {
398
+ actions.selectRow(id);
399
+ }
400
+ },
401
+ selectAll: () => {
402
+ const allIds = new Set(state.data.map(getRowIdFn));
403
+ dispatch({ type: "SET_SELECTED_IDS", payload: allIds });
404
+ },
405
+ deselectAll: () => dispatch({ type: "SET_SELECTED_IDS", payload: /* @__PURE__ */ new Set() }),
406
+ expandRow: (id) => {
407
+ const newSet = new Set(state.expandedIds);
408
+ newSet.add(id);
409
+ dispatch({ type: "SET_EXPANDED_IDS", payload: newSet });
410
+ },
411
+ collapseRow: (id) => {
412
+ const newSet = new Set(state.expandedIds);
413
+ newSet.delete(id);
414
+ dispatch({ type: "SET_EXPANDED_IDS", payload: newSet });
415
+ },
416
+ toggleRowExpansion: (id) => {
417
+ if (state.expandedIds.has(id)) {
418
+ actions.collapseRow(id);
419
+ } else {
420
+ actions.expandRow(id);
421
+ }
422
+ },
423
+ reorderColumn: (sourceId, targetId) => {
424
+ const newStates = [...state.columnStates];
425
+ const sourceIndex = newStates.findIndex((c) => c.id === sourceId);
426
+ const targetIndex = newStates.findIndex((c) => c.id === targetId);
427
+ if (sourceIndex === -ONE || targetIndex === -ONE) return;
428
+ const [removed] = newStates.splice(sourceIndex, ONE);
429
+ newStates.splice(targetIndex, ZERO, removed);
430
+ newStates.forEach((col, i) => col.order = i);
431
+ dispatch({ type: "SET_COLUMN_STATES", payload: newStates });
432
+ },
433
+ resizeColumn: (columnId, width) => {
434
+ const newStates = state.columnStates.map(
435
+ (col) => col.id === columnId ? { ...col, width } : col
436
+ );
437
+ dispatch({ type: "SET_COLUMN_STATES", payload: newStates });
438
+ },
439
+ toggleColumnVisibility: (columnId) => {
440
+ const newStates = state.columnStates.map(
441
+ (col) => col.id === columnId ? { ...col, visible: !col.visible } : col
442
+ );
443
+ dispatch({ type: "SET_COLUMN_STATES", payload: newStates });
444
+ },
445
+ resetColumns: () => dispatch({ type: "SET_COLUMN_STATES", payload: initialColumnStates }),
446
+ setDraggingColumn: (columnId) => dispatch({ type: "SET_DRAGGING_COLUMN", payload: columnId }),
447
+ setResizingColumn: (columnId) => dispatch({ type: "SET_RESIZING_COLUMN", payload: columnId }),
448
+ setActiveFilterColumn: (columnId) => dispatch({ type: "SET_ACTIVE_FILTER_COLUMN", payload: columnId }),
449
+ openMobileDrawer: (content) => dispatch({ type: "SET_MOBILE_DRAWER", payload: { show: true, content } }),
450
+ closeMobileDrawer: () => dispatch({ type: "SET_MOBILE_DRAWER", payload: { show: false, content: null } }),
451
+ refresh: () => dispatch({ type: "SET_DATA", payload: state.originalData }),
452
+ reset: () => dispatch({
453
+ type: "RESET",
454
+ payload: {
455
+ sorting: [],
456
+ filters: [],
457
+ globalFilter: "",
458
+ page: ONE,
459
+ selectedIds: /* @__PURE__ */ new Set(),
460
+ expandedIds: /* @__PURE__ */ new Set(),
461
+ columnStates: initialColumnStates
462
+ }
463
+ })
464
+ }),
465
+ [state, enableMultiSort, getRowIdFn, initialColumnStates]
466
+ );
467
+ const computed = (0, import_react.useMemo)(() => {
468
+ let filteredData = [...state.data];
469
+ if (state.globalFilter) {
470
+ const searchLower = state.globalFilter.toLowerCase();
471
+ filteredData = filteredData.filter(
472
+ (row) => Object.values(row).some(
473
+ (val) => String(val).toLowerCase().includes(searchLower)
474
+ )
475
+ );
476
+ }
477
+ state.filters.forEach((filter) => {
478
+ const column = columns.find((c) => c.id === filter.columnId);
479
+ if (!column) return;
480
+ filteredData = filteredData.filter((row) => {
481
+ const accessor = column.accessor;
482
+ const value = typeof accessor === "function" ? accessor(row) : row[accessor];
483
+ const filterValue = filter.value;
484
+ if (column.filterFn) {
485
+ return column.filterFn(value, filterValue, filter.operator);
486
+ }
487
+ const strValue = String(value != null ? value : "").toLowerCase();
488
+ const strFilter = String(filterValue != null ? filterValue : "").toLowerCase();
489
+ switch (filter.operator) {
490
+ case "equals":
491
+ return strValue === strFilter;
492
+ case "notEquals":
493
+ return strValue !== strFilter;
494
+ case "contains":
495
+ return strValue.includes(strFilter);
496
+ case "notContains":
497
+ return !strValue.includes(strFilter);
498
+ case "startsWith":
499
+ return strValue.startsWith(strFilter);
500
+ case "endsWith":
501
+ return strValue.endsWith(strFilter);
502
+ case "isEmpty":
503
+ return !value || strValue === "";
504
+ case "isNotEmpty":
505
+ return value && strValue !== "";
506
+ default:
507
+ return strValue.includes(strFilter);
508
+ }
509
+ });
510
+ });
511
+ let sortedData = [...filteredData];
512
+ if (state.sorting.length > ZERO) {
513
+ sortedData.sort((a, b) => {
514
+ for (const sort of state.sorting) {
515
+ const column = columns.find((c) => c.id === sort.columnId);
516
+ if (!column) continue;
517
+ const accessor = column.accessor;
518
+ const aVal = typeof accessor === "function" ? accessor(a) : a[accessor];
519
+ const bVal = typeof accessor === "function" ? accessor(b) : b[accessor];
520
+ if (column.sortFn) {
521
+ const result2 = column.sortFn(aVal, bVal, sort.direction);
522
+ if (result2 !== ZERO) return result2;
523
+ continue;
524
+ }
525
+ if (aVal === bVal) continue;
526
+ if (aVal == null) return ONE;
527
+ if (bVal == null) return -ONE;
528
+ const comparison = aVal < bVal ? -ONE : ONE;
529
+ const result = sort.direction === "desc" ? -comparison : comparison;
530
+ if (result !== ZERO) return result;
531
+ }
532
+ return ZERO;
533
+ });
534
+ }
535
+ const totalPages = Math.ceil(sortedData.length / state.pageSize) || ONE;
536
+ const startIndex = (state.page - ONE) * state.pageSize;
537
+ const paginatedData = sortedData.slice(startIndex, startIndex + state.pageSize);
538
+ const visibleColumns = columns.filter((col) => {
539
+ const colState = state.columnStates.find((cs) => cs.id === col.id);
540
+ return (colState == null ? void 0 : colState.visible) !== false;
541
+ });
542
+ const allSelected = state.data.length > ZERO && state.selectedIds.size === state.data.length;
543
+ const someSelected = state.selectedIds.size > ZERO && !allSelected;
544
+ const isMobile = state.currentBreakpoint === "mobile";
545
+ const isTablet = state.currentBreakpoint === "tablet";
546
+ const isDesktop = state.currentBreakpoint === "desktop";
547
+ return {
548
+ filteredData,
549
+ sortedData,
550
+ paginatedData,
551
+ visibleColumns,
552
+ totalPages,
553
+ canGoNext: state.page < totalPages,
554
+ canGoPrevious: state.page > ONE,
555
+ allSelected,
556
+ someSelected,
557
+ isMobile,
558
+ isTablet,
559
+ isDesktop
560
+ };
561
+ }, [state, columns]);
562
+ const contextValue = {
563
+ state,
564
+ actions,
565
+ computed
566
+ };
567
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableContext.Provider, { value: contextValue, children });
568
+ }
569
+ function useTableContext() {
570
+ const context = (0, import_react.useContext)(TableContext);
571
+ if (!context) {
572
+ throw new Error("useTableContext must be used within a TableProvider");
573
+ }
574
+ return context;
575
+ }
576
+
577
+ // src/hooks/useTable.ts
578
+ var import_react7 = require("react");
579
+
580
+ // src/hooks/useSort.ts
581
+ var import_react2 = require("react");
582
+ function useSort() {
583
+ const { state, actions } = useTableContext();
584
+ const getSortDirection = (0, import_react2.useCallback)(
585
+ (columnId) => {
586
+ var _a;
587
+ const sort = state.sorting.find((s) => s.columnId === columnId);
588
+ return (_a = sort == null ? void 0 : sort.direction) != null ? _a : null;
589
+ },
590
+ [state.sorting]
591
+ );
592
+ const getSortIndex = (0, import_react2.useCallback)(
593
+ (columnId) => {
594
+ return state.sorting.findIndex((s) => s.columnId === columnId);
595
+ },
596
+ [state.sorting]
597
+ );
598
+ const isSorted = (0, import_react2.useCallback)(
599
+ (columnId) => {
600
+ return state.sorting.some((s) => s.columnId === columnId);
601
+ },
602
+ [state.sorting]
603
+ );
604
+ const clearColumnSorting = (0, import_react2.useCallback)(
605
+ (columnId) => {
606
+ actions.setSorting(columnId, null);
607
+ },
608
+ [actions]
609
+ );
610
+ return (0, import_react2.useMemo)(
611
+ () => ({
612
+ sorting: state.sorting,
613
+ getSortDirection,
614
+ getSortIndex,
615
+ isSorted,
616
+ setSorting: actions.setSorting,
617
+ toggleSorting: actions.toggleSorting,
618
+ clearSorting: actions.clearSorting,
619
+ clearColumnSorting
620
+ }),
621
+ [state.sorting, getSortDirection, getSortIndex, isSorted, actions, clearColumnSorting]
622
+ );
623
+ }
624
+
625
+ // src/hooks/useFilter.ts
626
+ var import_react3 = require("react");
627
+ function useFilter(options = {}) {
628
+ const { debounceMs = DEBOUNCE_DELAY } = options;
629
+ const { state, actions } = useTableContext();
630
+ const [debouncedGlobalFilter, setDebouncedGlobalFilter] = (0, import_react3.useState)(state.globalFilter);
631
+ (0, import_react3.useEffect)(() => {
632
+ const timer = setTimeout(() => {
633
+ if (debouncedGlobalFilter !== state.globalFilter) {
634
+ actions.setGlobalFilter(debouncedGlobalFilter);
635
+ }
636
+ }, debounceMs);
637
+ return () => clearTimeout(timer);
638
+ }, [debouncedGlobalFilter, debounceMs, actions, state.globalFilter]);
639
+ const hasAnyFilter = (0, import_react3.useCallback)(() => {
640
+ return state.filters.length > 0 || state.globalFilter.length > 0;
641
+ }, [state.filters, state.globalFilter]);
642
+ const hasFilter = (0, import_react3.useCallback)(
643
+ (columnId) => {
644
+ return state.filters.some((f) => f.columnId === columnId);
645
+ },
646
+ [state.filters]
647
+ );
648
+ const getFilterValue = (0, import_react3.useCallback)(
649
+ (columnId) => {
650
+ return state.filters.find((f) => f.columnId === columnId);
651
+ },
652
+ [state.filters]
653
+ );
654
+ const setFilter = (0, import_react3.useCallback)(
655
+ (columnId, value, operator = "contains") => {
656
+ actions.setFilter(columnId, value, operator);
657
+ },
658
+ [actions]
659
+ );
660
+ const clearGlobalFilter = (0, import_react3.useCallback)(() => {
661
+ setDebouncedGlobalFilter("");
662
+ actions.setGlobalFilter("");
663
+ }, [actions]);
664
+ const setGlobalFilterDebounced = (0, import_react3.useCallback)((value) => {
665
+ setDebouncedGlobalFilter(value);
666
+ }, []);
667
+ const openFilterPanel = (0, import_react3.useCallback)(
668
+ (columnId) => {
669
+ actions.setActiveFilterColumn(columnId);
670
+ },
671
+ [actions]
672
+ );
673
+ const closeFilterPanel = (0, import_react3.useCallback)(() => {
674
+ actions.setActiveFilterColumn(null);
675
+ }, [actions]);
676
+ return (0, import_react3.useMemo)(
677
+ () => ({
678
+ filters: state.filters,
679
+ globalFilter: debouncedGlobalFilter,
680
+ activeFilterColumnId: state.activeFilterColumnId,
681
+ hasAnyFilter,
682
+ hasFilter,
683
+ getFilterValue,
684
+ setFilter,
685
+ removeFilter: actions.removeFilter,
686
+ clearFilters: actions.clearFilters,
687
+ setGlobalFilter: setGlobalFilterDebounced,
688
+ clearGlobalFilter,
689
+ openFilterPanel,
690
+ closeFilterPanel
691
+ }),
692
+ [
693
+ state.filters,
694
+ state.activeFilterColumnId,
695
+ debouncedGlobalFilter,
696
+ hasAnyFilter,
697
+ hasFilter,
698
+ getFilterValue,
699
+ setFilter,
700
+ actions,
701
+ setGlobalFilterDebounced,
702
+ clearGlobalFilter,
703
+ openFilterPanel,
704
+ closeFilterPanel
705
+ ]
706
+ );
707
+ }
708
+
709
+ // src/hooks/usePagination.ts
710
+ var import_react4 = require("react");
711
+ function usePagination(options = {}) {
712
+ const { pageSizeOptions = [10, 20, 50, 100] } = options;
713
+ const { state, actions, computed } = useTableContext();
714
+ const setPage = (0, import_react4.useCallback)(
715
+ (page) => {
716
+ const validPage = Math.max(ONE, Math.min(page, computed.totalPages));
717
+ actions.setPage(validPage);
718
+ },
719
+ [actions, computed.totalPages]
720
+ );
721
+ const setPageSize = (0, import_react4.useCallback)(
722
+ (pageSize) => {
723
+ actions.setPageSize(pageSize);
724
+ },
725
+ [actions]
726
+ );
727
+ const goToFirstPage = (0, import_react4.useCallback)(() => {
728
+ actions.setPage(ONE);
729
+ }, [actions]);
730
+ const goToLastPage = (0, import_react4.useCallback)(() => {
731
+ actions.setPage(computed.totalPages);
732
+ }, [actions, computed.totalPages]);
733
+ const goToNextPage = (0, import_react4.useCallback)(() => {
734
+ if (computed.canGoNext) {
735
+ actions.setPage(state.page + ONE);
736
+ }
737
+ }, [actions, computed.canGoNext, state.page]);
738
+ const goToPreviousPage = (0, import_react4.useCallback)(() => {
739
+ if (computed.canGoPrevious) {
740
+ actions.setPage(state.page - ONE);
741
+ }
742
+ }, [actions, computed.canGoPrevious, state.page]);
743
+ const canGoToNextPage = (0, import_react4.useCallback)(() => {
744
+ return computed.canGoNext;
745
+ }, [computed.canGoNext]);
746
+ const canGoToPreviousPage = (0, import_react4.useCallback)(() => {
747
+ return computed.canGoPrevious;
748
+ }, [computed.canGoPrevious]);
749
+ const getPageRange = (0, import_react4.useCallback)(() => {
750
+ const start = (state.page - ONE) * state.pageSize + ONE;
751
+ const end = Math.min(state.page * state.pageSize, computed.sortedData.length);
752
+ return { start, end };
753
+ }, [state.page, state.pageSize, computed.sortedData.length]);
754
+ const paginationInfo = (0, import_react4.useMemo)(() => {
755
+ const { start, end } = getPageRange();
756
+ return {
757
+ page: state.page,
758
+ pageSize: state.pageSize,
759
+ totalItems: computed.sortedData.length,
760
+ totalPages: computed.totalPages,
761
+ startIndex: start,
762
+ endIndex: end,
763
+ isFirstPage: state.page === ONE,
764
+ isLastPage: state.page === computed.totalPages
765
+ };
766
+ }, [state.page, state.pageSize, computed.sortedData.length, computed.totalPages, getPageRange]);
767
+ return (0, import_react4.useMemo)(
768
+ () => ({
769
+ ...paginationInfo,
770
+ pageSizeOptions,
771
+ setPage,
772
+ setPageSize,
773
+ goToFirstPage,
774
+ goToLastPage,
775
+ goToNextPage,
776
+ goToPreviousPage,
777
+ canGoToNextPage,
778
+ canGoToPreviousPage,
779
+ getPageRange
780
+ }),
781
+ [
782
+ paginationInfo,
783
+ pageSizeOptions,
784
+ setPage,
785
+ setPageSize,
786
+ goToFirstPage,
787
+ goToLastPage,
788
+ goToNextPage,
789
+ goToPreviousPage,
790
+ canGoToNextPage,
791
+ canGoToPreviousPage,
792
+ getPageRange
793
+ ]
794
+ );
795
+ }
796
+
797
+ // src/hooks/useDragDrop.ts
798
+ var import_react5 = require("react");
799
+ function useDragDrop(options = {}) {
800
+ const { onReorder, enabled = true } = options;
801
+ const { state, actions } = useTableContext();
802
+ const [dragOverColumnId, setDragOverColumnId] = (0, import_react5.useState)(null);
803
+ const dragStartPosition = (0, import_react5.useRef)(null);
804
+ const isDragValid = (0, import_react5.useRef)(false);
805
+ const handleDragStart = (0, import_react5.useCallback)(
806
+ (columnId) => (event) => {
807
+ if (!enabled) {
808
+ event.preventDefault();
809
+ return;
810
+ }
811
+ dragStartPosition.current = { x: event.clientX, y: event.clientY };
812
+ isDragValid.current = false;
813
+ event.dataTransfer.effectAllowed = "move";
814
+ event.dataTransfer.setData("text/plain", columnId);
815
+ requestAnimationFrame(() => {
816
+ actions.setDraggingColumn(columnId);
817
+ });
818
+ },
819
+ [enabled, actions]
820
+ );
821
+ const handleDragOver = (0, import_react5.useCallback)(
822
+ (columnId) => (event) => {
823
+ if (!enabled || !state.draggingColumnId) return;
824
+ event.preventDefault();
825
+ event.dataTransfer.dropEffect = "move";
826
+ if (dragStartPosition.current) {
827
+ const dx = Math.abs(event.clientX - dragStartPosition.current.x);
828
+ const dy = Math.abs(event.clientY - dragStartPosition.current.y);
829
+ if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) {
830
+ isDragValid.current = true;
831
+ }
832
+ }
833
+ if (columnId !== state.draggingColumnId && columnId !== dragOverColumnId) {
834
+ setDragOverColumnId(columnId);
835
+ }
836
+ },
837
+ [enabled, state.draggingColumnId, dragOverColumnId]
838
+ );
839
+ const handleDragLeave = (0, import_react5.useCallback)(() => {
840
+ setDragOverColumnId(null);
841
+ }, []);
842
+ const handleDrop = (0, import_react5.useCallback)(
843
+ (targetColumnId) => (event) => {
844
+ event.preventDefault();
845
+ if (!enabled || !state.draggingColumnId || !isDragValid.current) return;
846
+ if (state.draggingColumnId === targetColumnId) return;
847
+ const sourceIndex = state.columnStates.findIndex((c) => c.id === state.draggingColumnId);
848
+ const targetIndex = state.columnStates.findIndex((c) => c.id === targetColumnId);
849
+ if (sourceIndex !== -1 && targetIndex !== -1) {
850
+ actions.reorderColumn(state.draggingColumnId, targetColumnId);
851
+ onReorder == null ? void 0 : onReorder({
852
+ sourceId: state.draggingColumnId,
853
+ targetId: targetColumnId,
854
+ sourceIndex,
855
+ targetIndex
856
+ });
857
+ }
858
+ setDragOverColumnId(null);
859
+ },
860
+ [enabled, state.draggingColumnId, state.columnStates, actions, onReorder]
861
+ );
862
+ const handleDragEnd = (0, import_react5.useCallback)(() => {
863
+ actions.setDraggingColumn(null);
864
+ setDragOverColumnId(null);
865
+ dragStartPosition.current = null;
866
+ isDragValid.current = false;
867
+ }, [actions]);
868
+ const getDragHandleProps = (0, import_react5.useCallback)(
869
+ (columnId) => ({
870
+ draggable: enabled,
871
+ onDragStart: handleDragStart(columnId),
872
+ onDragEnd: handleDragEnd
873
+ }),
874
+ [enabled, handleDragStart, handleDragEnd]
875
+ );
876
+ const getDropTargetProps = (0, import_react5.useCallback)(
877
+ (columnId) => ({
878
+ onDragOver: handleDragOver(columnId),
879
+ onDragLeave: handleDragLeave,
880
+ onDrop: handleDrop(columnId)
881
+ }),
882
+ [handleDragOver, handleDragLeave, handleDrop]
883
+ );
884
+ return (0, import_react5.useMemo)(
885
+ () => ({
886
+ isDragging: !!state.draggingColumnId,
887
+ draggingColumnId: state.draggingColumnId,
888
+ dragOverColumnId,
889
+ handleDragStart,
890
+ handleDragOver,
891
+ handleDragEnd,
892
+ handleDrop,
893
+ handleDragLeave,
894
+ getDragHandleProps,
895
+ getDropTargetProps
896
+ }),
897
+ [
898
+ state.draggingColumnId,
899
+ dragOverColumnId,
900
+ handleDragStart,
901
+ handleDragOver,
902
+ handleDragEnd,
903
+ handleDrop,
904
+ handleDragLeave,
905
+ getDragHandleProps,
906
+ getDropTargetProps
907
+ ]
908
+ );
909
+ }
910
+
911
+ // src/hooks/useBreakpoint.ts
912
+ var import_react6 = require("react");
913
+ function useBreakpoint() {
914
+ const { state, computed } = useTableContext();
915
+ const breakpointValue = (0, import_react6.useMemo)(
916
+ () => (value, fallback) => {
917
+ if (value === null || value === void 0) return fallback;
918
+ if (typeof value !== "object" || !("mobile" in value || "tablet" in value || "desktop" in value)) {
919
+ return value;
920
+ }
921
+ const responsiveValue = value;
922
+ const breakpointOrder = ["mobile", "tablet", "desktop"];
923
+ const currentIndex = breakpointOrder.indexOf(state.currentBreakpoint);
924
+ for (let i = currentIndex; i >= 0; i--) {
925
+ const bp = breakpointOrder[i];
926
+ if (responsiveValue[bp] !== void 0) {
927
+ return responsiveValue[bp];
928
+ }
929
+ }
930
+ for (let i = currentIndex + 1; i < breakpointOrder.length; i++) {
931
+ const bp = breakpointOrder[i];
932
+ if (responsiveValue[bp] !== void 0) {
933
+ return responsiveValue[bp];
934
+ }
935
+ }
936
+ return fallback;
937
+ },
938
+ [state.currentBreakpoint]
939
+ );
940
+ const shouldShowMobileView = (0, import_react6.useMemo)(() => {
941
+ const mobileBreakpoints = ["mobile"];
942
+ if (state.mobileBreakpoint === "tablet") {
943
+ mobileBreakpoints.push("tablet");
944
+ }
945
+ return mobileBreakpoints.includes(state.currentBreakpoint);
946
+ }, [state.currentBreakpoint, state.mobileBreakpoint]);
947
+ return (0, import_react6.useMemo)(
948
+ () => ({
949
+ currentBreakpoint: state.currentBreakpoint,
950
+ isMobile: computed.isMobile,
951
+ isTablet: computed.isTablet,
952
+ isDesktop: computed.isDesktop,
953
+ isMobileOrTablet: computed.isMobile || computed.isTablet,
954
+ isTabletOrDesktop: computed.isTablet || computed.isDesktop,
955
+ breakpointValue,
956
+ shouldShowMobileView
957
+ }),
958
+ [state.currentBreakpoint, computed, breakpointValue, shouldShowMobileView]
959
+ );
960
+ }
961
+
962
+ // src/hooks/useTable.ts
963
+ function useTable() {
964
+ const { state, actions, computed } = useTableContext();
965
+ const sort = useSort();
966
+ const filter = useFilter();
967
+ const pagination = usePagination();
968
+ const dragDrop = useDragDrop();
969
+ const breakpoint = useBreakpoint();
970
+ const selection = (0, import_react7.useMemo)(
971
+ () => ({
972
+ selectedIds: state.selectedIds,
973
+ allSelected: computed.allSelected,
974
+ someSelected: computed.someSelected,
975
+ selectRow: actions.selectRow,
976
+ deselectRow: actions.deselectRow,
977
+ toggleRow: actions.toggleRow,
978
+ selectAll: actions.selectAll,
979
+ deselectAll: actions.deselectAll,
980
+ isSelected: (id) => state.selectedIds.has(id)
981
+ }),
982
+ [state.selectedIds, computed.allSelected, computed.someSelected, actions]
983
+ );
984
+ const expansion = (0, import_react7.useMemo)(
985
+ () => ({
986
+ expandedIds: state.expandedIds,
987
+ expandRow: actions.expandRow,
988
+ collapseRow: actions.collapseRow,
989
+ toggleRow: actions.toggleRowExpansion,
990
+ isExpanded: (id) => state.expandedIds.has(id)
991
+ }),
992
+ [state.expandedIds, actions]
993
+ );
994
+ const columnsApi = (0, import_react7.useMemo)(
995
+ () => ({
996
+ states: state.columnStates,
997
+ reorder: actions.reorderColumn,
998
+ resize: actions.resizeColumn,
999
+ toggleVisibility: actions.toggleColumnVisibility,
1000
+ reset: actions.resetColumns,
1001
+ getWidth: (columnId) => {
1002
+ var _a;
1003
+ const colState = state.columnStates.find((c) => c.id === columnId);
1004
+ return (_a = colState == null ? void 0 : colState.width) != null ? _a : 150;
1005
+ },
1006
+ isVisible: (columnId) => {
1007
+ const colState = state.columnStates.find((c) => c.id === columnId);
1008
+ return (colState == null ? void 0 : colState.visible) !== false;
1009
+ }
1010
+ }),
1011
+ [state.columnStates, actions]
1012
+ );
1013
+ const mobile = (0, import_react7.useMemo)(
1014
+ () => ({
1015
+ showDrawer: state.showMobileDrawer,
1016
+ drawerContent: state.mobileDrawerContent,
1017
+ openDrawer: actions.openMobileDrawer,
1018
+ closeDrawer: actions.closeMobileDrawer
1019
+ }),
1020
+ [state.showMobileDrawer, state.mobileDrawerContent, actions]
1021
+ );
1022
+ return (0, import_react7.useMemo)(
1023
+ () => ({
1024
+ data: state.data,
1025
+ filteredData: computed.filteredData,
1026
+ sortedData: computed.sortedData,
1027
+ paginatedData: computed.paginatedData,
1028
+ columns: state.columns,
1029
+ visibleColumns: computed.visibleColumns,
1030
+ loading: state.loading,
1031
+ error: state.error,
1032
+ isEmpty: computed.paginatedData.length === 0 && !state.loading,
1033
+ sort,
1034
+ filter,
1035
+ pagination,
1036
+ dragDrop,
1037
+ breakpoint,
1038
+ selection,
1039
+ expansion,
1040
+ columnApi: columnsApi,
1041
+ mobile,
1042
+ theme: state.theme,
1043
+ translations: state.translations,
1044
+ refresh: actions.refresh,
1045
+ reset: actions.reset
1046
+ }),
1047
+ [state, computed, sort, filter, pagination, dragDrop, breakpoint, selection, expansion, columnsApi, mobile, actions]
1048
+ );
1049
+ }
1050
+
1051
+ // src/components/GridHeader/GridHeader.tsx
1052
+ var import_react9 = require("react");
1053
+
1054
+ // src/components/FilterPopup/FilterPopup.tsx
1055
+ var import_react8 = require("react");
1056
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1057
+ var TEXT_OPERATORS = ["contains", "equals", "startsWith", "endsWith", "notContains", "notEquals"];
1058
+ var NUMBER_OPERATORS = ["equals", "notEquals", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual"];
1059
+ var OPERATOR_LABELS = {
1060
+ equals: "Equals",
1061
+ notEquals: "Not equals",
1062
+ contains: "Contains",
1063
+ notContains: "Not contains",
1064
+ startsWith: "Starts with",
1065
+ endsWith: "Ends with",
1066
+ greaterThan: "Greater than",
1067
+ lessThan: "Less than",
1068
+ greaterThanOrEqual: "Greater or equal",
1069
+ lessThanOrEqual: "Less or equal",
1070
+ between: "Between",
1071
+ isEmpty: "Is empty",
1072
+ isNotEmpty: "Is not empty"
1073
+ };
1074
+ function FilterPopup({
1075
+ columnId,
1076
+ columnHeader,
1077
+ filterType = "text",
1078
+ filterOptions,
1079
+ currentValue,
1080
+ currentOperator = "contains",
1081
+ position,
1082
+ onApply,
1083
+ onClear,
1084
+ onClose,
1085
+ className = "",
1086
+ style
1087
+ }) {
1088
+ var _a, _b;
1089
+ const { state } = useTableContext();
1090
+ const { translations } = state;
1091
+ const popupRef = (0, import_react8.useRef)(null);
1092
+ const [value, setValue] = (0, import_react8.useState)(currentValue ? String(currentValue) : "");
1093
+ const [operator, setOperator] = (0, import_react8.useState)(currentOperator);
1094
+ const operators = filterType === "number" ? NUMBER_OPERATORS : TEXT_OPERATORS;
1095
+ (0, import_react8.useEffect)(() => {
1096
+ const handleClickOutside = (event) => {
1097
+ if (popupRef.current && !popupRef.current.contains(event.target)) {
1098
+ onClose();
1099
+ }
1100
+ };
1101
+ const handleEscape = (event) => {
1102
+ if (event.key === "Escape") {
1103
+ onClose();
1104
+ }
1105
+ };
1106
+ document.addEventListener("mousedown", handleClickOutside);
1107
+ document.addEventListener("keydown", handleEscape);
1108
+ return () => {
1109
+ document.removeEventListener("mousedown", handleClickOutside);
1110
+ document.removeEventListener("keydown", handleEscape);
1111
+ };
1112
+ }, [onClose]);
1113
+ const handleApply = (0, import_react8.useCallback)(() => {
1114
+ if (value.trim()) {
1115
+ onApply(filterType === "number" ? Number(value) : value, operator);
1116
+ }
1117
+ onClose();
1118
+ }, [value, operator, filterType, onApply, onClose]);
1119
+ const handleClear = (0, import_react8.useCallback)(() => {
1120
+ setValue("");
1121
+ onClear();
1122
+ onClose();
1123
+ }, [onClear, onClose]);
1124
+ const handleKeyDown = (0, import_react8.useCallback)(
1125
+ (e) => {
1126
+ if (e.key === "Enter") {
1127
+ handleApply();
1128
+ }
1129
+ },
1130
+ [handleApply]
1131
+ );
1132
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1133
+ "div",
1134
+ {
1135
+ ref: popupRef,
1136
+ className: `filter-popup absolute z-50 bg-theme-primary border border-theme-border rounded-lg shadow-xl min-w-[280px] ${className}`,
1137
+ style: {
1138
+ top: (_a = position == null ? void 0 : position.top) != null ? _a : "100%",
1139
+ left: (_b = position == null ? void 0 : position.left) != null ? _b : 0,
1140
+ marginTop: 4,
1141
+ ...style
1142
+ },
1143
+ children: [
1144
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "filter-popup-header px-4 py-3 border-b border-theme-border", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
1145
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium text-theme-primary", children: columnHeader }),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1147
+ "button",
1148
+ {
1149
+ onClick: onClose,
1150
+ className: "p-1 rounded hover:bg-theme-hover text-theme-muted",
1151
+ "aria-label": "Close",
1152
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
1153
+ }
1154
+ )
1155
+ ] }) }),
1156
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "filter-popup-body p-4 space-y-4", children: filterType === "select" && filterOptions ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1157
+ "select",
1158
+ {
1159
+ value: String(value),
1160
+ onChange: (e) => setValue(e.target.value),
1161
+ className: "w-full px-3 py-2 text-sm rounded border border-theme-border bg-theme-secondary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary",
1162
+ children: [
1163
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "Select..." }),
1164
+ filterOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
1165
+ ]
1166
+ }
1167
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1168
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1169
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs text-theme-muted mb-1", children: "Operator" }),
1170
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1171
+ "select",
1172
+ {
1173
+ value: operator,
1174
+ onChange: (e) => setOperator(e.target.value),
1175
+ className: "w-full px-3 py-2 text-sm rounded border border-theme-border bg-theme-secondary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary",
1176
+ children: operators.map((op) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: op, children: OPERATOR_LABELS[op] }, op))
1177
+ }
1178
+ )
1179
+ ] }),
1180
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1181
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "block text-xs text-theme-muted mb-1", children: "Value" }),
1182
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1183
+ "input",
1184
+ {
1185
+ type: filterType === "number" ? "number" : "text",
1186
+ value,
1187
+ onChange: (e) => setValue(e.target.value),
1188
+ onKeyDown: handleKeyDown,
1189
+ placeholder: `Filter ${columnHeader}...`,
1190
+ className: "w-full px-3 py-2 text-sm rounded border border-theme-border bg-theme-secondary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary",
1191
+ autoFocus: true
1192
+ }
1193
+ )
1194
+ ] })
1195
+ ] }) }),
1196
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "filter-popup-footer px-4 py-3 border-t border-theme-border flex items-center justify-between", children: [
1197
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1198
+ "button",
1199
+ {
1200
+ onClick: handleClear,
1201
+ className: "px-3 py-1.5 text-sm text-theme-muted hover:text-theme-primary transition-colors",
1202
+ children: translations.clearFilter
1203
+ }
1204
+ ),
1205
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1206
+ "button",
1207
+ {
1208
+ onClick: handleApply,
1209
+ className: "px-4 py-1.5 text-sm bg-accent-primary text-white rounded hover:opacity-90 transition-opacity",
1210
+ children: translations.apply
1211
+ }
1212
+ )
1213
+ ] })
1214
+ ]
1215
+ }
1216
+ );
1217
+ }
1218
+
1219
+ // src/components/GridHeader/GridHeader.tsx
1220
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1221
+ var FilterIcon = ({ active = false }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1222
+ "svg",
1223
+ {
1224
+ className: `w-3.5 h-3.5 ${active ? "text-accent-primary" : "text-theme-muted"}`,
1225
+ fill: "none",
1226
+ viewBox: "0 0 24 24",
1227
+ stroke: "currentColor",
1228
+ strokeWidth: 2,
1229
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1230
+ "path",
1231
+ {
1232
+ strokeLinecap: "round",
1233
+ strokeLinejoin: "round",
1234
+ d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
1235
+ }
1236
+ )
1237
+ }
1238
+ );
1239
+ var SortIcon = ({ direction }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1240
+ "svg",
1241
+ {
1242
+ className: `w-3.5 h-3.5 ${direction ? "text-accent-primary" : "text-theme-muted"}`,
1243
+ fill: "none",
1244
+ viewBox: "0 0 24 24",
1245
+ stroke: "currentColor",
1246
+ strokeWidth: 2,
1247
+ children: direction === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 15l7-7 7 7" }) : direction === "desc" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" })
1248
+ }
1249
+ );
1250
+ var ALIGN_CLASSES = {
1251
+ left: "text-left justify-start",
1252
+ center: "text-center justify-center",
1253
+ right: "text-right justify-end"
1254
+ };
1255
+ function HeaderCell({
1256
+ column,
1257
+ columnState,
1258
+ sortDirection,
1259
+ sortIndex,
1260
+ isMultiSort = false,
1261
+ enableSort = true,
1262
+ enableFilter = true,
1263
+ enableDragDrop = true,
1264
+ enableResize = true,
1265
+ hasFilter = false,
1266
+ isDragging = false,
1267
+ isDragOver = false,
1268
+ onSort,
1269
+ onFilterOpen,
1270
+ onResizeStart,
1271
+ dragHandleProps,
1272
+ dropTargetProps
1273
+ }) {
1274
+ const isSortable = enableSort && column.sortable !== false;
1275
+ const isFilterable = enableFilter && column.filterable !== false;
1276
+ const isDraggable = enableDragDrop && column.draggable !== false;
1277
+ const isResizable = enableResize && column.resizable !== false;
1278
+ const headerContent = (0, import_react9.useMemo)(() => {
1279
+ if (typeof column.header === "function") {
1280
+ return column.header();
1281
+ }
1282
+ return column.header;
1283
+ }, [column.header]);
1284
+ const handleClick = (0, import_react9.useCallback)(() => {
1285
+ if (isSortable) {
1286
+ onSort == null ? void 0 : onSort();
1287
+ }
1288
+ }, [isSortable, onSort]);
1289
+ const handleFilterClick = (0, import_react9.useCallback)(
1290
+ (e) => {
1291
+ e.stopPropagation();
1292
+ onFilterOpen == null ? void 0 : onFilterOpen();
1293
+ },
1294
+ [onFilterOpen]
1295
+ );
1296
+ const cellClasses = (0, import_react9.useMemo)(() => {
1297
+ const classes = [
1298
+ "grid-header-cell",
1299
+ "relative",
1300
+ "flex",
1301
+ "items-center",
1302
+ "gap-2",
1303
+ "px-4",
1304
+ "py-3",
1305
+ "font-medium",
1306
+ "text-sm",
1307
+ "text-theme-secondary",
1308
+ "select-none",
1309
+ "border-b",
1310
+ "border-theme-border",
1311
+ "transition-colors",
1312
+ ALIGN_CLASSES[column.align || "left"]
1313
+ ];
1314
+ if (isSortable) {
1315
+ classes.push("cursor-pointer", "hover:text-theme-primary", "hover:bg-theme-hover");
1316
+ }
1317
+ if (isDragging) {
1318
+ classes.push("opacity-50");
1319
+ }
1320
+ if (isDragOver) {
1321
+ classes.push("bg-accent-primary/10", "border-l-2", "border-l-accent-primary");
1322
+ }
1323
+ return classes.join(" ");
1324
+ }, [column.align, isSortable, isDragging, isDragOver]);
1325
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1326
+ "div",
1327
+ {
1328
+ className: `${cellClasses} ${column.headerClassName || ""} ${column.sticky ? "shadow-[2px_0_4px_-2px_rgba(0,0,0,0.2)]" : ""}`,
1329
+ style: {
1330
+ width: columnState.width,
1331
+ minWidth: column.minWidth || MIN_COLUMN_WIDTH,
1332
+ maxWidth: column.maxWidth || MAX_COLUMN_WIDTH,
1333
+ flexShrink: 0,
1334
+ ...column.sticky && {
1335
+ position: "sticky",
1336
+ [column.sticky]: 0,
1337
+ zIndex: 2,
1338
+ backgroundColor: "var(--bg-secondary, #2b2b2b)"
1339
+ },
1340
+ ...column.headerStyle
1341
+ },
1342
+ role: "columnheader",
1343
+ "aria-sort": sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : "none",
1344
+ onClick: handleClick,
1345
+ ...isDraggable ? { ...dragHandleProps, ...dropTargetProps } : {},
1346
+ children: [
1347
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "grid-header-content truncate flex-1", children: headerContent }),
1348
+ isSortable && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "grid-header-sort flex items-center gap-0.5", children: [
1349
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SortIcon, { direction: sortDirection != null ? sortDirection : null }),
1350
+ isMultiSort && sortIndex !== void 0 && sortIndex >= 0 && sortDirection && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-xs text-theme-muted", children: sortIndex + 1 })
1351
+ ] }),
1352
+ isFilterable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1353
+ "button",
1354
+ {
1355
+ onClick: handleFilterClick,
1356
+ className: "grid-header-filter p-1 rounded hover:bg-theme-tertiary",
1357
+ "aria-label": "Filter column",
1358
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FilterIcon, { active: hasFilter })
1359
+ }
1360
+ ),
1361
+ isResizable && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1362
+ "div",
1363
+ {
1364
+ className: "grid-header-resize absolute right-0 top-0 bottom-0 w-1 cursor-col-resize hover:bg-accent-primary",
1365
+ onMouseDown: onResizeStart,
1366
+ onClick: (e) => e.stopPropagation()
1367
+ }
1368
+ )
1369
+ ]
1370
+ }
1371
+ );
1372
+ }
1373
+ function GridHeader({
1374
+ columns,
1375
+ columnStates,
1376
+ className = "",
1377
+ style,
1378
+ sticky = true,
1379
+ enableSort = true,
1380
+ enableFilter = true,
1381
+ enableDragDrop = true,
1382
+ enableResize = true,
1383
+ enableSelection = false,
1384
+ allSelected = false,
1385
+ someSelected = false,
1386
+ onSelectAll,
1387
+ onSort,
1388
+ onFilterOpen,
1389
+ getSortDirection
1390
+ }) {
1391
+ const { state, actions } = useTableContext();
1392
+ const dragDrop = useDragDrop();
1393
+ const [resizingColumn, setResizingColumn] = (0, import_react9.useState)(null);
1394
+ const [activeFilterColumn, setActiveFilterColumn] = (0, import_react9.useState)(null);
1395
+ const filterButtonRefs = (0, import_react9.useRef)(/* @__PURE__ */ new Map());
1396
+ const resizeStartX = (0, import_react9.useRef)(0);
1397
+ const resizeStartWidth = (0, import_react9.useRef)(0);
1398
+ const handleFilterClick = (0, import_react9.useCallback)((columnId) => {
1399
+ setActiveFilterColumn(activeFilterColumn === columnId ? null : columnId);
1400
+ }, [activeFilterColumn]);
1401
+ const handleFilterApply = (0, import_react9.useCallback)((columnId, value, operator) => {
1402
+ actions.setFilter(columnId, value, operator);
1403
+ setActiveFilterColumn(null);
1404
+ }, [actions]);
1405
+ const handleFilterClear = (0, import_react9.useCallback)((columnId) => {
1406
+ actions.removeFilter(columnId);
1407
+ setActiveFilterColumn(null);
1408
+ }, [actions]);
1409
+ const handleFilterClose = (0, import_react9.useCallback)(() => {
1410
+ setActiveFilterColumn(null);
1411
+ }, []);
1412
+ const visibleColumns = (0, import_react9.useMemo)(() => {
1413
+ return columns.filter((col) => {
1414
+ const colState = columnStates.find((cs) => cs.id === col.id);
1415
+ return (colState == null ? void 0 : colState.visible) !== false;
1416
+ }).sort((a, b) => {
1417
+ var _a, _b;
1418
+ const aState = columnStates.find((cs) => cs.id === a.id);
1419
+ const bState = columnStates.find((cs) => cs.id === b.id);
1420
+ return ((_a = aState == null ? void 0 : aState.order) != null ? _a : 0) - ((_b = bState == null ? void 0 : bState.order) != null ? _b : 0);
1421
+ });
1422
+ }, [columns, columnStates]);
1423
+ const handleResizeStart = (0, import_react9.useCallback)(
1424
+ (columnId, currentWidth) => (event) => {
1425
+ event.preventDefault();
1426
+ setResizingColumn(columnId);
1427
+ resizeStartX.current = event.clientX;
1428
+ resizeStartWidth.current = currentWidth;
1429
+ const handleMouseMove = (e) => {
1430
+ const delta = e.clientX - resizeStartX.current;
1431
+ const newWidth = Math.max(
1432
+ MIN_COLUMN_WIDTH,
1433
+ Math.min(MAX_COLUMN_WIDTH, resizeStartWidth.current + delta)
1434
+ );
1435
+ actions.resizeColumn(columnId, newWidth);
1436
+ };
1437
+ const handleMouseUp = () => {
1438
+ setResizingColumn(null);
1439
+ document.removeEventListener("mousemove", handleMouseMove);
1440
+ document.removeEventListener("mouseup", handleMouseUp);
1441
+ };
1442
+ document.addEventListener("mousemove", handleMouseMove);
1443
+ document.addEventListener("mouseup", handleMouseUp);
1444
+ },
1445
+ [actions]
1446
+ );
1447
+ const headerClasses = (0, import_react9.useMemo)(() => {
1448
+ const classes = ["grid-header", "flex", "bg-theme-secondary"];
1449
+ if (sticky) {
1450
+ classes.push("sticky", "top-0", "z-10");
1451
+ }
1452
+ return classes.join(" ");
1453
+ }, [sticky]);
1454
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `${headerClasses} ${className}`, style, role: "row", children: [
1455
+ enableSelection && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "grid-header-select flex items-center px-2 border-b border-theme-border", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1456
+ "input",
1457
+ {
1458
+ type: "checkbox",
1459
+ checked: allSelected,
1460
+ ref: (el) => {
1461
+ if (el) el.indeterminate = someSelected && !allSelected;
1462
+ },
1463
+ onChange: onSelectAll,
1464
+ className: "w-4 h-4 rounded border-theme-border",
1465
+ "aria-label": "Select all rows"
1466
+ }
1467
+ ) }),
1468
+ visibleColumns.map((col, index) => {
1469
+ const colState = columnStates.find((cs) => cs.id === col.id) || {
1470
+ id: col.id,
1471
+ visible: true,
1472
+ width: 150,
1473
+ order: index,
1474
+ pinned: null
1475
+ };
1476
+ const sortDir = getSortDirection ? getSortDirection(col.id) : null;
1477
+ const sortIdx = state.sorting.findIndex((s) => s.columnId === col.id);
1478
+ const hasFilter = state.filters.some((f) => f.columnId === col.id);
1479
+ const existingFilter = state.filters.find((f) => f.columnId === col.id);
1480
+ const headerText = typeof col.header === "string" ? col.header : col.id;
1481
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative", children: [
1482
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1483
+ HeaderCell,
1484
+ {
1485
+ column: col,
1486
+ columnState: colState,
1487
+ sortDirection: sortDir,
1488
+ sortIndex: sortIdx,
1489
+ isMultiSort: state.sorting.length > 1,
1490
+ enableSort,
1491
+ enableFilter,
1492
+ enableDragDrop,
1493
+ enableResize,
1494
+ hasFilter,
1495
+ isDragging: dragDrop.draggingColumnId === col.id,
1496
+ isDragOver: dragDrop.dragOverColumnId === col.id,
1497
+ onSort: () => actions.toggleSorting(col.id),
1498
+ onFilterOpen: () => handleFilterClick(col.id),
1499
+ onResizeStart: handleResizeStart(col.id, colState.width),
1500
+ dragHandleProps: dragDrop.getDragHandleProps(col.id),
1501
+ dropTargetProps: dragDrop.getDropTargetProps(col.id)
1502
+ }
1503
+ ),
1504
+ activeFilterColumn === col.id && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1505
+ FilterPopup,
1506
+ {
1507
+ columnId: col.id,
1508
+ columnHeader: headerText,
1509
+ filterType: col.filterType || "text",
1510
+ filterOptions: col.filterOptions,
1511
+ currentValue: existingFilter == null ? void 0 : existingFilter.value,
1512
+ currentOperator: existingFilter == null ? void 0 : existingFilter.operator,
1513
+ onApply: (value, operator) => handleFilterApply(col.id, value, operator),
1514
+ onClear: () => handleFilterClear(col.id),
1515
+ onClose: handleFilterClose
1516
+ }
1517
+ )
1518
+ ] }, col.id);
1519
+ })
1520
+ ] });
1521
+ }
1522
+
1523
+ // src/components/GridBody/GridBody.tsx
1524
+ var import_react12 = require("react");
1525
+
1526
+ // src/components/GridRow/GridRow.tsx
1527
+ var import_react11 = require("react");
1528
+
1529
+ // src/components/GridCell/GridCell.tsx
1530
+ var import_react10 = require("react");
1531
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1532
+ var ALIGN_CLASSES2 = {
1533
+ left: "text-left justify-start",
1534
+ center: "text-center justify-center",
1535
+ right: "text-right justify-end"
1536
+ };
1537
+ function GridCell({
1538
+ column,
1539
+ row,
1540
+ rowIndex,
1541
+ value,
1542
+ width,
1543
+ align = "left",
1544
+ className = "",
1545
+ style,
1546
+ showLabel = false,
1547
+ labelText,
1548
+ sticky,
1549
+ stickyOffset = 0,
1550
+ onClick
1551
+ }) {
1552
+ const handleClick = (0, import_react10.useCallback)(
1553
+ (e) => {
1554
+ if (onClick) {
1555
+ e.stopPropagation();
1556
+ onClick({
1557
+ row,
1558
+ rowIndex,
1559
+ columnId: column.id,
1560
+ value
1561
+ });
1562
+ }
1563
+ },
1564
+ [onClick, row, rowIndex, column.id, value]
1565
+ );
1566
+ const formattedValue = (0, import_react10.useMemo)(() => {
1567
+ if (column.render) {
1568
+ return column.render(value, row, rowIndex);
1569
+ }
1570
+ if (value === null || value === void 0) {
1571
+ return "-";
1572
+ }
1573
+ if (typeof value === "boolean") {
1574
+ return value ? "Yes" : "No";
1575
+ }
1576
+ if (value instanceof Date) {
1577
+ return value.toLocaleDateString();
1578
+ }
1579
+ return String(value);
1580
+ }, [column, row, rowIndex, value]);
1581
+ const cellStyle = (0, import_react10.useMemo)(() => {
1582
+ const baseStyle = { ...style };
1583
+ if (width !== void 0) {
1584
+ baseStyle.width = typeof width === "number" ? `${width}px` : width;
1585
+ baseStyle.minWidth = baseStyle.width;
1586
+ baseStyle.maxWidth = baseStyle.width;
1587
+ }
1588
+ if (sticky) {
1589
+ baseStyle.position = "sticky";
1590
+ baseStyle.zIndex = 1;
1591
+ baseStyle.backgroundColor = "var(--bg-primary, #1e1e1e)";
1592
+ if (sticky === "left") {
1593
+ baseStyle.left = stickyOffset;
1594
+ } else if (sticky === "right") {
1595
+ baseStyle.right = stickyOffset;
1596
+ }
1597
+ }
1598
+ return baseStyle;
1599
+ }, [style, width, sticky, stickyOffset]);
1600
+ const alignClass = ALIGN_CLASSES2[align];
1601
+ const stickyClasses = sticky ? "shadow-[2px_0_4px_-2px_rgba(0,0,0,0.2)]" : "";
1602
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1603
+ "div",
1604
+ {
1605
+ className: `
1606
+ grid-cell
1607
+ px-4 py-3
1608
+ flex items-center
1609
+ ${alignClass}
1610
+ ${stickyClasses}
1611
+ ${onClick ? "cursor-pointer hover:bg-theme-hover" : ""}
1612
+ ${column.cellClassName || ""}
1613
+ ${className}
1614
+ `.trim(),
1615
+ style: { ...cellStyle, ...column.cellStyle },
1616
+ role: "cell",
1617
+ onClick: onClick ? handleClick : void 0,
1618
+ children: [
1619
+ showLabel && labelText && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "grid-cell-label font-medium text-theme-muted mr-2 text-sm", children: [
1620
+ labelText,
1621
+ ":"
1622
+ ] }),
1623
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "grid-cell-value truncate", children: formattedValue })
1624
+ ]
1625
+ }
1626
+ );
1627
+ }
1628
+
1629
+ // src/components/GridRow/GridRow.tsx
1630
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1631
+ function GridRow({
1632
+ row,
1633
+ rowIndex,
1634
+ columns,
1635
+ columnStates,
1636
+ isSelected = false,
1637
+ isExpanded = false,
1638
+ isDisabled = false,
1639
+ isMobile = false,
1640
+ showMobileLabels = true,
1641
+ className = "",
1642
+ style,
1643
+ onClick,
1644
+ onDoubleClick,
1645
+ onContextMenu,
1646
+ onCellClick,
1647
+ onSelect,
1648
+ onExpand,
1649
+ enableSelection = false,
1650
+ enableExpansion = false,
1651
+ renderExpansion,
1652
+ getRowId
1653
+ }) {
1654
+ const [isHovered, setIsHovered] = (0, import_react11.useState)(false);
1655
+ const handleClick = (0, import_react11.useCallback)(() => {
1656
+ if (isDisabled) return;
1657
+ onClick == null ? void 0 : onClick(row, rowIndex);
1658
+ }, [onClick, row, rowIndex, isDisabled]);
1659
+ const handleDoubleClick = (0, import_react11.useCallback)(() => {
1660
+ if (isDisabled) return;
1661
+ onDoubleClick == null ? void 0 : onDoubleClick(row, rowIndex);
1662
+ }, [onDoubleClick, row, rowIndex, isDisabled]);
1663
+ const handleContextMenu = (0, import_react11.useCallback)(
1664
+ (event) => {
1665
+ if (isDisabled) return;
1666
+ onContextMenu == null ? void 0 : onContextMenu(row, rowIndex, event);
1667
+ },
1668
+ [onContextMenu, row, rowIndex, isDisabled]
1669
+ );
1670
+ const handleSelectChange = (0, import_react11.useCallback)(() => {
1671
+ if (isDisabled) return;
1672
+ onSelect == null ? void 0 : onSelect(!isSelected);
1673
+ }, [onSelect, isSelected, isDisabled]);
1674
+ const handleExpandToggle = (0, import_react11.useCallback)(() => {
1675
+ if (isDisabled) return;
1676
+ onExpand == null ? void 0 : onExpand(!isExpanded);
1677
+ }, [onExpand, isExpanded, isDisabled]);
1678
+ const visibleColumns = (0, import_react11.useMemo)(() => {
1679
+ return columns.filter((col) => {
1680
+ const state = columnStates.find((cs) => cs.id === col.id);
1681
+ if ((state == null ? void 0 : state.visible) === false) return false;
1682
+ if (isMobile && col.hiddenOnMobile) return false;
1683
+ return true;
1684
+ }).sort((a, b) => {
1685
+ var _a, _b;
1686
+ const aState = columnStates.find((cs) => cs.id === a.id);
1687
+ const bState = columnStates.find((cs) => cs.id === b.id);
1688
+ return ((_a = aState == null ? void 0 : aState.order) != null ? _a : 0) - ((_b = bState == null ? void 0 : bState.order) != null ? _b : 0);
1689
+ });
1690
+ }, [columns, columnStates, isMobile]);
1691
+ const getCellValue = (0, import_react11.useCallback)(
1692
+ (col) => {
1693
+ const accessor = col.accessor;
1694
+ if (typeof accessor === "function") {
1695
+ return accessor(row);
1696
+ }
1697
+ return row[accessor];
1698
+ },
1699
+ [row]
1700
+ );
1701
+ const rowClasses = (0, import_react11.useMemo)(() => {
1702
+ const classes = [
1703
+ "grid-row",
1704
+ "border-b",
1705
+ "border-theme-border",
1706
+ "transition-colors",
1707
+ "duration-150"
1708
+ ];
1709
+ if (isHovered && !isDisabled) {
1710
+ classes.push("bg-theme-hover");
1711
+ }
1712
+ if (isSelected) {
1713
+ classes.push("bg-accent-primary/10");
1714
+ }
1715
+ if (isDisabled) {
1716
+ classes.push("opacity-50", "cursor-not-allowed");
1717
+ } else if (onClick) {
1718
+ classes.push("cursor-pointer");
1719
+ }
1720
+ if (isMobile) {
1721
+ classes.push("flex", "flex-wrap", "gap-2", "p-4");
1722
+ } else {
1723
+ classes.push("flex", "items-stretch");
1724
+ }
1725
+ return classes.join(" ");
1726
+ }, [isHovered, isSelected, isDisabled, onClick, isMobile]);
1727
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1728
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1729
+ "div",
1730
+ {
1731
+ className: `${rowClasses} ${className}`,
1732
+ style,
1733
+ role: "row",
1734
+ "aria-selected": isSelected,
1735
+ "aria-disabled": isDisabled,
1736
+ onClick: handleClick,
1737
+ onDoubleClick: handleDoubleClick,
1738
+ onContextMenu: handleContextMenu,
1739
+ onMouseEnter: () => setIsHovered(true),
1740
+ onMouseLeave: () => setIsHovered(false),
1741
+ children: [
1742
+ enableSelection && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid-row-select flex items-center px-2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1743
+ "input",
1744
+ {
1745
+ type: "checkbox",
1746
+ checked: isSelected,
1747
+ onChange: handleSelectChange,
1748
+ disabled: isDisabled,
1749
+ className: "w-4 h-4 rounded border-theme-border",
1750
+ "aria-label": "Select row"
1751
+ }
1752
+ ) }),
1753
+ enableExpansion && renderExpansion && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid-row-expand flex items-center px-2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1754
+ "button",
1755
+ {
1756
+ onClick: handleExpandToggle,
1757
+ disabled: isDisabled,
1758
+ className: "w-6 h-6 flex items-center justify-center rounded hover:bg-theme-tertiary",
1759
+ "aria-label": isExpanded ? "Collapse row" : "Expand row",
1760
+ "aria-expanded": isExpanded,
1761
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1762
+ "span",
1763
+ {
1764
+ className: `transform transition-transform duration-200 ${isExpanded ? "rotate-90" : ""}`,
1765
+ children: ">"
1766
+ }
1767
+ )
1768
+ }
1769
+ ) }),
1770
+ visibleColumns.map((col, colIndex) => {
1771
+ var _a, _b;
1772
+ const colState = columnStates.find((cs) => cs.id === col.id);
1773
+ const width = isMobile ? "100%" : colState == null ? void 0 : colState.width;
1774
+ let stickyOffset = 0;
1775
+ if (col.sticky === "left") {
1776
+ for (let i = 0; i < colIndex; i++) {
1777
+ const prevCol = visibleColumns[i];
1778
+ if (prevCol.sticky === "left") {
1779
+ const prevState = columnStates.find((cs) => cs.id === prevCol.id);
1780
+ stickyOffset += (_a = prevState == null ? void 0 : prevState.width) != null ? _a : 150;
1781
+ }
1782
+ }
1783
+ }
1784
+ if (col.sticky === "right") {
1785
+ for (let i = visibleColumns.length - 1; i > colIndex; i--) {
1786
+ const nextCol = visibleColumns[i];
1787
+ if (nextCol.sticky === "right") {
1788
+ const nextState = columnStates.find((cs) => cs.id === nextCol.id);
1789
+ stickyOffset += (_b = nextState == null ? void 0 : nextState.width) != null ? _b : 150;
1790
+ }
1791
+ }
1792
+ }
1793
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1794
+ GridCell,
1795
+ {
1796
+ column: col,
1797
+ row,
1798
+ rowIndex,
1799
+ value: getCellValue(col),
1800
+ width,
1801
+ align: col.align,
1802
+ showLabel: isMobile && showMobileLabels && col.showLabelOnMobile !== false,
1803
+ labelText: typeof col.header === "string" ? col.header : col.id,
1804
+ className: isMobile ? "w-full sm:w-auto flex-shrink-0" : "flex-shrink-0",
1805
+ sticky: col.sticky,
1806
+ stickyOffset,
1807
+ onClick: onCellClick
1808
+ },
1809
+ col.id
1810
+ );
1811
+ })
1812
+ ]
1813
+ }
1814
+ ),
1815
+ isExpanded && renderExpansion && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grid-row-expansion border-b border-theme-border bg-theme-secondary p-4", children: renderExpansion(row) })
1816
+ ] });
1817
+ }
1818
+
1819
+ // src/components/GridBody/GridBody.tsx
1820
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1821
+ function GridBody({
1822
+ data,
1823
+ columns,
1824
+ columnStates,
1825
+ className = "",
1826
+ style,
1827
+ isMobile = false,
1828
+ showMobileLabels = true,
1829
+ enableSelection = false,
1830
+ enableExpansion = false,
1831
+ selectedIds = /* @__PURE__ */ new Set(),
1832
+ expandedIds = /* @__PURE__ */ new Set(),
1833
+ onRowClick,
1834
+ onRowDoubleClick,
1835
+ onCellClick,
1836
+ onRowSelect,
1837
+ onRowExpand,
1838
+ getRowId,
1839
+ getRowClassName,
1840
+ getRowStyle,
1841
+ isRowDisabled,
1842
+ renderRowExpansion
1843
+ }) {
1844
+ const handleRowSelect = (0, import_react12.useCallback)(
1845
+ (row) => (selected) => {
1846
+ const id = getRowId(row);
1847
+ onRowSelect == null ? void 0 : onRowSelect(id, selected);
1848
+ },
1849
+ [getRowId, onRowSelect]
1850
+ );
1851
+ const handleRowExpand = (0, import_react12.useCallback)(
1852
+ (row) => (expanded) => {
1853
+ const id = getRowId(row);
1854
+ onRowExpand == null ? void 0 : onRowExpand(id, expanded);
1855
+ },
1856
+ [getRowId, onRowExpand]
1857
+ );
1858
+ if (data.length === 0) {
1859
+ return null;
1860
+ }
1861
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: `grid-body ${className}`, style, role: "rowgroup", children: data.map((row, index) => {
1862
+ var _a, _b;
1863
+ const rowId = getRowId(row);
1864
+ const isSelected = selectedIds.has(rowId);
1865
+ const isExpanded = expandedIds.has(rowId);
1866
+ const isDisabled = (_a = isRowDisabled == null ? void 0 : isRowDisabled(row)) != null ? _a : false;
1867
+ const rowClassName = (_b = getRowClassName == null ? void 0 : getRowClassName(row, index)) != null ? _b : "";
1868
+ const rowStyle = getRowStyle == null ? void 0 : getRowStyle(row, index);
1869
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1870
+ GridRow,
1871
+ {
1872
+ row,
1873
+ rowIndex: index,
1874
+ columns,
1875
+ columnStates,
1876
+ isSelected,
1877
+ isExpanded,
1878
+ isDisabled,
1879
+ isMobile,
1880
+ showMobileLabels,
1881
+ className: rowClassName,
1882
+ style: rowStyle,
1883
+ onClick: onRowClick,
1884
+ onDoubleClick: onRowDoubleClick,
1885
+ onCellClick,
1886
+ onSelect: handleRowSelect(row),
1887
+ onExpand: handleRowExpand(row),
1888
+ enableSelection,
1889
+ enableExpansion: enableExpansion && !!renderRowExpansion,
1890
+ renderExpansion: renderRowExpansion,
1891
+ getRowId
1892
+ },
1893
+ rowId
1894
+ );
1895
+ }) });
1896
+ }
1897
+
1898
+ // src/components/Pagination/Pagination.tsx
1899
+ var import_react13 = require("react");
1900
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1901
+ function Pagination({
1902
+ page,
1903
+ pageSize,
1904
+ totalItems,
1905
+ totalPages,
1906
+ pageSizeOptions = [10, 20, 50, 100],
1907
+ showFirstLast = true,
1908
+ showPageNumbers = true,
1909
+ maxPageButtons = FIVE,
1910
+ className = "",
1911
+ style,
1912
+ onPageChange,
1913
+ onPageSizeChange
1914
+ }) {
1915
+ const { state } = useTableContext();
1916
+ const { translations } = state;
1917
+ const canGoPrevious = page > ONE;
1918
+ const canGoNext = page < totalPages;
1919
+ const startItem = (page - ONE) * pageSize + ONE;
1920
+ const endItem = Math.min(page * pageSize, totalItems);
1921
+ const handleFirstPage = (0, import_react13.useCallback)(() => {
1922
+ onPageChange(ONE);
1923
+ }, [onPageChange]);
1924
+ const handlePreviousPage = (0, import_react13.useCallback)(() => {
1925
+ if (canGoPrevious) {
1926
+ onPageChange(page - ONE);
1927
+ }
1928
+ }, [canGoPrevious, page, onPageChange]);
1929
+ const handleNextPage = (0, import_react13.useCallback)(() => {
1930
+ if (canGoNext) {
1931
+ onPageChange(page + ONE);
1932
+ }
1933
+ }, [canGoNext, page, onPageChange]);
1934
+ const handleLastPage = (0, import_react13.useCallback)(() => {
1935
+ onPageChange(totalPages);
1936
+ }, [onPageChange, totalPages]);
1937
+ const handlePageSizeChange = (0, import_react13.useCallback)(
1938
+ (event) => {
1939
+ onPageSizeChange(Number(event.target.value));
1940
+ },
1941
+ [onPageSizeChange]
1942
+ );
1943
+ const pageNumbers = (0, import_react13.useMemo)(() => {
1944
+ if (!showPageNumbers || totalPages <= ONE) return [];
1945
+ const pages = [];
1946
+ const halfMax = Math.floor(maxPageButtons / 2);
1947
+ let start = Math.max(ONE, page - halfMax);
1948
+ let end = Math.min(totalPages, page + halfMax);
1949
+ if (page <= halfMax) {
1950
+ end = Math.min(totalPages, maxPageButtons);
1951
+ }
1952
+ if (page > totalPages - halfMax) {
1953
+ start = Math.max(ONE, totalPages - maxPageButtons + ONE);
1954
+ }
1955
+ if (start > ONE) {
1956
+ pages.push(ONE);
1957
+ if (start > 2) {
1958
+ pages.push("ellipsis");
1959
+ }
1960
+ }
1961
+ for (let i = start; i <= end; i++) {
1962
+ if (!pages.includes(i)) {
1963
+ pages.push(i);
1964
+ }
1965
+ }
1966
+ if (end < totalPages) {
1967
+ if (end < totalPages - ONE) {
1968
+ pages.push("ellipsis");
1969
+ }
1970
+ pages.push(totalPages);
1971
+ }
1972
+ return pages;
1973
+ }, [page, totalPages, showPageNumbers, maxPageButtons]);
1974
+ if (totalItems === 0) {
1975
+ return null;
1976
+ }
1977
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1978
+ "div",
1979
+ {
1980
+ className: `grid-pagination flex flex-wrap items-center justify-between gap-4 px-4 py-3 border-t border-theme-border ${className}`,
1981
+ style,
1982
+ role: "navigation",
1983
+ "aria-label": "Pagination",
1984
+ children: [
1985
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid-pagination-info flex items-center gap-4", children: [
1986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid-pagination-range text-sm text-theme-secondary", children: [
1987
+ startItem,
1988
+ "-",
1989
+ endItem,
1990
+ " ",
1991
+ translations.of,
1992
+ " ",
1993
+ totalItems
1994
+ ] }),
1995
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid-pagination-size flex items-center gap-2", children: [
1996
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { htmlFor: "page-size", className: "text-sm text-theme-muted", children: [
1997
+ translations.rowsPerPage,
1998
+ ":"
1999
+ ] }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2001
+ "select",
2002
+ {
2003
+ id: "page-size",
2004
+ value: pageSize,
2005
+ onChange: handlePageSizeChange,
2006
+ className: "px-2 py-1 text-sm rounded border border-theme-border bg-theme-primary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary",
2007
+ children: pageSizeOptions.map((size) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: size, children: size }, size))
2008
+ }
2009
+ )
2010
+ ] })
2011
+ ] }),
2012
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "grid-pagination-controls flex items-center gap-1", children: [
2013
+ showFirstLast && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2014
+ "button",
2015
+ {
2016
+ onClick: handleFirstPage,
2017
+ disabled: !canGoPrevious,
2018
+ className: "p-2 rounded hover:bg-theme-hover disabled:opacity-50 disabled:cursor-not-allowed text-theme-secondary",
2019
+ "aria-label": translations.first,
2020
+ children: "<<"
2021
+ }
2022
+ ),
2023
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2024
+ "button",
2025
+ {
2026
+ onClick: handlePreviousPage,
2027
+ disabled: !canGoPrevious,
2028
+ className: "p-2 rounded hover:bg-theme-hover disabled:opacity-50 disabled:cursor-not-allowed text-theme-secondary",
2029
+ "aria-label": translations.previous,
2030
+ children: "<"
2031
+ }
2032
+ ),
2033
+ showPageNumbers && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "grid-pagination-pages flex items-center gap-1", children: pageNumbers.map(
2034
+ (pageNum, index) => pageNum === "ellipsis" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "px-2 text-theme-muted", children: "..." }, `ellipsis-${index}`) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2035
+ "button",
2036
+ {
2037
+ onClick: () => onPageChange(pageNum),
2038
+ className: `min-w-[32px] h-8 px-2 rounded text-sm transition-colors ${pageNum === page ? "bg-accent-primary text-white" : "hover:bg-theme-hover text-theme-secondary"}`,
2039
+ "aria-current": pageNum === page ? "page" : void 0,
2040
+ children: pageNum
2041
+ },
2042
+ pageNum
2043
+ )
2044
+ ) }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2046
+ "button",
2047
+ {
2048
+ onClick: handleNextPage,
2049
+ disabled: !canGoNext,
2050
+ className: "p-2 rounded hover:bg-theme-hover disabled:opacity-50 disabled:cursor-not-allowed text-theme-secondary",
2051
+ "aria-label": translations.next,
2052
+ children: ">"
2053
+ }
2054
+ ),
2055
+ showFirstLast && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2056
+ "button",
2057
+ {
2058
+ onClick: handleLastPage,
2059
+ disabled: !canGoNext,
2060
+ className: "p-2 rounded hover:bg-theme-hover disabled:opacity-50 disabled:cursor-not-allowed text-theme-secondary",
2061
+ "aria-label": translations.last,
2062
+ children: ">>"
2063
+ }
2064
+ )
2065
+ ] })
2066
+ ]
2067
+ }
2068
+ );
2069
+ }
2070
+
2071
+ // src/components/Skeleton/Skeleton.tsx
2072
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2073
+ function SkeletonCell({ width = DEFAULT_COLUMN_WIDTH, height = 16, animate = true }) {
2074
+ const widthStyle = typeof width === "number" ? `${width}px` : width;
2075
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2076
+ "div",
2077
+ {
2078
+ className: "grid-skeleton-cell px-4 py-3 flex-shrink-0",
2079
+ style: { width: widthStyle },
2080
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2081
+ "div",
2082
+ {
2083
+ className: `rounded bg-theme-tertiary ${animate ? "animate-pulse" : ""}`,
2084
+ style: { height: `${height}px`, width: "80%" }
2085
+ }
2086
+ )
2087
+ }
2088
+ );
2089
+ }
2090
+ function SkeletonRow({ columns, columnWidths, height = 16, animate = true }) {
2091
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid-skeleton-row flex border-b border-theme-border", children: Array.from({ length: columns }).map((_, index) => {
2092
+ var _a;
2093
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2094
+ SkeletonCell,
2095
+ {
2096
+ width: (_a = columnWidths == null ? void 0 : columnWidths[index]) != null ? _a : DEFAULT_COLUMN_WIDTH,
2097
+ height,
2098
+ animate
2099
+ },
2100
+ index
2101
+ );
2102
+ }) });
2103
+ }
2104
+ function Skeleton({
2105
+ rows = SKELETON_ROWS,
2106
+ columns = 4,
2107
+ columnWidths,
2108
+ rowHeight = 16,
2109
+ className = "",
2110
+ style,
2111
+ showHeader = true,
2112
+ animate = true
2113
+ }) {
2114
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `grid-skeleton ${className}`, style, role: "status", "aria-label": "Loading", children: [
2115
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid-skeleton-header flex border-b border-theme-border bg-theme-secondary", children: Array.from({ length: columns }).map((_, index) => {
2116
+ var _a;
2117
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2118
+ "div",
2119
+ {
2120
+ className: "px-4 py-3 flex-shrink-0",
2121
+ style: { width: (_a = columnWidths == null ? void 0 : columnWidths[index]) != null ? _a : DEFAULT_COLUMN_WIDTH },
2122
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2123
+ "div",
2124
+ {
2125
+ className: `rounded bg-theme-tertiary ${animate ? "animate-pulse" : ""}`,
2126
+ style: { height: "12px", width: "60%" }
2127
+ }
2128
+ )
2129
+ },
2130
+ index
2131
+ );
2132
+ }) }),
2133
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "grid-skeleton-body", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2134
+ SkeletonRow,
2135
+ {
2136
+ columns,
2137
+ columnWidths,
2138
+ height: rowHeight,
2139
+ animate
2140
+ },
2141
+ index
2142
+ )) })
2143
+ ] });
2144
+ }
2145
+
2146
+ // src/components/EmptyState/EmptyState.tsx
2147
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2148
+ function EmptyState({
2149
+ title,
2150
+ description,
2151
+ icon,
2152
+ action,
2153
+ className = "",
2154
+ style
2155
+ }) {
2156
+ const { state } = useTableContext();
2157
+ const { translations } = state;
2158
+ const displayTitle = title != null ? title : translations.empty;
2159
+ const displayDescription = description != null ? description : translations.noResults;
2160
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2161
+ "div",
2162
+ {
2163
+ className: `grid-empty-state flex flex-col items-center justify-center py-16 px-8 text-center ${className}`,
2164
+ style,
2165
+ role: "status",
2166
+ children: [
2167
+ icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid-empty-icon mb-4 text-theme-muted text-4xl", children: icon }),
2168
+ !icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid-empty-icon mb-4 text-theme-muted", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2169
+ "svg",
2170
+ {
2171
+ className: "w-16 h-16",
2172
+ fill: "none",
2173
+ viewBox: "0 0 24 24",
2174
+ stroke: "currentColor",
2175
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2176
+ "path",
2177
+ {
2178
+ strokeLinecap: "round",
2179
+ strokeLinejoin: "round",
2180
+ strokeWidth: 1,
2181
+ d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
2182
+ }
2183
+ )
2184
+ }
2185
+ ) }),
2186
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { className: "grid-empty-title text-lg font-medium text-theme-primary mb-2", children: displayTitle }),
2187
+ displayDescription && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className: "grid-empty-description text-sm text-theme-muted max-w-sm mb-4", children: displayDescription }),
2188
+ action && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "grid-empty-action", children: action })
2189
+ ]
2190
+ }
2191
+ );
2192
+ }
2193
+
2194
+ // src/components/MobileDrawer/MobileDrawer.tsx
2195
+ var import_react14 = require("react");
2196
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2197
+ function DrawerHeader({ title, onClose }) {
2198
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "drawer-header flex items-center justify-between px-4 py-3 border-b border-theme-border", children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-lg font-medium text-theme-primary", children: title }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2201
+ "button",
2202
+ {
2203
+ onClick: onClose,
2204
+ className: "p-2 rounded hover:bg-theme-hover text-theme-secondary",
2205
+ "aria-label": "Close",
2206
+ children: "X"
2207
+ }
2208
+ )
2209
+ ] });
2210
+ }
2211
+ function FilterContent() {
2212
+ const { state, actions } = useTableContext();
2213
+ const { translations, columns, filters } = state;
2214
+ const handleClearAll = (0, import_react14.useCallback)(() => {
2215
+ actions.clearFilters();
2216
+ }, [actions]);
2217
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "drawer-filter-content p-4 space-y-4", children: [
2218
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
2219
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-theme-muted", children: [
2220
+ filters.length,
2221
+ " ",
2222
+ translations.filter,
2223
+ "(s) active"
2224
+ ] }),
2225
+ filters.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2226
+ "button",
2227
+ {
2228
+ onClick: handleClearAll,
2229
+ className: "text-sm text-accent-primary hover:underline",
2230
+ children: translations.clearAll
2231
+ }
2232
+ )
2233
+ ] }),
2234
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-3", children: columns.filter((col) => col.filterable !== false).map((col) => {
2235
+ var _a;
2236
+ const existingFilter = filters.find((f) => f.columnId === col.id);
2237
+ const headerText = typeof col.header === "string" ? col.header : col.id;
2238
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "filter-item", children: [
2239
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("label", { className: "block text-sm font-medium text-theme-secondary mb-1", children: headerText }),
2240
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2241
+ "input",
2242
+ {
2243
+ type: "text",
2244
+ value: (_a = existingFilter == null ? void 0 : existingFilter.value) != null ? _a : "",
2245
+ onChange: (e) => {
2246
+ if (e.target.value) {
2247
+ actions.setFilter(col.id, e.target.value);
2248
+ } else {
2249
+ actions.removeFilter(col.id);
2250
+ }
2251
+ },
2252
+ placeholder: `${translations.filter} ${headerText}...`,
2253
+ className: "w-full px-3 py-2 text-sm rounded border border-theme-border bg-theme-primary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary"
2254
+ }
2255
+ )
2256
+ ] }, col.id);
2257
+ }) })
2258
+ ] });
2259
+ }
2260
+ function SortContent() {
2261
+ const { state, actions } = useTableContext();
2262
+ const { translations, columns, sorting } = state;
2263
+ const handleClearAll = (0, import_react14.useCallback)(() => {
2264
+ actions.clearSorting();
2265
+ }, [actions]);
2266
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "drawer-sort-content p-4 space-y-4", children: [
2267
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
2268
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-sm text-theme-muted", children: [
2269
+ sorting.length,
2270
+ " ",
2271
+ translations.sort,
2272
+ "(s) active"
2273
+ ] }),
2274
+ sorting.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2275
+ "button",
2276
+ {
2277
+ onClick: handleClearAll,
2278
+ className: "text-sm text-accent-primary hover:underline",
2279
+ children: translations.clearAll
2280
+ }
2281
+ )
2282
+ ] }),
2283
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-2", children: columns.filter((col) => col.sortable !== false).map((col) => {
2284
+ const sortItem = sorting.find((s) => s.columnId === col.id);
2285
+ const headerText = typeof col.header === "string" ? col.header : col.id;
2286
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2287
+ "button",
2288
+ {
2289
+ onClick: () => actions.toggleSorting(col.id),
2290
+ className: `w-full flex items-center justify-between px-3 py-2 rounded border transition-colors ${sortItem ? "border-accent-primary bg-accent-primary/10" : "border-theme-border hover:bg-theme-hover"}`,
2291
+ children: [
2292
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-theme-primary", children: headerText }),
2293
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-theme-muted", children: (sortItem == null ? void 0 : sortItem.direction) === "asc" ? translations.sortAsc : (sortItem == null ? void 0 : sortItem.direction) === "desc" ? translations.sortDesc : "-" })
2294
+ ]
2295
+ },
2296
+ col.id
2297
+ );
2298
+ }) })
2299
+ ] });
2300
+ }
2301
+ function ColumnsContent() {
2302
+ const { state, actions } = useTableContext();
2303
+ const { translations, columns, columnStates } = state;
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "drawer-columns-content p-4 space-y-4", children: [
2305
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
2306
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-theme-muted", children: translations.showColumns }),
2307
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2308
+ "button",
2309
+ {
2310
+ onClick: actions.resetColumns,
2311
+ className: "text-sm text-accent-primary hover:underline",
2312
+ children: translations.resetColumns
2313
+ }
2314
+ )
2315
+ ] }),
2316
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "space-y-2", children: columns.map((col) => {
2317
+ const colState = columnStates.find((cs) => cs.id === col.id);
2318
+ const isVisible = (colState == null ? void 0 : colState.visible) !== false;
2319
+ const headerText = typeof col.header === "string" ? col.header : col.id;
2320
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2321
+ "label",
2322
+ {
2323
+ className: "flex items-center gap-3 px-3 py-2 rounded hover:bg-theme-hover cursor-pointer",
2324
+ children: [
2325
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2326
+ "input",
2327
+ {
2328
+ type: "checkbox",
2329
+ checked: isVisible,
2330
+ onChange: () => actions.toggleColumnVisibility(col.id),
2331
+ className: "w-4 h-4 rounded border-theme-border"
2332
+ }
2333
+ ),
2334
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-sm text-theme-primary", children: headerText })
2335
+ ]
2336
+ },
2337
+ col.id
2338
+ );
2339
+ }) })
2340
+ ] });
2341
+ }
2342
+ var DRAWER_TITLES = {
2343
+ filter: "Filters",
2344
+ sort: "Sort",
2345
+ columns: "Columns"
2346
+ };
2347
+ function MobileDrawer({
2348
+ isOpen,
2349
+ content,
2350
+ onClose,
2351
+ className = "",
2352
+ style
2353
+ }) {
2354
+ (0, import_react14.useEffect)(() => {
2355
+ if (isOpen) {
2356
+ document.body.style.overflow = "hidden";
2357
+ } else {
2358
+ document.body.style.overflow = "";
2359
+ }
2360
+ return () => {
2361
+ document.body.style.overflow = "";
2362
+ };
2363
+ }, [isOpen]);
2364
+ (0, import_react14.useEffect)(() => {
2365
+ const handleEscape = (e) => {
2366
+ if (e.key === "Escape" && isOpen) {
2367
+ onClose();
2368
+ }
2369
+ };
2370
+ document.addEventListener("keydown", handleEscape);
2371
+ return () => document.removeEventListener("keydown", handleEscape);
2372
+ }, [isOpen, onClose]);
2373
+ if (!isOpen || !content) {
2374
+ return null;
2375
+ }
2376
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `mobile-drawer-container fixed inset-0 z-50 ${className}`, style, children: [
2377
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2378
+ "div",
2379
+ {
2380
+ className: "mobile-drawer-overlay absolute inset-0 bg-black transition-opacity",
2381
+ style: {
2382
+ opacity: DRAWER_OVERLAY_OPACITY,
2383
+ transitionDuration: `${DRAWER_ANIMATION_DURATION}ms`
2384
+ },
2385
+ onClick: onClose,
2386
+ "aria-hidden": "true"
2387
+ }
2388
+ ),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2390
+ "div",
2391
+ {
2392
+ className: "mobile-drawer absolute bottom-0 left-0 right-0 bg-theme-primary rounded-t-2xl shadow-2xl max-h-[80vh] overflow-hidden flex flex-col",
2393
+ style: {
2394
+ transitionDuration: `${DRAWER_ANIMATION_DURATION}ms`
2395
+ },
2396
+ role: "dialog",
2397
+ "aria-modal": "true",
2398
+ "aria-labelledby": "drawer-title",
2399
+ children: [
2400
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DrawerHeader, { title: DRAWER_TITLES[content], onClose }),
2401
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "drawer-content flex-1 overflow-y-auto", children: [
2402
+ content === "filter" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FilterContent, {}),
2403
+ content === "sort" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SortContent, {}),
2404
+ content === "columns" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ColumnsContent, {})
2405
+ ] })
2406
+ ]
2407
+ }
2408
+ )
2409
+ ] });
2410
+ }
2411
+
2412
+ // src/components/GridTable/GridTable.tsx
2413
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2414
+ function GridTableContent({
2415
+ data,
2416
+ columns,
2417
+ loading = false,
2418
+ error = null,
2419
+ emptyContent,
2420
+ loadingContent,
2421
+ errorContent,
2422
+ dimensions,
2423
+ classNames = {},
2424
+ styles = {},
2425
+ showMobileLabels = true,
2426
+ enableDragDrop = true,
2427
+ enableColumnResize = true,
2428
+ enableRowSelection = false,
2429
+ enableRowExpansion = false,
2430
+ stickyHeader = true,
2431
+ showPagination = true,
2432
+ showFilter = true,
2433
+ showGlobalFilter = true,
2434
+ onRowClick,
2435
+ onRowDoubleClick,
2436
+ onCellClick,
2437
+ onRowSelect,
2438
+ onSort,
2439
+ onFilter: _onFilter,
2440
+ onPageChange,
2441
+ onError: _onError,
2442
+ onRetry,
2443
+ getRowId,
2444
+ getRowClassName,
2445
+ getRowStyle,
2446
+ isRowDisabled,
2447
+ renderRowExpansion,
2448
+ renderHeader,
2449
+ renderFooter,
2450
+ className = "",
2451
+ style
2452
+ }) {
2453
+ const { state, actions, computed } = useTableContext();
2454
+ const { shouldShowMobileView, breakpointValue } = useBreakpoint();
2455
+ const getRowIdFn = (0, import_react15.useCallback)(
2456
+ (row) => {
2457
+ if (getRowId) return getRowId(row);
2458
+ if ("id" in row) return row.id;
2459
+ return data.indexOf(row);
2460
+ },
2461
+ [getRowId, data]
2462
+ );
2463
+ const handleRowSelect = (0, import_react15.useCallback)(
2464
+ (id, selected) => {
2465
+ if (selected) {
2466
+ actions.selectRow(id);
2467
+ } else {
2468
+ actions.deselectRow(id);
2469
+ }
2470
+ },
2471
+ [actions]
2472
+ );
2473
+ const handleRowExpand = (0, import_react15.useCallback)(
2474
+ (id, expanded) => {
2475
+ if (expanded) {
2476
+ actions.expandRow(id);
2477
+ } else {
2478
+ actions.collapseRow(id);
2479
+ }
2480
+ },
2481
+ [actions]
2482
+ );
2483
+ const handleFilterOpen = (0, import_react15.useCallback)(
2484
+ (columnId) => {
2485
+ if (shouldShowMobileView) {
2486
+ actions.openMobileDrawer("filter");
2487
+ } else {
2488
+ actions.setActiveFilterColumn(columnId);
2489
+ }
2490
+ },
2491
+ [shouldShowMobileView, actions]
2492
+ );
2493
+ const containerStyle = (0, import_react15.useMemo)(() => {
2494
+ const baseStyle = { ...style, ...styles.root };
2495
+ if (dimensions == null ? void 0 : dimensions.width) {
2496
+ baseStyle.width = breakpointValue(dimensions.width, "auto");
2497
+ }
2498
+ if (dimensions == null ? void 0 : dimensions.height) {
2499
+ baseStyle.height = breakpointValue(dimensions.height, "auto");
2500
+ }
2501
+ if (dimensions == null ? void 0 : dimensions.maxHeight) {
2502
+ baseStyle.maxHeight = breakpointValue(dimensions.maxHeight, "none");
2503
+ }
2504
+ return baseStyle;
2505
+ }, [style, styles.root, dimensions, breakpointValue]);
2506
+ const columnWidths = (0, import_react15.useMemo)(() => {
2507
+ return state.columnStates.map((cs) => cs.width);
2508
+ }, [state.columnStates]);
2509
+ if (error) {
2510
+ const errorMessage = typeof error === "string" ? error : error.message;
2511
+ if (errorContent) {
2512
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `grid-table-error ${classNames.root || ""} ${className}`, style: containerStyle, children: typeof errorContent === "function" ? errorContent(error) : errorContent });
2513
+ }
2514
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `grid-table-error ${classNames.root || ""} ${className}`, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2515
+ EmptyState,
2516
+ {
2517
+ title: state.translations.errorLoading,
2518
+ description: errorMessage,
2519
+ action: onRetry && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2520
+ "button",
2521
+ {
2522
+ onClick: onRetry,
2523
+ className: "px-4 py-2 bg-accent-primary text-white rounded hover:bg-accent-primary/90",
2524
+ children: state.translations.retry
2525
+ }
2526
+ )
2527
+ }
2528
+ ) });
2529
+ }
2530
+ if (loading) {
2531
+ if (loadingContent) {
2532
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `grid-table-loading ${classNames.root || ""} ${className}`, style: containerStyle, children: loadingContent });
2533
+ }
2534
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: `grid-table-loading ${classNames.root || ""} ${className}`, style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2535
+ Skeleton,
2536
+ {
2537
+ rows: 5,
2538
+ columns: columns.length,
2539
+ columnWidths,
2540
+ showHeader: true,
2541
+ animate: true,
2542
+ className: classNames.skeleton,
2543
+ style: styles.skeleton
2544
+ }
2545
+ ) });
2546
+ }
2547
+ const isEmpty = computed.paginatedData.length === 0;
2548
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2549
+ "div",
2550
+ {
2551
+ className: `grid-table bg-theme-primary rounded-lg border border-theme-border overflow-hidden ${classNames.root || ""} ${className}`,
2552
+ style: containerStyle,
2553
+ role: "table",
2554
+ children: [
2555
+ renderHeader && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid-table-custom-header", children: renderHeader() }),
2556
+ showGlobalFilter && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid-table-toolbar flex items-center gap-4 px-4 py-3 border-b border-theme-border", children: [
2557
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 relative", children: [
2558
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2559
+ "svg",
2560
+ {
2561
+ className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-theme-muted",
2562
+ fill: "none",
2563
+ viewBox: "0 0 24 24",
2564
+ stroke: "currentColor",
2565
+ strokeWidth: 2,
2566
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" })
2567
+ }
2568
+ ),
2569
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2570
+ "input",
2571
+ {
2572
+ type: "text",
2573
+ value: state.globalFilter,
2574
+ onChange: (e) => actions.setGlobalFilter(e.target.value),
2575
+ placeholder: state.translations.search,
2576
+ className: "w-full pl-10 pr-3 py-2 text-sm rounded border border-theme-border bg-theme-secondary text-theme-primary focus:outline-none focus:ring-2 focus:ring-accent-primary"
2577
+ }
2578
+ ),
2579
+ state.globalFilter && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2580
+ "button",
2581
+ {
2582
+ onClick: () => actions.setGlobalFilter(""),
2583
+ className: "absolute right-3 top-1/2 -translate-y-1/2 text-theme-muted hover:text-theme-primary",
2584
+ "aria-label": "Clear search",
2585
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) })
2586
+ }
2587
+ )
2588
+ ] }),
2589
+ state.filters.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2590
+ "button",
2591
+ {
2592
+ onClick: () => actions.clearFilters(),
2593
+ className: "flex items-center gap-2 px-3 py-2 text-sm rounded border border-theme-border hover:bg-theme-hover text-theme-secondary",
2594
+ children: [
2595
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" }) }),
2596
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
2597
+ state.filters.length,
2598
+ " filter",
2599
+ state.filters.length > 1 ? "s" : ""
2600
+ ] })
2601
+ ]
2602
+ }
2603
+ ),
2604
+ shouldShowMobileView && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
2605
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2606
+ "button",
2607
+ {
2608
+ onClick: () => actions.openMobileDrawer("filter"),
2609
+ className: "p-2 rounded border border-theme-border hover:bg-theme-hover",
2610
+ "aria-label": state.translations.filter,
2611
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" }) })
2612
+ }
2613
+ ),
2614
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2615
+ "button",
2616
+ {
2617
+ onClick: () => actions.openMobileDrawer("sort"),
2618
+ className: "p-2 rounded border border-theme-border hover:bg-theme-hover",
2619
+ "aria-label": state.translations.sort,
2620
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) })
2621
+ }
2622
+ ),
2623
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2624
+ "button",
2625
+ {
2626
+ onClick: () => actions.openMobileDrawer("columns"),
2627
+ className: "p-2 rounded border border-theme-border hover:bg-theme-hover",
2628
+ "aria-label": state.translations.columns,
2629
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { className: "w-4 h-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) })
2630
+ }
2631
+ )
2632
+ ] })
2633
+ ] }),
2634
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid-table-container overflow-auto", children: [
2635
+ !shouldShowMobileView && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2636
+ GridHeader,
2637
+ {
2638
+ columns,
2639
+ columnStates: state.columnStates,
2640
+ className: classNames.header,
2641
+ style: styles.header,
2642
+ sticky: stickyHeader,
2643
+ enableSort: true,
2644
+ enableFilter: showFilter,
2645
+ enableDragDrop,
2646
+ enableResize: enableColumnResize,
2647
+ enableSelection: enableRowSelection,
2648
+ allSelected: computed.allSelected,
2649
+ someSelected: computed.someSelected,
2650
+ onSelectAll: actions.selectAll,
2651
+ onFilterOpen: handleFilterOpen,
2652
+ getSortDirection: (colId) => {
2653
+ var _a;
2654
+ const sort = state.sorting.find((s) => s.columnId === colId);
2655
+ return (_a = sort == null ? void 0 : sort.direction) != null ? _a : null;
2656
+ }
2657
+ }
2658
+ ),
2659
+ isEmpty ? emptyContent || /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2660
+ EmptyState,
2661
+ {
2662
+ className: classNames.empty,
2663
+ style: styles.empty
2664
+ }
2665
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2666
+ GridBody,
2667
+ {
2668
+ data: computed.paginatedData,
2669
+ columns,
2670
+ columnStates: state.columnStates,
2671
+ className: classNames.body,
2672
+ style: styles.body,
2673
+ isMobile: shouldShowMobileView,
2674
+ showMobileLabels,
2675
+ enableSelection: enableRowSelection,
2676
+ enableExpansion: enableRowExpansion,
2677
+ selectedIds: state.selectedIds,
2678
+ expandedIds: state.expandedIds,
2679
+ onRowClick,
2680
+ onRowDoubleClick,
2681
+ onCellClick,
2682
+ onRowSelect: handleRowSelect,
2683
+ onRowExpand: handleRowExpand,
2684
+ getRowId: getRowIdFn,
2685
+ getRowClassName,
2686
+ getRowStyle,
2687
+ isRowDisabled,
2688
+ renderRowExpansion
2689
+ }
2690
+ )
2691
+ ] }),
2692
+ showPagination && !isEmpty && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2693
+ Pagination,
2694
+ {
2695
+ page: state.page,
2696
+ pageSize: state.pageSize,
2697
+ totalItems: computed.sortedData.length,
2698
+ totalPages: computed.totalPages,
2699
+ className: classNames.pagination,
2700
+ style: styles.pagination,
2701
+ onPageChange: (page) => {
2702
+ actions.setPage(page);
2703
+ onPageChange == null ? void 0 : onPageChange(page, state.pageSize);
2704
+ },
2705
+ onPageSizeChange: (pageSize) => {
2706
+ actions.setPageSize(pageSize);
2707
+ onPageChange == null ? void 0 : onPageChange(1, pageSize);
2708
+ }
2709
+ }
2710
+ ),
2711
+ renderFooter && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "grid-table-custom-footer", children: renderFooter() }),
2712
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2713
+ MobileDrawer,
2714
+ {
2715
+ isOpen: state.showMobileDrawer,
2716
+ content: state.mobileDrawerContent,
2717
+ onClose: actions.closeMobileDrawer,
2718
+ className: classNames.drawer,
2719
+ style: styles.drawer
2720
+ }
2721
+ )
2722
+ ]
2723
+ }
2724
+ );
2725
+ }
2726
+ function GridTable({
2727
+ data,
2728
+ columns,
2729
+ loading = false,
2730
+ error = null,
2731
+ theme,
2732
+ translations,
2733
+ mobileBreakpoint = "tablet",
2734
+ paginationConfig,
2735
+ filterConfig,
2736
+ sortConfig,
2737
+ enableMultiSelect = false,
2738
+ getRowId,
2739
+ ...props
2740
+ }) {
2741
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2742
+ TableProvider,
2743
+ {
2744
+ data,
2745
+ columns,
2746
+ loading,
2747
+ error,
2748
+ theme,
2749
+ translations,
2750
+ mobileBreakpoint,
2751
+ paginationConfig,
2752
+ filterConfig,
2753
+ sortConfig,
2754
+ enableMultiSort: sortConfig == null ? void 0 : sortConfig.multiSort,
2755
+ enableMultiSelect,
2756
+ getRowId,
2757
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2758
+ GridTableContent,
2759
+ {
2760
+ data,
2761
+ columns,
2762
+ loading,
2763
+ error,
2764
+ getRowId,
2765
+ ...props
2766
+ }
2767
+ )
2768
+ }
2769
+ );
2770
+ }
2771
+ // Annotate the CommonJS export names for ESM import in node:
2772
+ 0 && (module.exports = {
2773
+ BREAKPOINTS,
2774
+ BREAKPOINT_KEYS,
2775
+ DEFAULT_COLUMN_WIDTH,
2776
+ DEFAULT_LIGHT_THEME,
2777
+ DEFAULT_PAGE_SIZE,
2778
+ DEFAULT_PAGE_SIZES,
2779
+ DEFAULT_TABLE_CONFIG,
2780
+ DEFAULT_THEME,
2781
+ DEFAULT_TRANSLATIONS,
2782
+ DESKTOP_BREAKPOINT,
2783
+ EmptyState,
2784
+ GridBody,
2785
+ GridCell,
2786
+ GridHeader,
2787
+ GridRow,
2788
+ GridTable,
2789
+ MAX_COLUMN_WIDTH,
2790
+ MIN_COLUMN_WIDTH,
2791
+ MOBILE_BREAKPOINT,
2792
+ MobileDrawer,
2793
+ Pagination,
2794
+ RESPONSIVE_MODES,
2795
+ Skeleton,
2796
+ TABLET_BREAKPOINT,
2797
+ TableContext,
2798
+ TableProvider,
2799
+ useBreakpoint,
2800
+ useDragDrop,
2801
+ useFilter,
2802
+ usePagination,
2803
+ useSort,
2804
+ useTable,
2805
+ useTableContext
2806
+ });