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
|
@@ -22,6 +22,15 @@ export type TableVariant = 'default' | 'striped' | 'bordered' | 'compact';
|
|
|
22
22
|
export type TableAlignment = 'left' | 'center' | 'right';
|
|
23
23
|
/** Selection control types for row selection */
|
|
24
24
|
export type SelectionType = 'checkbox' | 'radio';
|
|
25
|
+
/** Filter operator types for column filtering */
|
|
26
|
+
export type FilterOperator = 'equals' | 'contains' | 'startsWith' | 'endsWith' | 'greaterThan' | 'lessThan';
|
|
27
|
+
/** Filter type for column filter UI */
|
|
28
|
+
export type FilterType = 'text' | 'select' | 'number';
|
|
29
|
+
/** Option for select-type filter columns */
|
|
30
|
+
export interface FilterOption {
|
|
31
|
+
label: string;
|
|
32
|
+
value: string;
|
|
33
|
+
}
|
|
25
34
|
/**
|
|
26
35
|
* Column definition for table data display and behavior
|
|
27
36
|
*/
|
|
@@ -38,6 +47,10 @@ export interface Column<T = any> {
|
|
|
38
47
|
sortable?: boolean;
|
|
39
48
|
/** Enable filtering for this column */
|
|
40
49
|
filterable?: boolean;
|
|
50
|
+
/** Type of filter UI to display */
|
|
51
|
+
filterType?: FilterType;
|
|
52
|
+
/** Options for select-type filter columns */
|
|
53
|
+
filterOptions?: FilterOption[];
|
|
41
54
|
/** Truncate long content with ellipsis */
|
|
42
55
|
ellipsis?: boolean;
|
|
43
56
|
/** Show tooltip on hover - boolean or function returning tooltip text */
|
|
@@ -70,6 +83,8 @@ export interface FilterConfig {
|
|
|
70
83
|
columnId: string;
|
|
71
84
|
/** Filter value - type depends on column data type */
|
|
72
85
|
value: any;
|
|
86
|
+
/** Filter operator for comparison */
|
|
87
|
+
operator?: FilterOperator;
|
|
73
88
|
}
|
|
74
89
|
export interface TableThemeOverrides {
|
|
75
90
|
baseStyle?: string;
|
|
@@ -120,13 +135,6 @@ export interface TableProps<T = any> {
|
|
|
120
135
|
/**
|
|
121
136
|
* Property name or function to extract stable row identifiers for React keys and selection.
|
|
122
137
|
* Provides consistent component identity during row reordering or updates.
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* // Using a property name
|
|
126
|
-
* rowKey="id"
|
|
127
|
-
*
|
|
128
|
-
* // Using a function for complex keys
|
|
129
|
-
* rowKey={(row, index) => `${row.category}-${row.id}`}
|
|
130
138
|
*/
|
|
131
139
|
rowKey?: keyof T | ((row: T, index: number) => string | number);
|
|
132
140
|
/** Visual variant for different table styles */
|
|
@@ -228,7 +236,6 @@ export interface InternalTableHeaderProps<T> {
|
|
|
228
236
|
export interface InternalTableBodyProps<T> {
|
|
229
237
|
data: T[];
|
|
230
238
|
columns: Column<T>[];
|
|
231
|
-
/** Row key extractor for stable row identification */
|
|
232
239
|
rowKey?: keyof T | ((row: T, index: number) => string | number);
|
|
233
240
|
expandedRowRender?: (row: T) => ReactNode;
|
|
234
241
|
expandedRows?: string[];
|
|
@@ -266,3 +273,83 @@ export interface InternalTableCellProps<T> {
|
|
|
266
273
|
theme?: TableThemeOverrides;
|
|
267
274
|
children?: ReactNode;
|
|
268
275
|
}
|
|
276
|
+
export type ActionVariant = 'default' | 'danger';
|
|
277
|
+
export type ActionPriority = 'high' | 'normal';
|
|
278
|
+
export interface ActionItem<T = any> {
|
|
279
|
+
/** Unique identifier for the action */
|
|
280
|
+
id: string;
|
|
281
|
+
/** Display label for the action */
|
|
282
|
+
label: string;
|
|
283
|
+
/** Icon component to display */
|
|
284
|
+
icon: React.ComponentType<{
|
|
285
|
+
className?: string;
|
|
286
|
+
}>;
|
|
287
|
+
/** Click handler that receives the row data */
|
|
288
|
+
onClick: (row: T) => void;
|
|
289
|
+
/** Visual variant for styling (default: 'default') */
|
|
290
|
+
variant?: ActionVariant;
|
|
291
|
+
/** Priority level for display ordering (default: 'normal') */
|
|
292
|
+
priority?: ActionPriority;
|
|
293
|
+
/** Function to determine if action should be disabled */
|
|
294
|
+
disabled?: (row: T) => boolean;
|
|
295
|
+
}
|
|
296
|
+
export interface TableActionsProps<T = any> {
|
|
297
|
+
/** Array of action items to display */
|
|
298
|
+
actions: ActionItem<T>[];
|
|
299
|
+
/** Row data to pass to action handlers */
|
|
300
|
+
row: T;
|
|
301
|
+
/** Maximum number of actions to show inline before using menu (default: 2) */
|
|
302
|
+
maxVisibleActions?: number;
|
|
303
|
+
/** Additional CSS class name */
|
|
304
|
+
className?: string;
|
|
305
|
+
}
|
|
306
|
+
export interface TableActionsMenuProps<T = any> {
|
|
307
|
+
/** Array of action items to display in menu */
|
|
308
|
+
actions: ActionItem<T>[];
|
|
309
|
+
/** Row data to pass to action handlers */
|
|
310
|
+
row: T;
|
|
311
|
+
/** Function to close the menu */
|
|
312
|
+
onClose: () => void;
|
|
313
|
+
/** Additional CSS class name */
|
|
314
|
+
className?: string;
|
|
315
|
+
}
|
|
316
|
+
export interface TablePaginationProps {
|
|
317
|
+
/** Current active page number (1-based) */
|
|
318
|
+
currentPage: number;
|
|
319
|
+
/** Total number of items across all pages */
|
|
320
|
+
totalItems: number;
|
|
321
|
+
/** Number of items per page */
|
|
322
|
+
pageSize: number;
|
|
323
|
+
/** Available page size options */
|
|
324
|
+
pageSizeOptions?: number[];
|
|
325
|
+
/** Callback when page changes */
|
|
326
|
+
onPageChange: (page: number) => void;
|
|
327
|
+
/** Callback when page size changes */
|
|
328
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
329
|
+
/** Whether to show the page size selector */
|
|
330
|
+
showPageSizeSelector?: boolean;
|
|
331
|
+
/** Additional CSS classes */
|
|
332
|
+
className?: string;
|
|
333
|
+
}
|
|
334
|
+
export interface TableSelectionHeaderProps {
|
|
335
|
+
selectedCount: number;
|
|
336
|
+
totalCount: number;
|
|
337
|
+
selectedRows: string[];
|
|
338
|
+
bulkActions?: BulkAction[];
|
|
339
|
+
onClearSelection: () => void;
|
|
340
|
+
className?: string;
|
|
341
|
+
}
|
|
342
|
+
export interface TableColumnManagerProps<T = any> {
|
|
343
|
+
columns: Column<T>[];
|
|
344
|
+
visibleColumns: string[];
|
|
345
|
+
columnOrder: string[];
|
|
346
|
+
onToggleColumn: (columnId: string) => void;
|
|
347
|
+
onResetToDefault: () => void;
|
|
348
|
+
onColumnReorder?: (fromIndex: number, toIndex: number) => void;
|
|
349
|
+
}
|
|
350
|
+
export interface TableFilterProps<T = any> {
|
|
351
|
+
columns: Column<T>[];
|
|
352
|
+
filterConfig: FilterConfig[];
|
|
353
|
+
onFilterChange: (filterConfig: FilterConfig[]) => void;
|
|
354
|
+
className?: string;
|
|
355
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import { TableAlignment } from './Table.types';
|
|
2
|
+
/** Constant for the utility column ID used in selection/expansion columns */
|
|
3
|
+
export declare const UTILITY_COLUMN_ID = "utility";
|
|
4
|
+
/** Width value for the utility column (1px + nowrap = shrink-to-content) */
|
|
5
|
+
export declare const UTILITY_COLUMN_WIDTH = 1;
|
|
6
|
+
/** Tailwind JIT-safe alignment class mapping */
|
|
7
|
+
export declare const alignmentClasses: Record<TableAlignment, string>;
|
|
1
8
|
/**
|
|
2
9
|
* Generate a stable row identifier for React keys and row IDs
|
|
3
10
|
* @param row - The data row object
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/** Constant for the utility column ID used in selection/expansion columns */
|
|
2
|
+
const UTILITY_COLUMN_ID = 'utility';
|
|
3
|
+
/** Width value for the utility column (1px + nowrap = shrink-to-content) */
|
|
4
|
+
const UTILITY_COLUMN_WIDTH = 1;
|
|
5
|
+
/** Tailwind JIT-safe alignment class mapping */
|
|
6
|
+
const alignmentClasses = {
|
|
7
|
+
left: 'text-left',
|
|
8
|
+
center: 'text-center',
|
|
9
|
+
right: 'text-right',
|
|
10
|
+
};
|
|
1
11
|
/**
|
|
2
12
|
* Generate a stable row identifier for React keys and row IDs
|
|
3
13
|
* @param row - The data row object
|
|
@@ -27,4 +37,4 @@ function getRowId(row, index, rowKey) {
|
|
|
27
37
|
return `row-${key}`;
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
export { getRowId };
|
|
40
|
+
export { UTILITY_COLUMN_ID, UTILITY_COLUMN_WIDTH, alignmentClasses, getRowId };
|
package/dist/components/core/Table/{components/TableActions/TableActions.d.ts → TableActions.d.ts}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { TableActionsProps } from "./
|
|
2
|
+
import { TableActionsProps } from "./Table.types";
|
|
3
3
|
/**
|
|
4
4
|
* TableActions component with smart display logic
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
5
|
+
* - <=2 actions: Show as individual icon buttons
|
|
6
|
+
* - >=3 actions: Show all actions in overflow menu using Dropdown
|
|
7
7
|
*/
|
|
8
8
|
export declare const TableActions: <T>({ actions, row, maxVisibleActions, className, }: TableActionsProps<T>) => React.JSX.Element;
|
package/dist/components/core/Table/{components/TableActions/TableActions.js → TableActions.js}
RENAMED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import React__default, { useMemo } from 'react';
|
|
2
2
|
import { EllipsisVerticalIcon } from '@heroicons/react/24/outline';
|
|
3
|
-
import { cn } from '
|
|
4
|
-
import { Dropdown } from '
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
7
|
-
import '
|
|
8
|
-
import '
|
|
9
|
-
import '
|
|
10
|
-
import { Button } from '
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { Dropdown } from '../Dropdown/Dropdown.js';
|
|
5
|
+
import '../Dropdown/DropdownTrigger.js';
|
|
6
|
+
import '../Dropdown/DropdownMenu.js';
|
|
7
|
+
import '../Dropdown/DropdownItem.js';
|
|
8
|
+
import '../Dropdown/DropdownSection.js';
|
|
9
|
+
import '../Dropdown/DropdownSeparator.js';
|
|
10
|
+
import { Button } from '../Button/Button.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* TableActions component with smart display logic
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
14
|
+
* - <=2 actions: Show as individual icon buttons
|
|
15
|
+
* - >=3 actions: Show all actions in overflow menu using Dropdown
|
|
16
16
|
*/
|
|
17
17
|
const TableActions = ({ actions, row, maxVisibleActions = 2, className, }) => {
|
|
18
|
-
// Sort actions by priority (high priority first)
|
|
19
18
|
const sortedActions = useMemo(() => {
|
|
20
19
|
return [...actions].sort((a, b) => {
|
|
21
20
|
const priorityOrder = { high: 0, normal: 1 };
|
|
@@ -24,15 +23,12 @@ const TableActions = ({ actions, row, maxVisibleActions = 2, className, }) => {
|
|
|
24
23
|
return aPriority - bPriority;
|
|
25
24
|
});
|
|
26
25
|
}, [actions]);
|
|
27
|
-
// Determine display strategy
|
|
28
26
|
const shouldUseMenu = actions.length > maxVisibleActions;
|
|
29
|
-
// Get disabled keys for Dropdown
|
|
30
27
|
const disabledKeys = useMemo(() => {
|
|
31
28
|
return sortedActions
|
|
32
29
|
.filter((action) => { var _a; return (_a = action.disabled) === null || _a === void 0 ? void 0 : _a.call(action, row); })
|
|
33
30
|
.map((action) => action.id);
|
|
34
31
|
}, [sortedActions, row]);
|
|
35
|
-
// Handle action click from Dropdown
|
|
36
32
|
const handleAction = (key) => {
|
|
37
33
|
var _a;
|
|
38
34
|
const action = sortedActions.find((a) => a.id === key);
|
|
@@ -40,34 +36,28 @@ const TableActions = ({ actions, row, maxVisibleActions = 2, className, }) => {
|
|
|
40
36
|
action.onClick(row);
|
|
41
37
|
}
|
|
42
38
|
};
|
|
43
|
-
// Render individual action buttons
|
|
44
39
|
const renderInlineActions = (actionsToRender) => {
|
|
45
40
|
return actionsToRender.map((action) => {
|
|
46
41
|
var _a;
|
|
47
42
|
const isDisabled = (_a = action.disabled) === null || _a === void 0 ? void 0 : _a.call(action, row);
|
|
48
43
|
const Icon = action.icon;
|
|
49
44
|
return (React__default.createElement(Button, { key: action.id, color: "primary", variant: "link", iconOnly: true, onClick: () => action.onClick(row), disabled: isDisabled, "aria-label": action.label, className: cn(action.variant === "danger"
|
|
50
|
-
? "text-
|
|
51
|
-
: "text-
|
|
45
|
+
? "text-[var(--color-danger-400)] hover:text-[var(--color-danger)] dark:text-[var(--color-danger-400)] dark:hover:text-[var(--color-danger-300)]"
|
|
46
|
+
: "text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] dark:text-[var(--color-text-muted)] dark:hover:text-[var(--color-text-secondary)]") },
|
|
52
47
|
React__default.createElement(Icon, { className: "size-4" })));
|
|
53
48
|
});
|
|
54
49
|
};
|
|
55
|
-
// Render overflow menu using Dropdown
|
|
56
50
|
const renderOverflowMenu = () => {
|
|
57
51
|
return (React__default.createElement(Dropdown, { placement: "bottom-end", offset: 4, disabledKeys: disabledKeys, onAction: handleAction },
|
|
58
52
|
React__default.createElement(Dropdown.Trigger, null,
|
|
59
|
-
React__default.createElement(Button, { color: "neutral", variant: "
|
|
53
|
+
React__default.createElement(Button, { color: "neutral", variant: "outline", size: "sm", iconOnly: true, "aria-label": "More actions", className: "text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)]" },
|
|
60
54
|
React__default.createElement(EllipsisVerticalIcon, { className: "size-4" }))),
|
|
61
55
|
React__default.createElement(Dropdown.Menu, { "aria-label": "Row actions" }, sortedActions.map((action) => {
|
|
62
56
|
const Icon = action.icon;
|
|
63
57
|
return (React__default.createElement(Dropdown.Item, { key: action.id, itemKey: action.id, isDanger: action.variant === "danger", startContent: React__default.createElement(Icon, { className: "size-4" }) }, action.label));
|
|
64
58
|
}))));
|
|
65
59
|
};
|
|
66
|
-
return (React__default.createElement("div", { className: cn("flex items-center justify-end", className) }, shouldUseMenu
|
|
67
|
-
? // All actions in overflow menu
|
|
68
|
-
renderOverflowMenu()
|
|
69
|
-
: // Show actions inline
|
|
70
|
-
renderInlineActions(sortedActions)));
|
|
60
|
+
return (React__default.createElement("div", { className: cn("flex items-center justify-end", className) }, shouldUseMenu ? renderOverflowMenu() : renderInlineActions(sortedActions)));
|
|
71
61
|
};
|
|
72
62
|
|
|
73
63
|
export { TableActions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
|
-
import { cn } from '
|
|
2
|
+
import { cn } from '../../../utils/cn.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TableActionsMenu component for displaying actions in an overflow menu
|
|
@@ -12,12 +12,12 @@ const TableActionsMenu = ({ actions, row, onClose, className, }) => {
|
|
|
12
12
|
action.onClick(row);
|
|
13
13
|
onClose();
|
|
14
14
|
};
|
|
15
|
-
return (React__default.createElement("div", { className: cn("
|
|
15
|
+
return (React__default.createElement("div", { className: cn("min-w-[180px] p-1", className), role: "menu", "aria-label": "Row actions" }, actions.map((action) => {
|
|
16
16
|
var _a;
|
|
17
17
|
const isDisabled = (_a = action.disabled) === null || _a === void 0 ? void 0 : _a.call(action, row);
|
|
18
18
|
const Icon = action.icon;
|
|
19
|
-
return (React__default.createElement("button", { key: action.id, onClick: () => handleActionClick(action), disabled: isDisabled, className: cn("w-full flex items-center gap-3 px-3 py-2 text-sm font-medium text-left transition-all duration-300", "hover:bg-
|
|
20
|
-
? "text-danger
|
|
19
|
+
return (React__default.createElement("button", { key: action.id, onClick: () => handleActionClick(action), disabled: isDisabled, className: cn("w-full flex items-center gap-3 px-3 py-2 text-sm font-medium text-left transition-all duration-300", "hover:bg-[var(--color-background-secondary)] focus:bg-[var(--color-background-secondary)] focus:outline-none rounded-sm cursor-pointer", action.variant === 'danger'
|
|
20
|
+
? "text-[var(--color-danger)] hover:bg-[var(--color-danger-50)] focus:bg-[var(--color-danger-50)]"
|
|
21
21
|
: "text-[var(--color-text-primary)]", isDisabled && "opacity-50 cursor-not-allowed hover:bg-transparent"), role: "menuitem", "aria-label": action.label },
|
|
22
22
|
React__default.createElement(Icon, { className: "size-4 flex-shrink-0" }),
|
|
23
23
|
React__default.createElement("span", null, action.label)));
|
|
@@ -1,32 +1,26 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
2
|
import { TableRow } from './TableRow.js';
|
|
3
|
-
import { getRowId } from '
|
|
3
|
+
import { getRowId } from './Table.utils.js';
|
|
4
|
+
import { useTableExpansion } from './hooks/useTableExpansion.js';
|
|
5
|
+
import { useTableSelection } from './hooks/useTableSelection.js';
|
|
4
6
|
|
|
5
7
|
function TableBodyComponent({ data, columns, rowKey, expandedRowRender, expandedRows = [], onExpandedRowsChange, selectable, selectionType, selectedRows = [], onSelectionChange, freezeFirstColumn, freezeLastColumn, theme, }) {
|
|
6
|
-
const handleExpandChange = (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const newSelectedRows = selectionType === 'checkbox'
|
|
18
|
-
? selected
|
|
19
|
-
? [...selectedRows, rowId]
|
|
20
|
-
: selectedRows.filter(id => id !== rowId)
|
|
21
|
-
: selected ? [rowId] : [];
|
|
22
|
-
onSelectionChange(newSelectedRows);
|
|
23
|
-
};
|
|
8
|
+
const { handleExpandChange } = useTableExpansion({
|
|
9
|
+
expandedRows,
|
|
10
|
+
onExpandedRowsChange,
|
|
11
|
+
});
|
|
12
|
+
const { handleSelectionChange } = useTableSelection({
|
|
13
|
+
data,
|
|
14
|
+
rowKey,
|
|
15
|
+
selectionType,
|
|
16
|
+
selectedRows,
|
|
17
|
+
onSelectionChange,
|
|
18
|
+
});
|
|
24
19
|
return (React__default.createElement("tbody", null, data.map((row, index) => {
|
|
25
20
|
const rowId = getRowId(row, index, rowKey);
|
|
26
21
|
return (React__default.createElement(TableRow, { key: rowId, row: row, rowId: rowId, columns: columns, expandedRowRender: expandedRowRender, isExpanded: expandedRows.includes(rowId), onExpandChange: (expanded) => handleExpandChange(rowId, expanded), selectable: selectable, selectionType: selectionType, isSelected: selectedRows.includes(rowId), onSelectionChange: (selected) => handleSelectionChange(rowId, selected), freezeFirstColumn: freezeFirstColumn, freezeLastColumn: freezeLastColumn, theme: theme }));
|
|
27
22
|
})));
|
|
28
23
|
}
|
|
29
|
-
// Export with proper type annotation
|
|
30
24
|
const TableBody = TableBodyComponent;
|
|
31
25
|
|
|
32
26
|
export { TableBody };
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { InternalTableCellProps } from '
|
|
2
|
+
import { InternalTableCellProps } from './Table.types';
|
|
3
3
|
/**
|
|
4
4
|
* Internal TableCell component used by the data-driven API
|
|
5
5
|
* Handles both header and data cells with proper theming and accessibility
|
|
6
6
|
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Dynamic cell type (th/td) based on isHeader prop
|
|
9
|
-
* - Frozen column support with visual indicators
|
|
10
|
-
* - Custom cell rendering via column.cell function
|
|
11
|
-
* - Tooltip support for truncated content
|
|
12
|
-
* - Alignment and width customization
|
|
13
|
-
* - Full accessibility with proper ARIA attributes
|
|
14
|
-
*
|
|
15
7
|
* @internal This component is used internally by the Table component
|
|
16
8
|
*/
|
|
17
9
|
declare function TableCellComponent<T extends Record<string, any>>({ column, row, rowId, isHeader, isFrozen, isLastFrozen, theme, children, }: InternalTableCellProps<T>): React.ReactElement;
|
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import React__default from 'react';
|
|
2
|
-
import { cn } from '
|
|
2
|
+
import { cn } from '../../../utils/cn.js';
|
|
3
|
+
import { UTILITY_COLUMN_ID, alignmentClasses } from './Table.utils.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Internal TableCell component used by the data-driven API
|
|
6
7
|
* Handles both header and data cells with proper theming and accessibility
|
|
7
8
|
*
|
|
8
|
-
* Features:
|
|
9
|
-
* - Dynamic cell type (th/td) based on isHeader prop
|
|
10
|
-
* - Frozen column support with visual indicators
|
|
11
|
-
* - Custom cell rendering via column.cell function
|
|
12
|
-
* - Tooltip support for truncated content
|
|
13
|
-
* - Alignment and width customization
|
|
14
|
-
* - Full accessibility with proper ARIA attributes
|
|
15
|
-
*
|
|
16
9
|
* @internal This component is used internally by the Table component
|
|
17
10
|
*/
|
|
18
11
|
function TableCellComponent({ column, row, rowId, isHeader = false, isFrozen = false, isLastFrozen = false, theme, children, }) {
|
|
19
12
|
const Cell = isHeader ? 'th' : 'td';
|
|
13
|
+
const isUtilityColumn = column.id === UTILITY_COLUMN_ID;
|
|
20
14
|
// For header cells, render the column header content
|
|
21
15
|
if (isHeader) {
|
|
22
|
-
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.headerStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), column.align &&
|
|
16
|
+
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.headerStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), column.align && alignmentClasses[column.align], isUtilityColumn && 'whitespace-nowrap');
|
|
23
17
|
return (React__default.createElement(Cell, { className: cellClasses, "data-frozen": isFrozen ? 'true' : isLastFrozen ? 'last' : undefined, style: { width: column.width }, role: "columnheader", "aria-label": typeof column.header === 'string' ? column.header : column.id }, children || column.header));
|
|
24
18
|
}
|
|
25
19
|
// For data cells, extract value using accessor (string key or function)
|
|
@@ -34,12 +28,10 @@ function TableCellComponent({ column, row, rowId, isHeader = false, isFrozen = f
|
|
|
34
28
|
: column.tooltip
|
|
35
29
|
? String(value)
|
|
36
30
|
: undefined;
|
|
37
|
-
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.cellStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), column.align &&
|
|
31
|
+
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.cellStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), column.align && alignmentClasses[column.align], column.ellipsis && 'truncate', isUtilityColumn && 'whitespace-nowrap');
|
|
38
32
|
return (React__default.createElement(Cell, { className: cellClasses, "data-frozen": isFrozen ? 'true' : isLastFrozen ? 'last' : undefined, style: { width: column.width }, title: tooltipContent, role: "cell" }, children || content));
|
|
39
33
|
}
|
|
40
|
-
// Set display name for dev tools
|
|
41
34
|
TableCellComponent.displayName = 'TableCell';
|
|
42
|
-
// Memoize component to prevent unnecessary re-renders when props haven't changed
|
|
43
35
|
const TableCell = React__default.memo(TableCellComponent);
|
|
44
36
|
|
|
45
37
|
export { TableCell };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React__default from 'react';
|
|
2
|
+
import { Popover } from '../Popover/Popover.js';
|
|
3
|
+
import '../Popover/PopoverContext.js';
|
|
4
|
+
import { Cog6ToothIcon } from '@heroicons/react/24/outline';
|
|
5
|
+
import { Button } from '../Button/Button.js';
|
|
6
|
+
import { Checkbox } from '../../forms/Checkbox/Checkbox.js';
|
|
7
|
+
import { Sortable, SortableItem } from '../Sortable/Sortable.js';
|
|
8
|
+
|
|
9
|
+
function TableColumnManagerComponent({ columns, visibleColumns, columnOrder, onToggleColumn, onResetToDefault, onColumnReorder, }) {
|
|
10
|
+
const orderedColumns = columnOrder.length > 0
|
|
11
|
+
? columnOrder.map(colId => columns.find(col => col.id === colId)).filter(Boolean)
|
|
12
|
+
: columns;
|
|
13
|
+
const renderColumnItem = (column) => {
|
|
14
|
+
const isVisible = visibleColumns.includes(column.id);
|
|
15
|
+
const isLocked = column.locked === true;
|
|
16
|
+
const displayName = typeof column.header === 'string' ? column.header : column.id;
|
|
17
|
+
return (React__default.createElement(Checkbox, { id: `column-checkbox-${column.id}`, name: `column-${column.id}`, value: column.id, checked: isVisible, onChange: () => onToggleColumn(column.id), "aria-label": `Toggle visibility for ${displayName} column`, label: displayName, state: isLocked ? 'disabled' : 'default' }));
|
|
18
|
+
};
|
|
19
|
+
return (React__default.createElement(Popover, { placement: "bottom-end", offset: 8 },
|
|
20
|
+
React__default.createElement(Popover.Trigger, null,
|
|
21
|
+
React__default.createElement(Button, { color: "neutral", variant: "filled", "aria-label": "Manage column visibility" },
|
|
22
|
+
React__default.createElement(Cog6ToothIcon, { className: "size-5", "aria-hidden": "true" }),
|
|
23
|
+
"Manage Columns")),
|
|
24
|
+
React__default.createElement(Popover.Content, { className: "p-0" },
|
|
25
|
+
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" },
|
|
26
|
+
React__default.createElement("div", { id: "column-manager-title", className: "text-xs uppercase font-bold mb-3 text-[var(--color-text-placeholder)]" }, "Manage Columns"),
|
|
27
|
+
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."),
|
|
28
|
+
React__default.createElement("div", { className: "space-y-0.5", role: "group", "aria-label": "Column visibility options" }, onColumnReorder ? (React__default.createElement(Sortable, { onReorder: onColumnReorder, showDragHandle: true, className: "space-y-0.5" }, orderedColumns.map((column) => (React__default.createElement(SortableItem, { key: column.id, id: column.id, disabled: column.locked === true, className: `bg-white hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}` }, renderColumnItem(column)))))) : (orderedColumns.map((column) => (React__default.createElement("div", { key: column.id, className: `bg-white hover:bg-[var(--color-background-tertiary)] rounded-lg p-1.5 transition-colors ${column.locked ? 'bg-[var(--color-background-secondary)]' : ''}` }, renderColumnItem(column)))))),
|
|
29
|
+
React__default.createElement("div", { className: "mt-3 flex justify-end" },
|
|
30
|
+
React__default.createElement(Button, { color: "neutral", variant: "filled", className: "w-full", onClick: onResetToDefault }, "Reset to Default"))))));
|
|
31
|
+
}
|
|
32
|
+
const TableColumnManager = TableColumnManagerComponent;
|
|
33
|
+
|
|
34
|
+
export { TableColumnManager };
|
package/dist/components/core/Table/{components/DeclarativeComponents.d.ts → TableDeclarative.d.ts}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { TableHeaderProps, TableBodyProps, TableRowProps, TableCellProps, TableHeaderCellProps } from '
|
|
2
|
+
import { TableHeaderProps, TableBodyProps, TableRowProps, TableCellProps, TableHeaderCellProps } from './Table.types';
|
|
3
3
|
export declare const Header: React.NamedExoticComponent<TableHeaderProps>;
|
|
4
4
|
export declare const Body: React.NamedExoticComponent<TableBodyProps>;
|
|
5
5
|
export declare const Row: React.NamedExoticComponent<TableRowProps>;
|
package/dist/components/core/Table/{components/DeclarativeComponents.js → TableDeclarative.js}
RENAMED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
import React__default, { useContext } from 'react';
|
|
2
|
-
import { TableContext } from '
|
|
3
|
-
import { cn } from '
|
|
2
|
+
import { TableContext } from './Table.js';
|
|
3
|
+
import { cn } from '../../../utils/cn.js';
|
|
4
|
+
import { alignmentClasses } from './Table.utils.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Declarative Table Header component
|
|
7
|
-
* Used within the declarative API for flexible table composition
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* <Table>
|
|
11
|
-
* <Table.Header freezeHeader>
|
|
12
|
-
* <Table.Row>
|
|
13
|
-
* <Table.HeaderCell>Name</Table.HeaderCell>
|
|
14
|
-
* </Table.Row>
|
|
15
|
-
* </Table.Header>
|
|
16
|
-
* </Table>
|
|
17
8
|
*/
|
|
18
9
|
const HeaderComponent = ({ children, freezeHeader, className = '' }) => {
|
|
19
10
|
const contextValue = useContext(TableContext);
|
|
@@ -23,37 +14,19 @@ const HeaderComponent = ({ children, freezeHeader, className = '' }) => {
|
|
|
23
14
|
: (contextValue.freezeHeader ? theme === null || theme === void 0 ? void 0 : theme.frozenHeaderStyle : ''), className);
|
|
24
15
|
return (React__default.createElement("thead", { className: headerClasses, "data-freeze": freezeHeader ? 'true' : undefined }, children));
|
|
25
16
|
};
|
|
26
|
-
// Set display name for dev tools
|
|
27
17
|
HeaderComponent.displayName = 'Table.Header';
|
|
28
|
-
// Memoize component to prevent unnecessary re-renders
|
|
29
18
|
const Header = React__default.memo(HeaderComponent);
|
|
30
19
|
/**
|
|
31
20
|
* Declarative Table Body component
|
|
32
|
-
* Container for table rows in the declarative API
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* <Table.Body>
|
|
36
|
-
* <Table.Row>
|
|
37
|
-
* <Table.Cell>Data</Table.Cell>
|
|
38
|
-
* </Table.Row>
|
|
39
|
-
* </Table.Body>
|
|
40
21
|
*/
|
|
41
22
|
const BodyComponent = ({ children, className = '', }) => {
|
|
42
23
|
const { theme } = useContext(TableContext);
|
|
43
24
|
return (React__default.createElement("tbody", { className: cn(theme === null || theme === void 0 ? void 0 : theme.bodyStyle, className) }, children));
|
|
44
25
|
};
|
|
45
|
-
// Set display name for dev tools
|
|
46
26
|
BodyComponent.displayName = 'Table.Body';
|
|
47
|
-
// Memoize component to prevent unnecessary re-renders
|
|
48
27
|
const Body = React__default.memo(BodyComponent);
|
|
49
28
|
/**
|
|
50
29
|
* Declarative Table Row component
|
|
51
|
-
* Supports selection, expansion, and custom styling
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* <Table.Row isSelected onSelectToggle={() => setSelected(!selected)}>
|
|
55
|
-
* <Table.Cell>Data</Table.Cell>
|
|
56
|
-
* </Table.Row>
|
|
57
30
|
*/
|
|
58
31
|
const RowComponent = ({ children, isExpandable = false, isExpanded = false, onExpandToggle, isSelected = false, onSelectToggle, className = '', }) => {
|
|
59
32
|
const { theme } = useContext(TableContext);
|
|
@@ -65,53 +38,30 @@ const RowComponent = ({ children, isExpandable = false, isExpanded = false, onEx
|
|
|
65
38
|
};
|
|
66
39
|
return (React__default.createElement("tr", { className: rowClasses, "data-selected": isSelected ? 'true' : undefined, "data-expanded": isExpandable && isExpanded ? 'true' : undefined, onClick: onSelectToggle ? handleRowClick : undefined, role: "row", "aria-selected": isSelected, "aria-expanded": isExpandable ? isExpanded : undefined }, children));
|
|
67
40
|
};
|
|
68
|
-
// Set display name for dev tools
|
|
69
41
|
RowComponent.displayName = 'Table.Row';
|
|
70
|
-
// Memoize component to prevent unnecessary re-renders
|
|
71
42
|
const Row = React__default.memo(RowComponent);
|
|
72
43
|
/**
|
|
73
44
|
* Declarative Table Cell component
|
|
74
|
-
* Standard data cell with alignment, width, and frozen column support
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* <Table.Cell align="right" width="200px" isFrozen>
|
|
78
|
-
* $1,234.56
|
|
79
|
-
* </Table.Cell>
|
|
80
45
|
*/
|
|
81
46
|
const CellComponent = ({ children, isFrozen = false, isLastFrozen = false, align, width, className = '', colSpan, }) => {
|
|
82
47
|
const { theme } = useContext(TableContext);
|
|
83
|
-
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.cellStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), align &&
|
|
48
|
+
const cellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.cellStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), align && alignmentClasses[align], className);
|
|
84
49
|
return (React__default.createElement("td", { className: cellClasses, "data-frozen": isFrozen ? 'true' : isLastFrozen ? 'last' : undefined, style: { width }, colSpan: colSpan, role: "cell" }, children));
|
|
85
50
|
};
|
|
86
|
-
// Set display name for dev tools
|
|
87
51
|
CellComponent.displayName = 'Table.Cell';
|
|
88
|
-
// Memoize component to prevent unnecessary re-renders
|
|
89
52
|
const Cell = React__default.memo(CellComponent);
|
|
90
53
|
/**
|
|
91
54
|
* Declarative Table Header Cell component
|
|
92
|
-
* Header cell with sorting functionality and alignment options
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* <Table.HeaderCell
|
|
96
|
-
* isSortable
|
|
97
|
-
* sortDirection="asc"
|
|
98
|
-
* onSort={() => handleSort('name')}
|
|
99
|
-
* align="left"
|
|
100
|
-
* >
|
|
101
|
-
* Name
|
|
102
|
-
* </Table.HeaderCell>
|
|
103
55
|
*/
|
|
104
56
|
const HeaderCellComponent = ({ children, isFrozen = false, isLastFrozen = false, isSortable = false, sortDirection, onSort, align = 'left', width, className = '', }) => {
|
|
105
57
|
const { theme } = useContext(TableContext);
|
|
106
|
-
const headerCellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.headerStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), align &&
|
|
58
|
+
const headerCellClasses = cn(theme === null || theme === void 0 ? void 0 : theme.headerStyle, isFrozen && (theme === null || theme === void 0 ? void 0 : theme.frozenColumnStyle), isLastFrozen && (theme === null || theme === void 0 ? void 0 : theme.lastFrozenColumnStyle), align && alignmentClasses[align], isSortable && 'cursor-pointer', className);
|
|
107
59
|
return (React__default.createElement("th", { className: headerCellClasses, "data-frozen": isFrozen ? 'true' : isLastFrozen ? 'last' : undefined, onClick: isSortable && onSort ? onSort : undefined, style: { width }, role: "columnheader", "aria-sort": sortDirection ? (sortDirection === 'asc' ? 'ascending' : 'descending') : undefined },
|
|
108
60
|
React__default.createElement("div", { className: "flex items-center" },
|
|
109
61
|
children,
|
|
110
|
-
isSortable && sortDirection && (React__default.createElement("span", { className: "ml-1" }, sortDirection === 'asc' ? '
|
|
62
|
+
isSortable && sortDirection && (React__default.createElement("span", { className: "ml-1" }, sortDirection === 'asc' ? '\u2191' : '\u2193')))));
|
|
111
63
|
};
|
|
112
|
-
// Set display name for dev tools
|
|
113
64
|
HeaderCellComponent.displayName = 'Table.HeaderCell';
|
|
114
|
-
// Memoize component to prevent unnecessary re-renders
|
|
115
65
|
const HeaderCell = React__default.memo(HeaderCellComponent);
|
|
116
66
|
|
|
117
67
|
export { Body, Cell, Header, HeaderCell, Row };
|