flikkui 0.2.0-beta.4 → 0.2.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/dist/components/core/Table/Table.animations.d.ts +5 -16
- package/dist/components/core/Table/Table.animations.js +46 -0
- package/dist/components/core/Table/Table.d.ts +0 -27
- package/dist/components/core/Table/Table.js +58 -156
- package/dist/components/core/Table/Table.theme.js +28 -19
- package/dist/components/core/Table/Table.types.d.ts +95 -8
- package/dist/components/core/Table/Table.utils.d.ts +7 -0
- package/dist/components/core/Table/Table.utils.js +11 -1
- package/dist/components/core/Table/{components/TableActions/TableActions.d.ts → TableActions.d.ts} +3 -3
- package/dist/components/core/Table/{components/TableActions/TableActions.js → TableActions.js} +14 -24
- package/dist/components/core/Table/{components/TableActions/TableActionsMenu.d.ts → TableActionsMenu.d.ts} +1 -1
- package/dist/components/core/Table/{components/TableActions/TableActionsMenu.js → TableActionsMenu.js} +4 -4
- package/dist/components/core/Table/{components/core/TableBody.d.ts → TableBody.d.ts} +1 -1
- package/dist/components/core/Table/{components/core/TableBody.js → TableBody.js} +14 -20
- package/dist/components/core/Table/{components/core/TableCell.d.ts → TableCell.d.ts} +1 -9
- package/dist/components/core/Table/{components/core/TableCell.js → TableCell.js} +5 -13
- package/dist/components/core/Table/TableColumnManager.d.ts +3 -0
- package/dist/components/core/Table/TableColumnManager.js +34 -0
- package/dist/components/core/Table/{components/DeclarativeComponents.d.ts → TableDeclarative.d.ts} +1 -1
- package/dist/components/core/Table/{components/DeclarativeComponents.js → TableDeclarative.js} +6 -56
- package/dist/components/core/Table/TableFilter.d.ts +3 -0
- package/dist/components/core/Table/TableFilter.js +122 -0
- package/dist/components/core/Table/{components/core/TableHeader.d.ts → TableHeader.d.ts} +1 -1
- package/dist/components/core/Table/{components/core/TableHeader.js → TableHeader.js} +15 -29
- package/dist/components/core/Table/TablePagination.d.ts +7 -0
- package/dist/components/core/Table/{components/TablePagination/TablePagination.js → TablePagination.js} +5 -16
- package/dist/components/core/Table/TableRow.d.ts +8 -0
- package/dist/components/core/Table/TableRow.js +45 -0
- package/dist/components/core/Table/TableSelectionHeader.d.ts +7 -0
- package/dist/components/core/Table/{components/TableSelectionHeader/TableSelectionHeader.js → TableSelectionHeader.js} +4 -5
- package/dist/components/core/Table/hooks/index.d.ts +10 -0
- package/dist/components/core/Table/hooks/useTableColumns.d.ts +16 -0
- package/dist/components/core/Table/hooks/useTableColumns.js +67 -0
- package/dist/components/core/Table/hooks/useTableExpansion.d.ts +8 -0
- package/dist/components/core/Table/hooks/useTableExpansion.js +15 -0
- package/dist/components/core/Table/hooks/useTableFilter.d.ts +12 -0
- package/dist/components/core/Table/hooks/useTableFilter.js +37 -0
- package/dist/components/core/Table/hooks/useTablePagination.d.ts +12 -0
- package/dist/components/core/Table/hooks/useTablePagination.js +13 -0
- package/dist/components/core/Table/hooks/useTableSelection.d.ts +17 -0
- package/dist/components/core/Table/hooks/useTableSelection.js +40 -0
- package/dist/components/core/Table/index.d.ts +9 -8
- package/dist/components/core/Table/index.js +7 -5
- package/dist/components/core/index.js +9 -3
- package/dist/index.js +9 -3
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/components/core/Table/components/TableActions/TableActions.types.d.ts +0 -40
- package/dist/components/core/Table/components/TableActions/index.d.ts +0 -3
- package/dist/components/core/Table/components/TableActionsMenu.d.ts +0 -6
- package/dist/components/core/Table/components/TablePagination/TablePagination.d.ts +0 -17
- package/dist/components/core/Table/components/TablePagination/TablePagination.types.d.ts +0 -21
- package/dist/components/core/Table/components/TablePagination/index.d.ts +0 -2
- package/dist/components/core/Table/components/TableSelectionHeader/TableSelectionHeader.d.ts +0 -15
- package/dist/components/core/Table/components/TableSelectionHeader/index.d.ts +0 -3
- package/dist/components/core/Table/components/core/TableRow.d.ts +0 -3
- package/dist/components/core/Table/components/core/TableRow.js +0 -44
- package/dist/components/core/Table/components/core/index.d.ts +0 -4
package/README.md
CHANGED
|
@@ -26,6 +26,98 @@ function App() {
|
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
## Customizing the Theme
|
|
30
|
+
|
|
31
|
+
Flikkui uses CSS variables for all theming. Override any variable in your own CSS to customize colors, spacing, border radius, and more.
|
|
32
|
+
|
|
33
|
+
### Colors
|
|
34
|
+
|
|
35
|
+
Override semantic color palettes by redefining the CSS variables after importing the library styles:
|
|
36
|
+
|
|
37
|
+
```css
|
|
38
|
+
:root {
|
|
39
|
+
/* Change the primary color to green */
|
|
40
|
+
--color-primary-50: oklch(0.982 0.018 155.826);
|
|
41
|
+
--color-primary-100: oklch(0.962 0.044 156.743);
|
|
42
|
+
--color-primary-200: oklch(0.925 0.084 155.995);
|
|
43
|
+
--color-primary-300: oklch(0.871 0.15 154.449);
|
|
44
|
+
--color-primary-400: oklch(0.792 0.209 151.711);
|
|
45
|
+
--color-primary-500: oklch(0.723 0.219 149.579);
|
|
46
|
+
--color-primary-600: oklch(0.627 0.194 149.214);
|
|
47
|
+
--color-primary-700: oklch(0.527 0.154 150.069);
|
|
48
|
+
--color-primary-800: oklch(0.448 0.119 151.328);
|
|
49
|
+
--color-primary-900: oklch(0.393 0.095 152.535);
|
|
50
|
+
--color-primary-950: oklch(0.266 0.065 152.934);
|
|
51
|
+
|
|
52
|
+
--color-primary: var(--color-primary-600);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Available color palettes: `primary`, `danger`, `success`, `warning`. Each has shades from `50` to `950`.
|
|
57
|
+
|
|
58
|
+
### Backgrounds & Borders
|
|
59
|
+
|
|
60
|
+
```css
|
|
61
|
+
:root {
|
|
62
|
+
--color-background: oklch(98.5% 0.002 247.839);
|
|
63
|
+
--color-background-secondary: oklch(95% 0.002 247.839);
|
|
64
|
+
--color-background-tertiary: oklch(90% 0.002 247.839);
|
|
65
|
+
--color-border: oklch(92.2% 0 0);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Form Elements
|
|
70
|
+
|
|
71
|
+
Control sizing, padding, and border radius for all form components:
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
:root {
|
|
75
|
+
/* Border radius */
|
|
76
|
+
--form-rounded: 0.5rem;
|
|
77
|
+
|
|
78
|
+
/* Heights */
|
|
79
|
+
--form-min-h-sm: 2rem;
|
|
80
|
+
--form-min-h-md: 2.5rem;
|
|
81
|
+
--form-min-h-lg: 3rem;
|
|
82
|
+
|
|
83
|
+
/* Horizontal padding */
|
|
84
|
+
--form-px-sm: 0.75rem;
|
|
85
|
+
--form-px-md: 0.875rem;
|
|
86
|
+
--form-px-lg: 1rem;
|
|
87
|
+
|
|
88
|
+
/* Font sizes */
|
|
89
|
+
--form-text-sm: 0.75rem;
|
|
90
|
+
--form-text-md: 0.875rem;
|
|
91
|
+
--form-text-lg: 1rem;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Button, badge, segmented, and other component variables inherit from these form defaults but can be overridden individually (e.g. `--button-rounded`, `--badge-rounded`).
|
|
96
|
+
|
|
97
|
+
### Dark Mode
|
|
98
|
+
|
|
99
|
+
Add the `dark` class to your `<html>` or any parent container. All components adapt automatically:
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<html class="dark">
|
|
103
|
+
<!-- dark mode active -->
|
|
104
|
+
</html>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The library ships with sensible dark mode defaults. To customize dark mode colors, override variables inside `.dark`:
|
|
108
|
+
|
|
109
|
+
```css
|
|
110
|
+
.dark {
|
|
111
|
+
--color-background: oklch(14.5% 0 0);
|
|
112
|
+
--color-border: oklch(30% 0 0);
|
|
113
|
+
--color-primary: var(--color-primary-400);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Full Variable Reference
|
|
118
|
+
|
|
119
|
+
See [`src/styles/theme.css`](src/styles/theme.css) for the complete list of available CSS variables.
|
|
120
|
+
|
|
29
121
|
## Documentation
|
|
30
122
|
|
|
31
123
|
This package is currently in beta. Full documentation coming soon.
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import { Variants } from "motion/react";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Container animation for row expansion (height: 0 -> auto with opacity)
|
|
4
|
+
* Uses the same easing curve pattern as Accordion for consistency
|
|
4
5
|
*/
|
|
5
|
-
export declare const
|
|
6
|
+
export declare const tableExpandAnimations: Variants;
|
|
6
7
|
/**
|
|
7
|
-
*
|
|
8
|
+
* Content slide-in animation for expanded row content (staggered after container)
|
|
8
9
|
*/
|
|
9
|
-
export declare const
|
|
10
|
-
/**
|
|
11
|
-
* Get table column manager slide animation variants
|
|
12
|
-
*/
|
|
13
|
-
export declare const getTableColumnManagerVariants: (shouldReduceMotion: boolean | null) => Variants | undefined;
|
|
14
|
-
/**
|
|
15
|
-
* Get table loading state animation variants
|
|
16
|
-
*/
|
|
17
|
-
export declare const getTableLoadingVariants: (shouldReduceMotion: boolean | null) => Variants | undefined;
|
|
18
|
-
/**
|
|
19
|
-
* Get table sort indicator animation variants
|
|
20
|
-
*/
|
|
21
|
-
export declare const getTableSortVariants: (shouldReduceMotion: boolean | null) => Variants | undefined;
|
|
10
|
+
export declare const tableExpandContentAnimations: Variants;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container animation for row expansion (height: 0 -> auto with opacity)
|
|
3
|
+
* Uses the same easing curve pattern as Accordion for consistency
|
|
4
|
+
*/
|
|
5
|
+
const tableExpandAnimations = {
|
|
6
|
+
collapsed: {
|
|
7
|
+
height: 0,
|
|
8
|
+
opacity: 0,
|
|
9
|
+
transition: {
|
|
10
|
+
height: { duration: 0.3, ease: [0.04, 0.62, 0.23, 0.98] },
|
|
11
|
+
opacity: { duration: 0.25 },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
expanded: {
|
|
15
|
+
height: 'auto',
|
|
16
|
+
opacity: 1,
|
|
17
|
+
transition: {
|
|
18
|
+
height: { duration: 0.4, ease: [0.04, 0.62, 0.23, 0.98] },
|
|
19
|
+
opacity: { duration: 0.3, delay: 0.1 },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Content slide-in animation for expanded row content (staggered after container)
|
|
25
|
+
*/
|
|
26
|
+
const tableExpandContentAnimations = {
|
|
27
|
+
collapsed: {
|
|
28
|
+
opacity: 0,
|
|
29
|
+
y: -10,
|
|
30
|
+
transition: {
|
|
31
|
+
y: { duration: 0.2 },
|
|
32
|
+
opacity: { duration: 0.2 },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
expanded: {
|
|
36
|
+
opacity: 1,
|
|
37
|
+
y: 0,
|
|
38
|
+
transition: {
|
|
39
|
+
delay: 0.15,
|
|
40
|
+
y: { duration: 0.3 },
|
|
41
|
+
opacity: { duration: 0.3 },
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { tableExpandAnimations, tableExpandContentAnimations };
|
|
@@ -17,33 +17,6 @@ declare const TableContext: React.Context<TableContextType>;
|
|
|
17
17
|
* - Pagination support
|
|
18
18
|
* - Full accessibility compliance (WCAG 2.1 AA)
|
|
19
19
|
* - Theme customization with className overrides
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* // Data-driven API with stable row keys
|
|
23
|
-
* <Table data={data} columns={columns} rowKey="id" sortable selectable />
|
|
24
|
-
*
|
|
25
|
-
* // Using a function for complex row keys
|
|
26
|
-
* <Table
|
|
27
|
-
* data={data}
|
|
28
|
-
* columns={columns}
|
|
29
|
-
* rowKey={(row, index) => `${row.category}-${row.id}`}
|
|
30
|
-
* sortable
|
|
31
|
-
* selectable
|
|
32
|
-
* />
|
|
33
|
-
*
|
|
34
|
-
* // Declarative API
|
|
35
|
-
* <Table>
|
|
36
|
-
* <Table.Header>
|
|
37
|
-
* <Table.Row>
|
|
38
|
-
* <Table.HeaderCell>Name</Table.HeaderCell>
|
|
39
|
-
* </Table.Row>
|
|
40
|
-
* </Table.Header>
|
|
41
|
-
* <Table.Body>
|
|
42
|
-
* <Table.Row>
|
|
43
|
-
* <Table.Cell>John Doe</Table.Cell>
|
|
44
|
-
* </Table.Row>
|
|
45
|
-
* </Table.Body>
|
|
46
|
-
* </Table>
|
|
47
20
|
*/
|
|
48
21
|
declare function TableComponent<T extends Record<string, any>>(props: TableProps<T>): React.ReactElement;
|
|
49
22
|
declare namespace TableComponent {
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import React__default, { createContext,
|
|
1
|
+
import React__default, { createContext, useMemo } from 'react';
|
|
2
2
|
import { tableTheme } from './Table.theme.js';
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
|
-
import { TableHeader } from './
|
|
5
|
-
import { TableBody } from './
|
|
6
|
-
import { TableSelectionHeader } from './
|
|
7
|
-
import {
|
|
8
|
-
import '
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { Sortable, SortableItem } from '../Sortable/Sortable.js';
|
|
4
|
+
import { TableHeader } from './TableHeader.js';
|
|
5
|
+
import { TableBody } from './TableBody.js';
|
|
6
|
+
import { TableSelectionHeader } from './TableSelectionHeader.js';
|
|
7
|
+
import { TableColumnManager } from './TableColumnManager.js';
|
|
8
|
+
import { TableFilter } from './TableFilter.js';
|
|
9
|
+
import { useTableColumns } from './hooks/useTableColumns.js';
|
|
10
|
+
import { useTableSelection } from './hooks/useTableSelection.js';
|
|
11
|
+
import { useTablePagination } from './hooks/useTablePagination.js';
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Context for sharing table state across all table components
|
|
@@ -34,131 +33,61 @@ const TableContext = createContext({
|
|
|
34
33
|
* - Pagination support
|
|
35
34
|
* - Full accessibility compliance (WCAG 2.1 AA)
|
|
36
35
|
* - Theme customization with className overrides
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* // Data-driven API with stable row keys
|
|
40
|
-
* <Table data={data} columns={columns} rowKey="id" sortable selectable />
|
|
41
|
-
*
|
|
42
|
-
* // Using a function for complex row keys
|
|
43
|
-
* <Table
|
|
44
|
-
* data={data}
|
|
45
|
-
* columns={columns}
|
|
46
|
-
* rowKey={(row, index) => `${row.category}-${row.id}`}
|
|
47
|
-
* sortable
|
|
48
|
-
* selectable
|
|
49
|
-
* />
|
|
50
|
-
*
|
|
51
|
-
* // Declarative API
|
|
52
|
-
* <Table>
|
|
53
|
-
* <Table.Header>
|
|
54
|
-
* <Table.Row>
|
|
55
|
-
* <Table.HeaderCell>Name</Table.HeaderCell>
|
|
56
|
-
* </Table.Row>
|
|
57
|
-
* </Table.Header>
|
|
58
|
-
* <Table.Body>
|
|
59
|
-
* <Table.Row>
|
|
60
|
-
* <Table.Cell>John Doe</Table.Cell>
|
|
61
|
-
* </Table.Row>
|
|
62
|
-
* </Table.Body>
|
|
63
|
-
* </Table>
|
|
64
36
|
*/
|
|
65
37
|
function TableComponent(props) {
|
|
66
38
|
var _a;
|
|
67
|
-
const { data, columns, rowKey, variant = "default", theme: themeOverrides, className = "", freezeHeader = false, freezeFirstColumn = false, freezeLastColumn = false, sortable = false, sortConfig = [], onSortChange, filterable = false, filterConfig = [], onFilterChange, expandable = false, expandedRowRender, expandedRows = [], onExpandedRowsChange, selectable = false, selectionType = "checkbox", selectedRows = [], onSelectionChange, bulkActions = [], visibleColumns: initialVisibleColumns, onVisibleColumnsChange, onColumnReorder, pagination, children, } = props;
|
|
68
|
-
//
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
39
|
+
const { data, columns, rowKey, variant = "default", theme: themeOverrides, className = "", freezeHeader = false, freezeFirstColumn = false, freezeLastColumn = false, sortable = false, sortConfig = [], onSortChange, filterable = false, filterConfig = [], onFilterChange, expandable = false, expandedRowRender, expandedRows = [], onExpandedRowsChange, selectable = false, selectionType = "checkbox", selectedRows = [], onSelectionChange, bulkActions = [], showColumnManager = false, visibleColumns: initialVisibleColumns, onVisibleColumnsChange, onColumnReorder, pagination, children, } = props;
|
|
40
|
+
// Column management hook
|
|
41
|
+
const { visibleColumns, columnOrder, visibleColumnsList, handleToggleColumn, handleColumnReorder, handleResetToDefault, } = useTableColumns({
|
|
42
|
+
columns,
|
|
43
|
+
initialVisibleColumns,
|
|
44
|
+
onVisibleColumnsChange,
|
|
45
|
+
onColumnReorder,
|
|
46
|
+
});
|
|
47
|
+
// Pagination hook
|
|
48
|
+
const { paginatedData } = useTablePagination({
|
|
49
|
+
data,
|
|
50
|
+
pagination,
|
|
51
|
+
});
|
|
52
|
+
// Selection hook (for clear selection in header)
|
|
53
|
+
const { handleClearSelection } = useTableSelection({
|
|
54
|
+
data: paginatedData,
|
|
55
|
+
rowKey,
|
|
56
|
+
selectionType,
|
|
57
|
+
selectedRows,
|
|
58
|
+
onSelectionChange,
|
|
59
|
+
});
|
|
79
60
|
// Determine which API is being used (declarative vs data-driven)
|
|
80
61
|
const isDeclarativeAPI = !!children;
|
|
81
62
|
// Merge global theme with component-specific overrides
|
|
82
|
-
const theme = {
|
|
63
|
+
const theme = useMemo(() => ({
|
|
83
64
|
...tableTheme,
|
|
84
65
|
...(themeOverrides || {}),
|
|
85
|
-
};
|
|
66
|
+
}), [themeOverrides]);
|
|
86
67
|
// Get base classes from theme
|
|
87
68
|
const baseClasses = theme.baseStyle || "";
|
|
88
69
|
const variantClasses = ((_a = theme.variants) === null || _a === void 0 ? void 0 : _a[variant]) || "";
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
* Resets column order back to the original columns order
|
|
111
|
-
*/
|
|
112
|
-
const handleColumnOrderReset = () => {
|
|
113
|
-
if (columns) {
|
|
114
|
-
const originalOrder = columns.map((col) => col.id);
|
|
115
|
-
setColumnOrder(originalOrder);
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* Handle clearing all row selections
|
|
120
|
-
*/
|
|
121
|
-
const handleClearSelection = () => {
|
|
122
|
-
onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange([]);
|
|
123
|
-
};
|
|
124
|
-
/**
|
|
125
|
-
* Handle toggling column visibility
|
|
126
|
-
* Prevents toggling locked columns
|
|
127
|
-
*/
|
|
128
|
-
const handleToggleColumn = (columnId) => {
|
|
129
|
-
const column = columns === null || columns === void 0 ? void 0 : columns.find(col => col.id === columnId);
|
|
130
|
-
if (column === null || column === void 0 ? void 0 : column.locked)
|
|
131
|
-
return; // Prevent toggling locked columns
|
|
132
|
-
const newVisibleColumns = visibleColumns.includes(columnId)
|
|
133
|
-
? visibleColumns.filter((id) => id !== columnId)
|
|
134
|
-
: [...visibleColumns, columnId];
|
|
135
|
-
handleVisibleColumnsChange(newVisibleColumns);
|
|
136
|
-
};
|
|
137
|
-
/**
|
|
138
|
-
* Handle resetting columns to default visibility and order
|
|
139
|
-
*/
|
|
140
|
-
const handleResetToDefault = () => {
|
|
141
|
-
// Get all locked column IDs to ensure they remain visible
|
|
142
|
-
const lockedColumnIds = (columns === null || columns === void 0 ? void 0 : columns.filter(col => col.locked).map(col => col.id)) || [];
|
|
143
|
-
// Combine initial visible columns with locked columns (remove duplicates)
|
|
144
|
-
const resetVisibleColumns = Array.from(new Set([...defaultVisibleColumns, ...lockedColumnIds]));
|
|
145
|
-
// Reset to initial visible columns with locked columns guaranteed to be visible
|
|
146
|
-
handleVisibleColumnsChange(resetVisibleColumns);
|
|
147
|
-
// Reset column order to default
|
|
148
|
-
handleColumnOrderReset();
|
|
149
|
-
};
|
|
150
|
-
// Filter and order columns based on column order and visibility settings
|
|
151
|
-
const visibleColumnsList = columns && columnOrder.length > 0
|
|
152
|
-
? columnOrder
|
|
153
|
-
.map(colId => columns.find(col => col.id === colId))
|
|
154
|
-
.filter((col) => col !== undefined && visibleColumns.includes(col.id))
|
|
155
|
-
: (columns ? columns.filter((col) => visibleColumns.includes(col.id)) : []);
|
|
156
|
-
// Calculate paginated data slice based on current page and page size
|
|
157
|
-
const paginatedData = pagination && data
|
|
158
|
-
? data.slice((pagination.currentPage - 1) * pagination.pageSize, pagination.currentPage * pagination.pageSize)
|
|
159
|
-
: data || [];
|
|
160
|
-
// Create context value with all table configuration and callbacks
|
|
161
|
-
const contextValue = {
|
|
70
|
+
// Memoize context value to prevent unnecessary re-renders in consumers
|
|
71
|
+
const contextValue = useMemo(() => ({
|
|
72
|
+
theme,
|
|
73
|
+
variant,
|
|
74
|
+
freezeHeader,
|
|
75
|
+
freezeFirstColumn,
|
|
76
|
+
freezeLastColumn,
|
|
77
|
+
sortable,
|
|
78
|
+
sortConfig,
|
|
79
|
+
onSortChange,
|
|
80
|
+
filterable,
|
|
81
|
+
filterConfig,
|
|
82
|
+
onFilterChange,
|
|
83
|
+
expandable,
|
|
84
|
+
expandedRows,
|
|
85
|
+
onExpandedRowsChange,
|
|
86
|
+
selectable,
|
|
87
|
+
selectionType,
|
|
88
|
+
selectedRows,
|
|
89
|
+
onSelectionChange,
|
|
90
|
+
}), [
|
|
162
91
|
theme,
|
|
163
92
|
variant,
|
|
164
93
|
freezeHeader,
|
|
@@ -177,47 +106,20 @@ function TableComponent(props) {
|
|
|
177
106
|
selectionType,
|
|
178
107
|
selectedRows,
|
|
179
108
|
onSelectionChange,
|
|
180
|
-
|
|
109
|
+
]);
|
|
181
110
|
return (React__default.createElement(TableContext.Provider, { value: contextValue },
|
|
182
111
|
React__default.createElement("div", { className: "relative" },
|
|
183
|
-
!isDeclarativeAPI && columns && (React__default.createElement("div", { className: theme.columnManagerContainer },
|
|
184
|
-
React__default.createElement(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
React__default.createElement(Cog6ToothIcon, { className: "size-5", "aria-hidden": "true" }),
|
|
188
|
-
"Manage Columns")),
|
|
189
|
-
React__default.createElement(Popover.Content, { className: "p-0" },
|
|
190
|
-
React__default.createElement("div", { className: "w-64 p-3 overflow-hidden bg-white", role: "dialog", "aria-labelledby": "column-manager-title", "aria-describedby": "column-manager-description", "aria-modal": "true" },
|
|
191
|
-
React__default.createElement("div", { id: "column-manager-title", className: "text-xs uppercase font-bold mb-3 text-[var(--color-text-placeholder)]" }, "Manage Columns"),
|
|
192
|
-
React__default.createElement("div", { id: "column-manager-description", className: "sr-only" }, "Use checkboxes to control which columns are visible in the table. Locked columns cannot be hidden."),
|
|
193
|
-
React__default.createElement("div", { className: "space-y-0.5", role: "group", "aria-label": "Column visibility options" }, onColumnReorder ? (React__default.createElement(Sortable, { onReorder: handleColumnReorder, showDragHandle: true, className: "space-y-0.5" }, (columnOrder.length > 0
|
|
194
|
-
? columnOrder.map(colId => columns.find(col => col.id === colId)).filter(Boolean)
|
|
195
|
-
: columns).map((column) => {
|
|
196
|
-
const isVisible = visibleColumns.includes(column.id);
|
|
197
|
-
const isLocked = column.locked === true;
|
|
198
|
-
const displayName = typeof column.header === "string" ? column.header : column.id;
|
|
199
|
-
return (React__default.createElement(SortableItem, { key: column.id, id: column.id, disabled: isLocked, className: `bg-white hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${isLocked ? "bg-gray-50" : ""}` },
|
|
200
|
-
React__default.createElement(Checkbox, { id: `column-checkbox-${column.id}`, name: `column-${column.id}`, value: column.id, checked: isVisible, onChange: () => handleToggleColumn(column.id), "aria-label": `Toggle visibility for ${displayName} column`, label: displayName, state: isLocked ? "disabled" : "default" })));
|
|
201
|
-
}))) : ((columnOrder.length > 0
|
|
202
|
-
? columnOrder.map(colId => columns.find(col => col.id === colId)).filter(Boolean)
|
|
203
|
-
: columns).map((column) => {
|
|
204
|
-
const isVisible = visibleColumns.includes(column.id);
|
|
205
|
-
const isLocked = column.locked === true;
|
|
206
|
-
const displayName = typeof column.header === "string" ? column.header : column.id;
|
|
207
|
-
return (React__default.createElement("div", { key: column.id, className: `bg-white hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${isLocked ? "bg-gray-50" : ""}` },
|
|
208
|
-
React__default.createElement(Checkbox, { id: `column-checkbox-${column.id}`, name: `column-${column.id}`, value: column.id, checked: isVisible, onChange: () => handleToggleColumn(column.id), "aria-label": `Toggle visibility for ${displayName} column`, label: displayName, state: isLocked ? "disabled" : "default" })));
|
|
209
|
-
}))),
|
|
210
|
-
React__default.createElement("div", { className: "mt-3 flex justify-end" },
|
|
211
|
-
React__default.createElement(Button, { color: "neutral", variant: "filled", className: "w-full", onClick: handleResetToDefault }, "Reset to Default"))))))),
|
|
112
|
+
!isDeclarativeAPI && columns && showColumnManager && (React__default.createElement("div", { className: theme.columnManagerContainer },
|
|
113
|
+
React__default.createElement(TableColumnManager, { columns: columns, visibleColumns: visibleColumns, columnOrder: columnOrder, onToggleColumn: handleToggleColumn, onResetToDefault: handleResetToDefault, onColumnReorder: onColumnReorder ? handleColumnReorder : undefined }))),
|
|
114
|
+
!isDeclarativeAPI && filterable && onFilterChange && columns && (React__default.createElement("div", { className: "mb-3" },
|
|
115
|
+
React__default.createElement(TableFilter, { columns: columns, filterConfig: filterConfig, onFilterChange: onFilterChange }))),
|
|
212
116
|
!isDeclarativeAPI && selectable && selectedRows.length > 0 && (React__default.createElement(TableSelectionHeader, { selectedCount: selectedRows.length, totalCount: paginatedData.length, selectedRows: selectedRows, bulkActions: bulkActions, onClearSelection: handleClearSelection })),
|
|
213
117
|
React__default.createElement("div", { className: "overflow-x-auto" },
|
|
214
118
|
React__default.createElement("table", { className: cn(baseClasses, variantClasses, className), role: "table", "aria-label": isDeclarativeAPI ? "Data table" : `Data table with ${paginatedData.length} rows`, "aria-rowcount": pagination ? pagination.totalItems : data === null || data === void 0 ? void 0 : data.length, "aria-colcount": visibleColumnsList.length }, isDeclarativeAPI ? (children) : (React__default.createElement(React__default.Fragment, null,
|
|
215
119
|
React__default.createElement(TableHeader, { columns: visibleColumnsList, sortConfig: sortConfig, onSortChange: onSortChange, filterConfig: filterConfig, onFilterChange: onFilterChange, freezeHeader: freezeHeader, freezeFirstColumn: freezeFirstColumn, freezeLastColumn: freezeLastColumn, expandable: expandable, expandedRowRender: expandedRowRender, selectable: selectable, selectionType: selectionType, selectedRows: selectedRows, onSelectionChange: onSelectionChange, totalRowCount: paginatedData.length, theme: theme, data: paginatedData, rowKey: rowKey }),
|
|
216
120
|
React__default.createElement(TableBody, { data: paginatedData, columns: visibleColumnsList, rowKey: rowKey, expandedRowRender: expandedRowRender, expandedRows: expandedRows, onExpandedRowsChange: onExpandedRowsChange, selectable: selectable, selectionType: selectionType, selectedRows: selectedRows, onSelectionChange: onSelectionChange, freezeFirstColumn: freezeFirstColumn, freezeLastColumn: freezeLastColumn, theme: theme }))))))));
|
|
217
121
|
}
|
|
218
|
-
// Set display name for dev tools and Storybook
|
|
219
122
|
TableComponent.displayName = "Table";
|
|
220
|
-
// Export as default
|
|
221
123
|
const Table = TableComponent;
|
|
222
124
|
|
|
223
125
|
export { Table, TableContext };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const tableTheme = {
|
|
2
2
|
// Base styles for the table
|
|
3
|
+
// Uses border-separate so sticky cells keep their borders (border-collapse
|
|
4
|
+
// paints borders on the table grid, which sticky cells float above)
|
|
3
5
|
// Light: white background | Dark: neutral-900 background
|
|
4
|
-
baseStyle: "w-full border-
|
|
6
|
+
baseStyle: "w-full border-separate border-spacing-0 text-sm " +
|
|
5
7
|
"bg-white dark:bg-[var(--color-neutral-900)]",
|
|
6
8
|
// Variant styles
|
|
7
9
|
// Each variant gets dark mode border colors and alternate row colors
|
|
@@ -11,8 +13,8 @@ const tableTheme = {
|
|
|
11
13
|
striped: "border-[var(--color-border)] dark:border-[var(--color-neutral-700)] " +
|
|
12
14
|
"[&>tbody>tr:nth-child(odd)]:bg-[var(--color-neutral-50)] dark:[&>tbody>tr:nth-child(odd)]:bg-[var(--color-neutral-800)] " +
|
|
13
15
|
"[&_td]:px-3 [&_td]:py-2.5 [&_th]:px-3 [&_th]:py-2.5",
|
|
14
|
-
bordered: "border border-[var(--color-border)] dark:border-[var(--color-neutral-700)] " +
|
|
15
|
-
"[&_td]:border [&_th]:border " +
|
|
16
|
+
bordered: "border-t border-l border-[var(--color-border)] dark:border-[var(--color-neutral-700)] " +
|
|
17
|
+
"[&_td]:border-b [&_td]:border-r [&_th]:border-b [&_th]:border-r " +
|
|
16
18
|
"[&_td]:border-[var(--color-border)] [&_th]:border-[var(--color-border)] " +
|
|
17
19
|
"dark:[&_td]:border-[var(--color-neutral-700)] dark:[&_th]:border-[var(--color-neutral-700)] " +
|
|
18
20
|
"[&_td]:px-3 [&_td]:py-2.5 [&_th]:px-3 [&_th]:py-2.5",
|
|
@@ -24,29 +26,36 @@ const tableTheme = {
|
|
|
24
26
|
headerStyle: "text-left font-medium sticky top-0 border-b " +
|
|
25
27
|
"text-[var(--color-text-primary)] border-[var(--color-border)] " +
|
|
26
28
|
"dark:text-[var(--color-neutral-200)] dark:border-[var(--color-neutral-700)]",
|
|
27
|
-
// Cell styles
|
|
28
|
-
// Light: primary text
|
|
29
|
-
cellStyle: "border-
|
|
30
|
-
"text-[var(--color-text-primary)]
|
|
31
|
-
"dark:
|
|
32
|
-
// Row styles
|
|
29
|
+
// Cell styles — borders on cells (not rows) so sticky columns keep them
|
|
30
|
+
// Light: primary text | Dark: neutral-300 text
|
|
31
|
+
cellStyle: "border-b border-b-[var(--color-border)] " +
|
|
32
|
+
"text-[var(--color-text-primary)] " +
|
|
33
|
+
"dark:border-b-[var(--color-neutral-700)] dark:text-[var(--color-neutral-300)]",
|
|
34
|
+
// Row styles — hover and layout only (borders moved to cells)
|
|
33
35
|
// Light: neutral-50 hover | Dark: neutral-800 hover
|
|
34
|
-
rowStyle: "transition-all duration-300 relative " +
|
|
35
|
-
"hover:bg-[var(--color-neutral-50)]
|
|
36
|
+
rowStyle: "group transition-all duration-300 relative " +
|
|
37
|
+
"hover:bg-[var(--color-neutral-50)] " +
|
|
38
|
+
"dark:hover:bg-[var(--color-neutral-800)]",
|
|
36
39
|
// Selected row styles
|
|
37
40
|
// Light: primary-50 background | Dark: primary-900/50 background with adjusted shadow
|
|
38
41
|
selectedRowStyle: "shadow-[inset_3px_0_0_0_var(--color-primary)] " +
|
|
39
42
|
"bg-[var(--color-primary-50)]/50 hover:bg-[var(--color-primary-50)] " +
|
|
40
43
|
"dark:bg-[var(--color-primary-900)]/30 dark:hover:bg-[var(--color-primary-900)]/50",
|
|
41
44
|
hoverRowStyle: "cursor-pointer",
|
|
42
|
-
// Frozen column styles
|
|
43
|
-
//
|
|
44
|
-
frozenColumnStyle: "sticky left-0 z-10 backdrop-blur-sm shadow-l-xl
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
"bg-
|
|
49
|
-
"dark:
|
|
45
|
+
// Frozen column styles — borders are on the cell (via cellStyle) so they
|
|
46
|
+
// travel with the sticky element. Only need vertical separator borders here.
|
|
47
|
+
frozenColumnStyle: "sticky left-0 z-10 backdrop-blur-sm shadow-l-xl " +
|
|
48
|
+
"border-r border-r-[var(--color-neutral-200)] " +
|
|
49
|
+
"bg-white/80 " +
|
|
50
|
+
"group-hover:bg-[var(--color-neutral-50)] " +
|
|
51
|
+
"dark:bg-[var(--color-neutral-900)]/80 dark:border-r-[var(--color-neutral-700)] " +
|
|
52
|
+
"dark:group-hover:bg-[var(--color-neutral-800)]",
|
|
53
|
+
lastFrozenColumnStyle: "sticky right-0 z-10 backdrop-blur-sm shadow-r-xl " +
|
|
54
|
+
"border-l border-l-[var(--color-neutral-200)] " +
|
|
55
|
+
"bg-white/80 " +
|
|
56
|
+
"group-hover:bg-[var(--color-neutral-50)] " +
|
|
57
|
+
"dark:bg-[var(--color-neutral-900)]/80 dark:border-l-[var(--color-neutral-700)] " +
|
|
58
|
+
"dark:group-hover:bg-[var(--color-neutral-800)]",
|
|
50
59
|
frozenHeaderStyle: "sticky top-0 z-20 " +
|
|
51
60
|
"shadow-lg shadow-[var(--color-neutral-200)]/50 " +
|
|
52
61
|
"dark:shadow-[var(--color-neutral-900)]/50",
|