@object-ui/components 0.3.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/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +46186 -0
- package/dist/index.umd.cjs +92 -0
- package/dist/src/hooks/use-mobile.d.ts +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.test.d.ts +1 -0
- package/dist/src/lib/utils.d.ts +4 -0
- package/dist/src/new-components.test.d.ts +1 -0
- package/dist/src/renderers/basic/div.d.ts +1 -0
- package/dist/src/renderers/basic/html.d.ts +1 -0
- package/dist/src/renderers/basic/icon.d.ts +1 -0
- package/dist/src/renderers/basic/image.d.ts +1 -0
- package/dist/src/renderers/basic/index.d.ts +0 -0
- package/dist/src/renderers/basic/separator.d.ts +1 -0
- package/dist/src/renderers/basic/span.d.ts +1 -0
- package/dist/src/renderers/basic/text.d.ts +1 -0
- package/dist/src/renderers/complex/__tests__/data-table.test.d.ts +0 -0
- package/dist/src/renderers/complex/calendar-view.d.ts +1 -0
- package/dist/src/renderers/complex/carousel.d.ts +1 -0
- package/dist/src/renderers/complex/chatbot.d.ts +1 -0
- package/dist/src/renderers/complex/chatbot.test.d.ts +1 -0
- package/dist/src/renderers/complex/data-table.d.ts +1 -0
- package/dist/src/renderers/complex/filter-builder.d.ts +1 -0
- package/dist/src/renderers/complex/index.d.ts +0 -0
- package/dist/src/renderers/complex/resizable.d.ts +1 -0
- package/dist/src/renderers/complex/scroll-area.d.ts +1 -0
- package/dist/src/renderers/complex/table.d.ts +1 -0
- package/dist/src/renderers/complex/timeline.d.ts +1 -0
- package/dist/src/renderers/data-display/alert.d.ts +1 -0
- package/dist/src/renderers/data-display/avatar.d.ts +1 -0
- package/dist/src/renderers/data-display/badge.d.ts +1 -0
- package/dist/src/renderers/data-display/index.d.ts +0 -0
- package/dist/src/renderers/data-display/list.d.ts +1 -0
- package/dist/src/renderers/data-display/statistic.d.ts +1 -0
- package/dist/src/renderers/data-display/tree-view.d.ts +1 -0
- package/dist/src/renderers/disclosure/accordion.d.ts +1 -0
- package/dist/src/renderers/disclosure/collapsible.d.ts +1 -0
- package/dist/src/renderers/disclosure/index.d.ts +0 -0
- package/dist/src/renderers/feedback/index.d.ts +0 -0
- package/dist/src/renderers/feedback/loading.d.ts +1 -0
- package/dist/src/renderers/feedback/progress.d.ts +1 -0
- package/dist/src/renderers/feedback/skeleton.d.ts +1 -0
- package/dist/src/renderers/feedback/toaster.d.ts +1 -0
- package/dist/src/renderers/form/button.d.ts +1 -0
- package/dist/src/renderers/form/calendar.d.ts +1 -0
- package/dist/src/renderers/form/checkbox.d.ts +1 -0
- package/dist/src/renderers/form/date-picker.d.ts +1 -0
- package/dist/src/renderers/form/file-upload.d.ts +1 -0
- package/dist/src/renderers/form/form.d.ts +1 -0
- package/dist/src/renderers/form/index.d.ts +0 -0
- package/dist/src/renderers/form/input-otp.d.ts +1 -0
- package/dist/src/renderers/form/input.d.ts +1 -0
- package/dist/src/renderers/form/label.d.ts +1 -0
- package/dist/src/renderers/form/radio-group.d.ts +1 -0
- package/dist/src/renderers/form/select.d.ts +1 -0
- package/dist/src/renderers/form/slider.d.ts +1 -0
- package/dist/src/renderers/form/switch.d.ts +1 -0
- package/dist/src/renderers/form/textarea.d.ts +1 -0
- package/dist/src/renderers/form/toggle.d.ts +1 -0
- package/dist/src/renderers/index.d.ts +0 -0
- package/dist/src/renderers/layout/card.d.ts +1 -0
- package/dist/src/renderers/layout/container.d.ts +1 -0
- package/dist/src/renderers/layout/flex.d.ts +1 -0
- package/dist/src/renderers/layout/grid.d.ts +1 -0
- package/dist/src/renderers/layout/index.d.ts +0 -0
- package/dist/src/renderers/layout/page.d.ts +7 -0
- package/dist/src/renderers/layout/semantic.d.ts +1 -0
- package/dist/src/renderers/layout/stack.d.ts +1 -0
- package/dist/src/renderers/layout/tabs.d.ts +1 -0
- package/dist/src/renderers/navigation/header-bar.d.ts +1 -0
- package/dist/src/renderers/navigation/index.d.ts +0 -0
- package/dist/src/renderers/navigation/sidebar.d.ts +1 -0
- package/dist/src/renderers/overlay/alert-dialog.d.ts +1 -0
- package/dist/src/renderers/overlay/context-menu.d.ts +1 -0
- package/dist/src/renderers/overlay/dialog.d.ts +1 -0
- package/dist/src/renderers/overlay/drawer.d.ts +1 -0
- package/dist/src/renderers/overlay/dropdown-menu.d.ts +1 -0
- package/dist/src/renderers/overlay/hover-card.d.ts +1 -0
- package/dist/src/renderers/overlay/index.d.ts +0 -0
- package/dist/src/renderers/overlay/popover.d.ts +1 -0
- package/dist/src/renderers/overlay/sheet.d.ts +1 -0
- package/dist/src/renderers/overlay/tooltip.d.ts +1 -0
- package/dist/src/ui/accordion.d.ts +7 -0
- package/dist/src/ui/alert-dialog.d.ts +14 -0
- package/dist/src/ui/alert.d.ts +9 -0
- package/dist/src/ui/aspect-ratio.d.ts +3 -0
- package/dist/src/ui/avatar.d.ts +6 -0
- package/dist/src/ui/badge.d.ts +9 -0
- package/dist/src/ui/breadcrumb.d.ts +11 -0
- package/dist/src/ui/button-group.d.ts +11 -0
- package/dist/src/ui/button.d.ts +13 -0
- package/dist/src/ui/calendar-view.d.ts +21 -0
- package/dist/src/ui/calendar.d.ts +8 -0
- package/dist/src/ui/card.d.ts +9 -0
- package/dist/src/ui/carousel.d.ts +19 -0
- package/dist/src/ui/chatbot.d.ts +36 -0
- package/dist/src/ui/checkbox.d.ts +4 -0
- package/dist/src/ui/collapsible.d.ts +5 -0
- package/dist/src/ui/command.d.ts +18 -0
- package/dist/src/ui/context-menu.d.ts +25 -0
- package/dist/src/ui/dialog.d.ts +15 -0
- package/dist/src/ui/drawer.d.ts +13 -0
- package/dist/src/ui/dropdown-menu.d.ts +25 -0
- package/dist/src/ui/empty.d.ts +11 -0
- package/dist/src/ui/field.d.ts +24 -0
- package/dist/src/ui/filter-builder.d.ts +31 -0
- package/dist/src/ui/form.d.ts +24 -0
- package/dist/src/ui/hover-card.d.ts +6 -0
- package/dist/src/ui/index.d.ts +56 -0
- package/dist/src/ui/input-group.d.ts +16 -0
- package/dist/src/ui/input-otp.d.ts +11 -0
- package/dist/src/ui/input.d.ts +3 -0
- package/dist/src/ui/item.d.ts +23 -0
- package/dist/src/ui/kbd.d.ts +3 -0
- package/dist/src/ui/label.d.ts +4 -0
- package/dist/src/ui/menubar.d.ts +26 -0
- package/dist/src/ui/navigation-menu.d.ts +14 -0
- package/dist/src/ui/pagination.d.ts +13 -0
- package/dist/src/ui/popover.d.ts +7 -0
- package/dist/src/ui/progress.d.ts +4 -0
- package/dist/src/ui/radio-group.d.ts +5 -0
- package/dist/src/ui/resizable.d.ts +10 -0
- package/dist/src/ui/scroll-area.d.ts +5 -0
- package/dist/src/ui/select.d.ts +15 -0
- package/dist/src/ui/separator.d.ts +4 -0
- package/dist/src/ui/sheet.d.ts +13 -0
- package/dist/src/ui/sidebar.d.ts +69 -0
- package/dist/src/ui/skeleton.d.ts +2 -0
- package/dist/src/ui/slider.d.ts +4 -0
- package/dist/src/ui/sonner.d.ts +3 -0
- package/dist/src/ui/spinner.d.ts +3 -0
- package/dist/src/ui/switch.d.ts +4 -0
- package/dist/src/ui/table.d.ts +10 -0
- package/dist/src/ui/tabs.d.ts +7 -0
- package/dist/src/ui/textarea.d.ts +3 -0
- package/dist/src/ui/timeline.d.ts +25 -0
- package/dist/src/ui/toggle-group.d.ts +9 -0
- package/dist/src/ui/toggle.d.ts +9 -0
- package/dist/src/ui/tooltip.d.ts +7 -0
- package/docs/FilterBuilder.md +268 -0
- package/metadata/Chart.component.yml +30 -0
- package/metadata/FilterBuilder.component.yml +39 -0
- package/metadata/GridLayout.component.yml +27 -0
- package/metadata/Menu.component.yml +31 -0
- package/metadata/ObjectForm.component.yml +34 -0
- package/metadata/ObjectTable.component.yml +41 -0
- package/metadata/Page.component.yml +24 -0
- package/package.json +87 -0
- package/postcss.config.js +6 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.css +76 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +10 -0
- package/src/lib/utils.tsx +27 -0
- package/src/new-components.test.ts +74 -0
- package/src/renderers/basic/div.tsx +41 -0
- package/src/renderers/basic/html.tsx +34 -0
- package/src/renderers/basic/icon.tsx +25 -0
- package/src/renderers/basic/image.tsx +37 -0
- package/src/renderers/basic/index.ts +7 -0
- package/src/renderers/basic/separator.tsx +48 -0
- package/src/renderers/basic/span.tsx +44 -0
- package/src/renderers/basic/text.tsx +42 -0
- package/src/renderers/complex/README-KANBAN.md +208 -0
- package/src/renderers/complex/TIMELINE.md +353 -0
- package/src/renderers/complex/__tests__/data-table.test.ts +52 -0
- package/src/renderers/complex/calendar-view.tsx +219 -0
- package/src/renderers/complex/carousel.tsx +60 -0
- package/src/renderers/complex/chatbot.test.ts +44 -0
- package/src/renderers/complex/chatbot.tsx +185 -0
- package/src/renderers/complex/data-table.tsx +650 -0
- package/src/renderers/complex/filter-builder.tsx +68 -0
- package/src/renderers/complex/index.ts +10 -0
- package/src/renderers/complex/resizable.tsx +54 -0
- package/src/renderers/complex/scroll-area.tsx +32 -0
- package/src/renderers/complex/table.tsx +86 -0
- package/src/renderers/complex/timeline.tsx +466 -0
- package/src/renderers/data-display/alert.tsx +37 -0
- package/src/renderers/data-display/avatar.tsx +29 -0
- package/src/renderers/data-display/badge.tsx +46 -0
- package/src/renderers/data-display/index.ts +6 -0
- package/src/renderers/data-display/list.tsx +95 -0
- package/src/renderers/data-display/statistic.tsx +98 -0
- package/src/renderers/data-display/tree-view.tsx +180 -0
- package/src/renderers/disclosure/accordion.tsx +60 -0
- package/src/renderers/disclosure/collapsible.tsx +44 -0
- package/src/renderers/disclosure/index.ts +2 -0
- package/src/renderers/feedback/index.ts +4 -0
- package/src/renderers/feedback/loading.tsx +69 -0
- package/src/renderers/feedback/progress.tsx +20 -0
- package/src/renderers/feedback/skeleton.tsx +22 -0
- package/src/renderers/feedback/toaster.tsx +26 -0
- package/src/renderers/form/button.tsx +61 -0
- package/src/renderers/form/calendar.tsx +25 -0
- package/src/renderers/form/checkbox.tsx +41 -0
- package/src/renderers/form/date-picker.tsx +75 -0
- package/src/renderers/form/file-upload.tsx +175 -0
- package/src/renderers/form/form.tsx +417 -0
- package/src/renderers/form/index.ts +16 -0
- package/src/renderers/form/input-otp.tsx +31 -0
- package/src/renderers/form/input.tsx +79 -0
- package/src/renderers/form/label.tsx +36 -0
- package/src/renderers/form/radio-group.tsx +54 -0
- package/src/renderers/form/select.tsx +66 -0
- package/src/renderers/form/slider.tsx +45 -0
- package/src/renderers/form/switch.tsx +39 -0
- package/src/renderers/form/textarea.tsx +45 -0
- package/src/renderers/form/toggle.tsx +76 -0
- package/src/renderers/index.ts +9 -0
- package/src/renderers/layout/card.tsx +69 -0
- package/src/renderers/layout/container.tsx +113 -0
- package/src/renderers/layout/flex.tsx +123 -0
- package/src/renderers/layout/grid.tsx +155 -0
- package/src/renderers/layout/index.ts +10 -0
- package/src/renderers/layout/page.tsx +82 -0
- package/src/renderers/layout/semantic.tsx +39 -0
- package/src/renderers/layout/stack.tsx +123 -0
- package/src/renderers/layout/tabs.tsx +63 -0
- package/src/renderers/navigation/header-bar.tsx +50 -0
- package/src/renderers/navigation/index.ts +2 -0
- package/src/renderers/navigation/sidebar.tsx +189 -0
- package/src/renderers/overlay/alert-dialog.tsx +63 -0
- package/src/renderers/overlay/context-menu.tsx +91 -0
- package/src/renderers/overlay/dialog.tsx +68 -0
- package/src/renderers/overlay/drawer.tsx +68 -0
- package/src/renderers/overlay/dropdown-menu.tsx +90 -0
- package/src/renderers/overlay/hover-card.tsx +46 -0
- package/src/renderers/overlay/index.ts +9 -0
- package/src/renderers/overlay/popover.tsx +47 -0
- package/src/renderers/overlay/sheet.tsx +68 -0
- package/src/renderers/overlay/tooltip.tsx +58 -0
- package/src/ui/accordion.tsx +64 -0
- package/src/ui/alert-dialog.tsx +155 -0
- package/src/ui/alert.tsx +78 -0
- package/src/ui/aspect-ratio.tsx +11 -0
- package/src/ui/avatar.tsx +51 -0
- package/src/ui/badge.tsx +46 -0
- package/src/ui/breadcrumb.tsx +109 -0
- package/src/ui/button-group.tsx +83 -0
- package/src/ui/button.tsx +65 -0
- package/src/ui/calendar-view.tsx +503 -0
- package/src/ui/calendar.tsx +237 -0
- package/src/ui/card.tsx +138 -0
- package/src/ui/carousel.tsx +239 -0
- package/src/ui/chatbot.tsx +240 -0
- package/src/ui/checkbox.tsx +32 -0
- package/src/ui/collapsible.tsx +31 -0
- package/src/ui/command.tsx +182 -0
- package/src/ui/context-menu.tsx +247 -0
- package/src/ui/dialog.tsx +141 -0
- package/src/ui/drawer.tsx +135 -0
- package/src/ui/dropdown-menu.tsx +254 -0
- package/src/ui/empty.tsx +104 -0
- package/src/ui/field.tsx +246 -0
- package/src/ui/filter-builder.tsx +359 -0
- package/src/ui/form.tsx +167 -0
- package/src/ui/hover-card.tsx +44 -0
- package/src/ui/index.ts +56 -0
- package/src/ui/input-group.tsx +170 -0
- package/src/ui/input-otp.tsx +81 -0
- package/src/ui/input.tsx +24 -0
- package/src/ui/item.tsx +193 -0
- package/src/ui/kbd.tsx +28 -0
- package/src/ui/label.tsx +24 -0
- package/src/ui/menubar.tsx +274 -0
- package/src/ui/navigation-menu.tsx +168 -0
- package/src/ui/pagination.tsx +127 -0
- package/src/ui/popover.tsx +48 -0
- package/src/ui/progress.tsx +41 -0
- package/src/ui/radio-group.tsx +45 -0
- package/src/ui/resizable.tsx +55 -0
- package/src/ui/scroll-area.tsx +58 -0
- package/src/ui/select.tsx +188 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/sheet.tsx +137 -0
- package/src/ui/sidebar.tsx +726 -0
- package/src/ui/skeleton.tsx +20 -0
- package/src/ui/slider.tsx +63 -0
- package/src/ui/sonner.tsx +43 -0
- package/src/ui/spinner.tsx +38 -0
- package/src/ui/switch.tsx +31 -0
- package/src/ui/table.tsx +120 -0
- package/src/ui/tabs.tsx +86 -0
- package/src/ui/textarea.tsx +18 -0
- package/src/ui/timeline.tsx +266 -0
- package/src/ui/toggle-group.tsx +87 -0
- package/src/ui/toggle.tsx +50 -0
- package/src/ui/tooltip.tsx +61 -0
- package/tailwind.config.js +75 -0
- package/tsconfig.json +18 -0
- package/vite.config.ts +44 -0
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
// Enterprise-level DataTable Component (Airtable-like)
|
|
2
|
+
import React, { useState, useMemo, useRef, useEffect } from 'react';
|
|
3
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
4
|
+
import type { DataTableSchema } from '@object-ui/types';
|
|
5
|
+
import {
|
|
6
|
+
Table,
|
|
7
|
+
TableHeader,
|
|
8
|
+
TableBody,
|
|
9
|
+
TableFooter,
|
|
10
|
+
TableHead,
|
|
11
|
+
TableRow,
|
|
12
|
+
TableCell,
|
|
13
|
+
TableCaption
|
|
14
|
+
} from '../../ui/table';
|
|
15
|
+
import { Button } from '../../ui/button';
|
|
16
|
+
import { Input } from '../../ui/input';
|
|
17
|
+
import { Checkbox } from '../../ui/checkbox';
|
|
18
|
+
import {
|
|
19
|
+
Select,
|
|
20
|
+
SelectContent,
|
|
21
|
+
SelectItem,
|
|
22
|
+
SelectTrigger,
|
|
23
|
+
SelectValue,
|
|
24
|
+
} from '../../ui/select';
|
|
25
|
+
import {
|
|
26
|
+
ChevronUp,
|
|
27
|
+
ChevronDown,
|
|
28
|
+
ChevronsUpDown,
|
|
29
|
+
Search,
|
|
30
|
+
Download,
|
|
31
|
+
Edit,
|
|
32
|
+
Trash2,
|
|
33
|
+
ChevronLeft,
|
|
34
|
+
ChevronRight,
|
|
35
|
+
ChevronsLeft,
|
|
36
|
+
ChevronsRight,
|
|
37
|
+
GripVertical,
|
|
38
|
+
} from 'lucide-react';
|
|
39
|
+
|
|
40
|
+
type SortDirection = 'asc' | 'desc' | null;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Enterprise-level data table component with Airtable-like features.
|
|
44
|
+
*
|
|
45
|
+
* Provides comprehensive table functionality including:
|
|
46
|
+
* - Multi-column sorting (ascending/descending/none)
|
|
47
|
+
* - Real-time search across all columns
|
|
48
|
+
* - Pagination with configurable page sizes
|
|
49
|
+
* - Row selection with persistence across pages
|
|
50
|
+
* - CSV export of filtered/sorted data
|
|
51
|
+
* - Row action buttons (edit/delete)
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```json
|
|
55
|
+
* {
|
|
56
|
+
* "type": "data-table",
|
|
57
|
+
* "pagination": true,
|
|
58
|
+
* "searchable": true,
|
|
59
|
+
* "selectable": true,
|
|
60
|
+
* "sortable": true,
|
|
61
|
+
* "exportable": true,
|
|
62
|
+
* "rowActions": true,
|
|
63
|
+
* "columns": [
|
|
64
|
+
* { "header": "ID", "accessorKey": "id", "width": "80px" },
|
|
65
|
+
* { "header": "Name", "accessorKey": "name" }
|
|
66
|
+
* ],
|
|
67
|
+
* "data": [
|
|
68
|
+
* { "id": 1, "name": "John Doe" }
|
|
69
|
+
* ]
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @param {Object} props - Component props
|
|
74
|
+
* @param {DataTableSchema} props.schema - Table schema configuration
|
|
75
|
+
* @returns {JSX.Element} Rendered data table component
|
|
76
|
+
*/
|
|
77
|
+
const DataTableRenderer = ({ schema }: { schema: DataTableSchema }) => {
|
|
78
|
+
const {
|
|
79
|
+
caption,
|
|
80
|
+
columns: initialColumns = [],
|
|
81
|
+
data = [],
|
|
82
|
+
pagination = true,
|
|
83
|
+
pageSize: initialPageSize = 10,
|
|
84
|
+
searchable = true,
|
|
85
|
+
selectable = false,
|
|
86
|
+
sortable = true,
|
|
87
|
+
exportable = false,
|
|
88
|
+
rowActions = false,
|
|
89
|
+
resizableColumns = true,
|
|
90
|
+
reorderableColumns = true,
|
|
91
|
+
className,
|
|
92
|
+
} = schema;
|
|
93
|
+
|
|
94
|
+
// State management
|
|
95
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
96
|
+
const [sortColumn, setSortColumn] = useState<string | null>(null);
|
|
97
|
+
const [sortDirection, setSortDirection] = useState<SortDirection>(null);
|
|
98
|
+
const [selectedRowIds, setSelectedRowIds] = useState<Set<any>>(new Set());
|
|
99
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
100
|
+
const [pageSize, setPageSize] = useState(initialPageSize);
|
|
101
|
+
const [columns, setColumns] = useState(initialColumns);
|
|
102
|
+
const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
|
|
103
|
+
const [draggedColumn, setDraggedColumn] = useState<number | null>(null);
|
|
104
|
+
const [dragOverColumn, setDragOverColumn] = useState<number | null>(null);
|
|
105
|
+
|
|
106
|
+
// Refs for column resizing
|
|
107
|
+
const resizingColumn = useRef<string | null>(null);
|
|
108
|
+
const startX = useRef<number>(0);
|
|
109
|
+
const startWidth = useRef<number>(0);
|
|
110
|
+
|
|
111
|
+
// Update columns when schema changes
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
setColumns(initialColumns);
|
|
114
|
+
}, [initialColumns]);
|
|
115
|
+
|
|
116
|
+
// Filtering
|
|
117
|
+
const filteredData = useMemo(() => {
|
|
118
|
+
if (!searchQuery) return data;
|
|
119
|
+
|
|
120
|
+
return data.filter((row) =>
|
|
121
|
+
columns.some((col) => {
|
|
122
|
+
const value = row[col.accessorKey];
|
|
123
|
+
return value?.toString().toLowerCase().includes(searchQuery.toLowerCase());
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
}, [data, searchQuery, columns]);
|
|
127
|
+
|
|
128
|
+
// Sorting
|
|
129
|
+
const sortedData = useMemo(() => {
|
|
130
|
+
if (!sortColumn || !sortDirection) return filteredData;
|
|
131
|
+
|
|
132
|
+
return [...filteredData].sort((a, b) => {
|
|
133
|
+
const aValue = a[sortColumn];
|
|
134
|
+
const bValue = b[sortColumn];
|
|
135
|
+
|
|
136
|
+
if (aValue === bValue) return 0;
|
|
137
|
+
|
|
138
|
+
const comparison = aValue < bValue ? -1 : 1;
|
|
139
|
+
return sortDirection === 'asc' ? comparison : -comparison;
|
|
140
|
+
});
|
|
141
|
+
}, [filteredData, sortColumn, sortDirection]);
|
|
142
|
+
|
|
143
|
+
// Pagination
|
|
144
|
+
const totalPages = Math.ceil(sortedData.length / pageSize);
|
|
145
|
+
const paginatedData = pagination
|
|
146
|
+
? sortedData.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
147
|
+
: sortedData;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generates a unique identifier for each row to maintain stable selection state
|
|
151
|
+
* across pagination and sorting operations.
|
|
152
|
+
*
|
|
153
|
+
* @param {any} row - The data row object
|
|
154
|
+
* @param {number} index - The row's index in the dataset
|
|
155
|
+
* @returns {string | number} Unique row identifier (uses 'id' field if available, falls back to index)
|
|
156
|
+
*/
|
|
157
|
+
const getRowId = (row: any, index: number) => {
|
|
158
|
+
// Try to use 'id' field, fall back to index
|
|
159
|
+
return row.id !== undefined ? row.id : `row-${index}`;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// Handlers
|
|
163
|
+
const handleSort = (columnKey: string) => {
|
|
164
|
+
if (!sortable) return;
|
|
165
|
+
|
|
166
|
+
if (sortColumn === columnKey) {
|
|
167
|
+
if (sortDirection === 'asc') {
|
|
168
|
+
setSortDirection('desc');
|
|
169
|
+
} else if (sortDirection === 'desc') {
|
|
170
|
+
setSortDirection(null);
|
|
171
|
+
setSortColumn(null);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
setSortColumn(columnKey);
|
|
175
|
+
setSortDirection('asc');
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const handleSelectAll = (checked: boolean) => {
|
|
180
|
+
const newSelected = new Set<any>();
|
|
181
|
+
if (checked) {
|
|
182
|
+
paginatedData.forEach((row, idx) => {
|
|
183
|
+
const globalIndex = (currentPage - 1) * pageSize + idx;
|
|
184
|
+
const rowId = getRowId(row, globalIndex);
|
|
185
|
+
newSelected.add(rowId);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
setSelectedRowIds(newSelected);
|
|
189
|
+
|
|
190
|
+
// Call callback if provided
|
|
191
|
+
if (schema.onSelectionChange) {
|
|
192
|
+
const selectedData = sortedData.filter((row, idx) => {
|
|
193
|
+
const rowId = getRowId(row, idx);
|
|
194
|
+
return newSelected.has(rowId);
|
|
195
|
+
});
|
|
196
|
+
schema.onSelectionChange(selectedData);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handleSelectRow = (rowId: any, checked: boolean) => {
|
|
201
|
+
const newSelected = new Set(selectedRowIds);
|
|
202
|
+
if (checked) {
|
|
203
|
+
newSelected.add(rowId);
|
|
204
|
+
} else {
|
|
205
|
+
newSelected.delete(rowId);
|
|
206
|
+
}
|
|
207
|
+
setSelectedRowIds(newSelected);
|
|
208
|
+
|
|
209
|
+
// Call callback if provided
|
|
210
|
+
if (schema.onSelectionChange) {
|
|
211
|
+
const selectedData = sortedData.filter((row, idx) => {
|
|
212
|
+
const id = getRowId(row, idx);
|
|
213
|
+
return newSelected.has(id);
|
|
214
|
+
});
|
|
215
|
+
schema.onSelectionChange(selectedData);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const handleExport = () => {
|
|
220
|
+
const csvContent = [
|
|
221
|
+
columns.map(col => col.header).join(','),
|
|
222
|
+
...sortedData.map(row =>
|
|
223
|
+
columns.map(col => JSON.stringify(row[col.accessorKey] || '')).join(',')
|
|
224
|
+
)
|
|
225
|
+
].join('\n');
|
|
226
|
+
|
|
227
|
+
const blob = new Blob([csvContent], { type: 'text/csv' });
|
|
228
|
+
const url = window.URL.createObjectURL(blob);
|
|
229
|
+
const a = document.createElement('a');
|
|
230
|
+
a.href = url;
|
|
231
|
+
a.download = 'table-export.csv';
|
|
232
|
+
a.click();
|
|
233
|
+
window.URL.revokeObjectURL(url);
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const getSortIcon = (columnKey: string) => {
|
|
237
|
+
if (sortColumn !== columnKey) {
|
|
238
|
+
return <ChevronsUpDown className="h-4 w-4 ml-1 opacity-50" />;
|
|
239
|
+
}
|
|
240
|
+
if (sortDirection === 'asc') {
|
|
241
|
+
return <ChevronUp className="h-4 w-4 ml-1" />;
|
|
242
|
+
}
|
|
243
|
+
return <ChevronDown className="h-4 w-4 ml-1" />;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Column resizing handlers
|
|
247
|
+
const handleResizeStart = (e: React.MouseEvent, columnKey: string) => {
|
|
248
|
+
if (!resizableColumns) return;
|
|
249
|
+
e.preventDefault();
|
|
250
|
+
e.stopPropagation();
|
|
251
|
+
|
|
252
|
+
resizingColumn.current = columnKey;
|
|
253
|
+
startX.current = e.clientX;
|
|
254
|
+
|
|
255
|
+
const headerCell = (e.target as HTMLElement).closest('th');
|
|
256
|
+
if (headerCell) {
|
|
257
|
+
startWidth.current = headerCell.offsetWidth;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
document.addEventListener('mousemove', handleResizeMove);
|
|
261
|
+
document.addEventListener('mouseup', handleResizeEnd);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const handleResizeMove = (e: MouseEvent) => {
|
|
265
|
+
if (!resizingColumn.current) return;
|
|
266
|
+
|
|
267
|
+
const diff = e.clientX - startX.current;
|
|
268
|
+
const newWidth = Math.max(50, startWidth.current + diff); // Min width 50px
|
|
269
|
+
|
|
270
|
+
setColumnWidths(prev => ({
|
|
271
|
+
...prev,
|
|
272
|
+
[resizingColumn.current!]: newWidth
|
|
273
|
+
}));
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const handleResizeEnd = () => {
|
|
277
|
+
resizingColumn.current = null;
|
|
278
|
+
document.removeEventListener('mousemove', handleResizeMove);
|
|
279
|
+
document.removeEventListener('mouseup', handleResizeEnd);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
// Column reordering handlers
|
|
283
|
+
const handleColumnDragStart = (e: React.DragEvent, index: number) => {
|
|
284
|
+
if (!reorderableColumns) return;
|
|
285
|
+
setDraggedColumn(index);
|
|
286
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const handleColumnDragOver = (e: React.DragEvent, index: number) => {
|
|
290
|
+
if (!reorderableColumns) return;
|
|
291
|
+
e.preventDefault();
|
|
292
|
+
e.dataTransfer.dropEffect = 'move';
|
|
293
|
+
setDragOverColumn(index);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const handleColumnDrop = (e: React.DragEvent, dropIndex: number) => {
|
|
297
|
+
if (!reorderableColumns || draggedColumn === null) return;
|
|
298
|
+
e.preventDefault();
|
|
299
|
+
|
|
300
|
+
if (draggedColumn === dropIndex) {
|
|
301
|
+
setDraggedColumn(null);
|
|
302
|
+
setDragOverColumn(null);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const newColumns = [...columns];
|
|
307
|
+
const [removed] = newColumns.splice(draggedColumn, 1);
|
|
308
|
+
newColumns.splice(dropIndex, 0, removed);
|
|
309
|
+
|
|
310
|
+
setColumns(newColumns);
|
|
311
|
+
setDraggedColumn(null);
|
|
312
|
+
setDragOverColumn(null);
|
|
313
|
+
|
|
314
|
+
// Call callback if provided
|
|
315
|
+
if (schema.onColumnsReorder) {
|
|
316
|
+
schema.onColumnsReorder(newColumns);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const handleColumnDragEnd = () => {
|
|
321
|
+
setDraggedColumn(null);
|
|
322
|
+
setDragOverColumn(null);
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// Cleanup on unmount
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
return () => {
|
|
328
|
+
document.removeEventListener('mousemove', handleResizeMove);
|
|
329
|
+
document.removeEventListener('mouseup', handleResizeEnd);
|
|
330
|
+
};
|
|
331
|
+
}, []);
|
|
332
|
+
|
|
333
|
+
// Check if all rows on current page are selected
|
|
334
|
+
const allPageRowsSelected = paginatedData.length > 0 && paginatedData.every((row, idx) => {
|
|
335
|
+
const globalIndex = (currentPage - 1) * pageSize + idx;
|
|
336
|
+
const rowId = getRowId(row, globalIndex);
|
|
337
|
+
return selectedRowIds.has(rowId);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const somePageRowsSelected = paginatedData.some((row, idx) => {
|
|
341
|
+
const globalIndex = (currentPage - 1) * pageSize + idx;
|
|
342
|
+
const rowId = getRowId(row, globalIndex);
|
|
343
|
+
return selectedRowIds.has(rowId);
|
|
344
|
+
}) && !allPageRowsSelected;
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<div className={`space-y-4 ${className || ''}`}>
|
|
348
|
+
{/* Toolbar */}
|
|
349
|
+
<div className="flex items-center justify-between gap-4">
|
|
350
|
+
<div className="flex items-center gap-2 flex-1">
|
|
351
|
+
{searchable && (
|
|
352
|
+
<div className="relative max-w-sm flex-1">
|
|
353
|
+
<Search className="absolute left-2 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
|
354
|
+
<Input
|
|
355
|
+
placeholder="Search..."
|
|
356
|
+
value={searchQuery}
|
|
357
|
+
onChange={(e) => {
|
|
358
|
+
setSearchQuery(e.target.value);
|
|
359
|
+
setCurrentPage(1);
|
|
360
|
+
}}
|
|
361
|
+
className="pl-8"
|
|
362
|
+
/>
|
|
363
|
+
</div>
|
|
364
|
+
)}
|
|
365
|
+
</div>
|
|
366
|
+
|
|
367
|
+
<div className="flex items-center gap-2">
|
|
368
|
+
{exportable && (
|
|
369
|
+
<Button
|
|
370
|
+
variant="outline"
|
|
371
|
+
size="sm"
|
|
372
|
+
onClick={handleExport}
|
|
373
|
+
disabled={sortedData.length === 0}
|
|
374
|
+
>
|
|
375
|
+
<Download className="h-4 w-4 mr-2" />
|
|
376
|
+
Export CSV
|
|
377
|
+
</Button>
|
|
378
|
+
)}
|
|
379
|
+
|
|
380
|
+
{selectable && selectedRowIds.size > 0 && (
|
|
381
|
+
<div className="text-sm text-muted-foreground">
|
|
382
|
+
{selectedRowIds.size} selected
|
|
383
|
+
</div>
|
|
384
|
+
)}
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
{/* Table */}
|
|
389
|
+
<div className="border rounded-lg">
|
|
390
|
+
<Table>
|
|
391
|
+
{caption && <TableCaption>{caption}</TableCaption>}
|
|
392
|
+
<TableHeader>
|
|
393
|
+
<TableRow>
|
|
394
|
+
{selectable && (
|
|
395
|
+
<TableHead className="w-12">
|
|
396
|
+
<Checkbox
|
|
397
|
+
checked={allPageRowsSelected ? true : somePageRowsSelected ? 'indeterminate' : false}
|
|
398
|
+
onCheckedChange={handleSelectAll}
|
|
399
|
+
/>
|
|
400
|
+
</TableHead>
|
|
401
|
+
)}
|
|
402
|
+
{columns.map((col, index) => {
|
|
403
|
+
const columnWidth = columnWidths[col.accessorKey] || col.width;
|
|
404
|
+
const isDragging = draggedColumn === index;
|
|
405
|
+
const isDragOver = dragOverColumn === index;
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<TableHead
|
|
409
|
+
key={col.accessorKey}
|
|
410
|
+
className={`${col.className || ''} ${sortable && col.sortable !== false ? 'cursor-pointer select-none' : ''} ${isDragging ? 'opacity-50' : ''} ${isDragOver ? 'border-l-2 border-primary' : ''} relative group`}
|
|
411
|
+
style={{
|
|
412
|
+
width: columnWidth,
|
|
413
|
+
minWidth: columnWidth
|
|
414
|
+
}}
|
|
415
|
+
draggable={reorderableColumns}
|
|
416
|
+
onDragStart={(e) => handleColumnDragStart(e, index)}
|
|
417
|
+
onDragOver={(e) => handleColumnDragOver(e, index)}
|
|
418
|
+
onDrop={(e) => handleColumnDrop(e, index)}
|
|
419
|
+
onDragEnd={handleColumnDragEnd}
|
|
420
|
+
onClick={() => sortable && col.sortable !== false && handleSort(col.accessorKey)}
|
|
421
|
+
>
|
|
422
|
+
<div className="flex items-center justify-between">
|
|
423
|
+
<div className="flex items-center gap-1">
|
|
424
|
+
{reorderableColumns && (
|
|
425
|
+
<GripVertical className="h-4 w-4 opacity-0 group-hover:opacity-50 cursor-grab active:cursor-grabbing flex-shrink-0" />
|
|
426
|
+
)}
|
|
427
|
+
<span>{col.header}</span>
|
|
428
|
+
{sortable && col.sortable !== false && getSortIcon(col.accessorKey)}
|
|
429
|
+
</div>
|
|
430
|
+
{resizableColumns && col.resizable !== false && (
|
|
431
|
+
<div
|
|
432
|
+
className="absolute right-0 top-0 h-full w-1 cursor-col-resize hover:bg-primary opacity-0 hover:opacity-100 transition-opacity"
|
|
433
|
+
onMouseDown={(e) => handleResizeStart(e, col.accessorKey)}
|
|
434
|
+
onClick={(e) => e.stopPropagation()}
|
|
435
|
+
/>
|
|
436
|
+
)}
|
|
437
|
+
</div>
|
|
438
|
+
</TableHead>
|
|
439
|
+
);
|
|
440
|
+
})}
|
|
441
|
+
{rowActions && (
|
|
442
|
+
<TableHead className="w-24 text-right">Actions</TableHead>
|
|
443
|
+
)}
|
|
444
|
+
</TableRow>
|
|
445
|
+
</TableHeader>
|
|
446
|
+
<TableBody>
|
|
447
|
+
{paginatedData.length === 0 ? (
|
|
448
|
+
<TableRow>
|
|
449
|
+
<TableCell
|
|
450
|
+
colSpan={columns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0)}
|
|
451
|
+
className="h-24 text-center text-muted-foreground"
|
|
452
|
+
>
|
|
453
|
+
No data available
|
|
454
|
+
</TableCell>
|
|
455
|
+
</TableRow>
|
|
456
|
+
) : (
|
|
457
|
+
paginatedData.map((row, rowIndex) => {
|
|
458
|
+
const globalIndex = (currentPage - 1) * pageSize + rowIndex;
|
|
459
|
+
const rowId = getRowId(row, globalIndex);
|
|
460
|
+
const isSelected = selectedRowIds.has(rowId);
|
|
461
|
+
|
|
462
|
+
return (
|
|
463
|
+
<TableRow key={rowId} data-state={isSelected ? 'selected' : undefined}>
|
|
464
|
+
{selectable && (
|
|
465
|
+
<TableCell>
|
|
466
|
+
<Checkbox
|
|
467
|
+
checked={isSelected}
|
|
468
|
+
onCheckedChange={(checked) => handleSelectRow(rowId, checked as boolean)}
|
|
469
|
+
/>
|
|
470
|
+
</TableCell>
|
|
471
|
+
)}
|
|
472
|
+
{columns.map((col, colIndex) => {
|
|
473
|
+
const columnWidth = columnWidths[col.accessorKey] || col.width;
|
|
474
|
+
return (
|
|
475
|
+
<TableCell
|
|
476
|
+
key={colIndex}
|
|
477
|
+
className={col.cellClassName}
|
|
478
|
+
style={{
|
|
479
|
+
width: columnWidth,
|
|
480
|
+
minWidth: columnWidth,
|
|
481
|
+
maxWidth: columnWidth
|
|
482
|
+
}}
|
|
483
|
+
>
|
|
484
|
+
{row[col.accessorKey]}
|
|
485
|
+
</TableCell>
|
|
486
|
+
);
|
|
487
|
+
})}
|
|
488
|
+
{rowActions && (
|
|
489
|
+
<TableCell className="text-right">
|
|
490
|
+
<div className="flex items-center justify-end gap-1">
|
|
491
|
+
<Button
|
|
492
|
+
variant="ghost"
|
|
493
|
+
size="icon-sm"
|
|
494
|
+
onClick={() => schema.onRowEdit?.(row)}
|
|
495
|
+
>
|
|
496
|
+
<Edit className="h-4 w-4" />
|
|
497
|
+
</Button>
|
|
498
|
+
<Button
|
|
499
|
+
variant="ghost"
|
|
500
|
+
size="icon-sm"
|
|
501
|
+
onClick={() => schema.onRowDelete?.(row)}
|
|
502
|
+
>
|
|
503
|
+
<Trash2 className="h-4 w-4 text-destructive" />
|
|
504
|
+
</Button>
|
|
505
|
+
</div>
|
|
506
|
+
</TableCell>
|
|
507
|
+
)}
|
|
508
|
+
</TableRow>
|
|
509
|
+
);
|
|
510
|
+
})
|
|
511
|
+
)}
|
|
512
|
+
</TableBody>
|
|
513
|
+
</Table>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
{/* Pagination */}
|
|
517
|
+
{pagination && sortedData.length > 0 && (
|
|
518
|
+
<div className="flex items-center justify-between">
|
|
519
|
+
<div className="flex items-center gap-2">
|
|
520
|
+
<span className="text-sm text-muted-foreground">Rows per page:</span>
|
|
521
|
+
<Select
|
|
522
|
+
value={pageSize.toString()}
|
|
523
|
+
onValueChange={(value) => {
|
|
524
|
+
setPageSize(Number(value));
|
|
525
|
+
setCurrentPage(1);
|
|
526
|
+
}}
|
|
527
|
+
>
|
|
528
|
+
<SelectTrigger className="w-20">
|
|
529
|
+
<SelectValue />
|
|
530
|
+
</SelectTrigger>
|
|
531
|
+
<SelectContent>
|
|
532
|
+
<SelectItem value="5">5</SelectItem>
|
|
533
|
+
<SelectItem value="10">10</SelectItem>
|
|
534
|
+
<SelectItem value="20">20</SelectItem>
|
|
535
|
+
<SelectItem value="50">50</SelectItem>
|
|
536
|
+
<SelectItem value="100">100</SelectItem>
|
|
537
|
+
</SelectContent>
|
|
538
|
+
</Select>
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<div className="flex items-center gap-2">
|
|
542
|
+
<span className="text-sm text-muted-foreground">
|
|
543
|
+
Page {currentPage} of {totalPages} ({sortedData.length} total)
|
|
544
|
+
</span>
|
|
545
|
+
<div className="flex items-center gap-1">
|
|
546
|
+
<Button
|
|
547
|
+
variant="outline"
|
|
548
|
+
size="icon-sm"
|
|
549
|
+
onClick={() => setCurrentPage(1)}
|
|
550
|
+
disabled={currentPage === 1}
|
|
551
|
+
>
|
|
552
|
+
<ChevronsLeft className="h-4 w-4" />
|
|
553
|
+
</Button>
|
|
554
|
+
<Button
|
|
555
|
+
variant="outline"
|
|
556
|
+
size="icon-sm"
|
|
557
|
+
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
|
|
558
|
+
disabled={currentPage === 1}
|
|
559
|
+
>
|
|
560
|
+
<ChevronLeft className="h-4 w-4" />
|
|
561
|
+
</Button>
|
|
562
|
+
<Button
|
|
563
|
+
variant="outline"
|
|
564
|
+
size="icon-sm"
|
|
565
|
+
onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
|
|
566
|
+
disabled={currentPage === totalPages}
|
|
567
|
+
>
|
|
568
|
+
<ChevronRight className="h-4 w-4" />
|
|
569
|
+
</Button>
|
|
570
|
+
<Button
|
|
571
|
+
variant="outline"
|
|
572
|
+
size="icon-sm"
|
|
573
|
+
onClick={() => setCurrentPage(totalPages)}
|
|
574
|
+
disabled={currentPage === totalPages}
|
|
575
|
+
>
|
|
576
|
+
<ChevronsRight className="h-4 w-4" />
|
|
577
|
+
</Button>
|
|
578
|
+
</div>
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
581
|
+
)}
|
|
582
|
+
</div>
|
|
583
|
+
);
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
// Register the component
|
|
587
|
+
ComponentRegistry.register('data-table', DataTableRenderer, {
|
|
588
|
+
label: 'Data Table',
|
|
589
|
+
icon: 'table',
|
|
590
|
+
inputs: [
|
|
591
|
+
{ name: 'caption', type: 'string', label: 'Caption' },
|
|
592
|
+
{
|
|
593
|
+
name: 'columns',
|
|
594
|
+
type: 'array',
|
|
595
|
+
label: 'Columns',
|
|
596
|
+
description: 'Array of { header, accessorKey, className, width, sortable, filterable, resizable }',
|
|
597
|
+
required: true,
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
name: 'data',
|
|
601
|
+
type: 'array',
|
|
602
|
+
label: 'Data',
|
|
603
|
+
description: 'Array of data objects',
|
|
604
|
+
required: true,
|
|
605
|
+
},
|
|
606
|
+
{ name: 'pagination', type: 'boolean', label: 'Enable Pagination', defaultValue: true },
|
|
607
|
+
{ name: 'pageSize', type: 'number', label: 'Page Size', defaultValue: 10 },
|
|
608
|
+
{ name: 'searchable', type: 'boolean', label: 'Enable Search', defaultValue: true },
|
|
609
|
+
{ name: 'selectable', type: 'boolean', label: 'Enable Row Selection', defaultValue: false },
|
|
610
|
+
{ name: 'sortable', type: 'boolean', label: 'Enable Sorting', defaultValue: true },
|
|
611
|
+
{ name: 'exportable', type: 'boolean', label: 'Enable Export', defaultValue: false },
|
|
612
|
+
{ name: 'rowActions', type: 'boolean', label: 'Show Row Actions', defaultValue: false },
|
|
613
|
+
{ name: 'resizableColumns', type: 'boolean', label: 'Enable Column Resizing', defaultValue: true },
|
|
614
|
+
{ name: 'reorderableColumns', type: 'boolean', label: 'Enable Column Reordering', defaultValue: true },
|
|
615
|
+
{ name: 'className', type: 'string', label: 'CSS Class' },
|
|
616
|
+
],
|
|
617
|
+
defaultProps: {
|
|
618
|
+
caption: 'Enterprise Data Table',
|
|
619
|
+
pagination: true,
|
|
620
|
+
pageSize: 10,
|
|
621
|
+
searchable: true,
|
|
622
|
+
selectable: true,
|
|
623
|
+
sortable: true,
|
|
624
|
+
exportable: true,
|
|
625
|
+
rowActions: true,
|
|
626
|
+
resizableColumns: true,
|
|
627
|
+
reorderableColumns: true,
|
|
628
|
+
columns: [
|
|
629
|
+
{ header: 'ID', accessorKey: 'id', width: '80px' },
|
|
630
|
+
{ header: 'Name', accessorKey: 'name' },
|
|
631
|
+
{ header: 'Email', accessorKey: 'email' },
|
|
632
|
+
{ header: 'Status', accessorKey: 'status' },
|
|
633
|
+
{ header: 'Role', accessorKey: 'role' },
|
|
634
|
+
],
|
|
635
|
+
data: [
|
|
636
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', status: 'Active', role: 'Admin' },
|
|
637
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'Active', role: 'User' },
|
|
638
|
+
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'Inactive', role: 'User' },
|
|
639
|
+
{ id: 4, name: 'Alice Williams', email: 'alice@example.com', status: 'Active', role: 'Manager' },
|
|
640
|
+
{ id: 5, name: 'Charlie Brown', email: 'charlie@example.com', status: 'Active', role: 'User' },
|
|
641
|
+
{ id: 6, name: 'Diana Prince', email: 'diana@example.com', status: 'Active', role: 'Admin' },
|
|
642
|
+
{ id: 7, name: 'Ethan Hunt', email: 'ethan@example.com', status: 'Inactive', role: 'User' },
|
|
643
|
+
{ id: 8, name: 'Fiona Gallagher', email: 'fiona@example.com', status: 'Active', role: 'User' },
|
|
644
|
+
{ id: 9, name: 'George Wilson', email: 'george@example.com', status: 'Active', role: 'Manager' },
|
|
645
|
+
{ id: 10, name: 'Hannah Montana', email: 'hannah@example.com', status: 'Active', role: 'User' },
|
|
646
|
+
{ id: 11, name: 'Ivan Drago', email: 'ivan@example.com', status: 'Inactive', role: 'User' },
|
|
647
|
+
{ id: 12, name: 'Julia Roberts', email: 'julia@example.com', status: 'Active', role: 'Admin' },
|
|
648
|
+
],
|
|
649
|
+
},
|
|
650
|
+
});
|