@urbicon-ui/table 6.1.4
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 +153 -0
- package/dist/cells/ActionButtons.svelte +224 -0
- package/dist/cells/ActionButtons.svelte.d.ts +74 -0
- package/dist/cells/CopyButton.svelte +89 -0
- package/dist/cells/CopyButton.svelte.d.ts +33 -0
- package/dist/cells/CustomCell.svelte +136 -0
- package/dist/cells/CustomCell.svelte.d.ts +44 -0
- package/dist/cells/DateCell.svelte +194 -0
- package/dist/cells/DateCell.svelte.d.ts +39 -0
- package/dist/cells/LinkCell.svelte +240 -0
- package/dist/cells/LinkCell.svelte.d.ts +42 -0
- package/dist/cells/NumberCell.svelte +225 -0
- package/dist/cells/NumberCell.svelte.d.ts +47 -0
- package/dist/cells/StatusBadge.svelte +121 -0
- package/dist/cells/StatusBadge.svelte.d.ts +44 -0
- package/dist/cells/UserAvatar.svelte +71 -0
- package/dist/cells/UserAvatar.svelte.d.ts +37 -0
- package/dist/cells/index.d.ts +8 -0
- package/dist/cells/index.js +9 -0
- package/dist/core/EmptyState.svelte +161 -0
- package/dist/core/EmptyState.svelte.d.ts +16 -0
- package/dist/core/ErrorState.svelte +158 -0
- package/dist/core/ErrorState.svelte.d.ts +15 -0
- package/dist/core/GroupedRow.svelte +239 -0
- package/dist/core/GroupedRow.svelte.d.ts +18 -0
- package/dist/core/LoadingState.svelte +75 -0
- package/dist/core/LoadingState.svelte.d.ts +14 -0
- package/dist/core/MobileCard.svelte +151 -0
- package/dist/core/MobileCard.svelte.d.ts +15 -0
- package/dist/core/TableCell.svelte +105 -0
- package/dist/core/TableCell.svelte.d.ts +14 -0
- package/dist/core/TableDesktop.svelte +480 -0
- package/dist/core/TableDesktop.svelte.d.ts +26 -0
- package/dist/core/TableHead.svelte +314 -0
- package/dist/core/TableHead.svelte.d.ts +7 -0
- package/dist/core/TableMobile.svelte +112 -0
- package/dist/core/TableMobile.svelte.d.ts +13 -0
- package/dist/core/TableProvider.svelte +271 -0
- package/dist/core/TableProvider.svelte.d.ts +40 -0
- package/dist/core/TableRow.svelte +171 -0
- package/dist/core/TableRow.svelte.d.ts +16 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.js +14 -0
- package/dist/core/sticky-context.svelte.d.ts +48 -0
- package/dist/core/sticky-context.svelte.js +88 -0
- package/dist/core/table/Table.svelte +304 -0
- package/dist/core/table/Table.svelte.d.ts +26 -0
- package/dist/core/table/index.d.ts +448 -0
- package/dist/core/table/index.js +1 -0
- package/dist/core/table-style-context.d.ts +66 -0
- package/dist/core/table-style-context.js +26 -0
- package/dist/factories/ColumnValidation.d.ts +49 -0
- package/dist/factories/ColumnValidation.js +188 -0
- package/dist/factories/TableColumns.d.ts +97 -0
- package/dist/factories/TableColumns.js +262 -0
- package/dist/factories/TypedColumnBuilder.d.ts +41 -0
- package/dist/factories/TypedColumnBuilder.js +72 -0
- package/dist/factories/index.d.ts +12 -0
- package/dist/factories/index.js +13 -0
- package/dist/features/HeaderMenu.svelte +236 -0
- package/dist/features/HeaderMenu.svelte.d.ts +8 -0
- package/dist/features/LiveUpdateBanner.svelte +66 -0
- package/dist/features/LiveUpdateBanner.svelte.d.ts +6 -0
- package/dist/features/SearchHighlight.svelte +21 -0
- package/dist/features/SearchHighlight.svelte.d.ts +8 -0
- package/dist/features/SmartFilterBar/ChipsField.svelte +104 -0
- package/dist/features/SmartFilterBar/ChipsField.svelte.d.ts +5 -0
- package/dist/features/SmartFilterBar/ColumnVisibilityMenu.svelte +84 -0
- package/dist/features/SmartFilterBar/ColumnVisibilityMenu.svelte.d.ts +3 -0
- package/dist/features/SmartFilterBar/FilterMenu.svelte +367 -0
- package/dist/features/SmartFilterBar/FilterMenu.svelte.d.ts +3 -0
- package/dist/features/SmartFilterBar/GroupingMenu.svelte +82 -0
- package/dist/features/SmartFilterBar/GroupingMenu.svelte.d.ts +3 -0
- package/dist/features/SmartFilterBar/SmartFilterBar.svelte +109 -0
- package/dist/features/SmartFilterBar/SmartFilterBar.svelte.d.ts +11 -0
- package/dist/features/SmartFilterBar/SummaryMenu.svelte +118 -0
- package/dist/features/SmartFilterBar/SummaryMenu.svelte.d.ts +3 -0
- package/dist/features/SummaryRow.svelte +97 -0
- package/dist/features/SummaryRow.svelte.d.ts +8 -0
- package/dist/features/index.d.ts +4 -0
- package/dist/features/index.js +4 -0
- package/dist/i18n/index.d.ts +366 -0
- package/dist/i18n/index.js +21 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +41 -0
- package/dist/stores/TableStore.svelte.d.ts +192 -0
- package/dist/stores/TableStore.svelte.js +362 -0
- package/dist/stores/concerns/index.d.ts +15 -0
- package/dist/stores/concerns/index.js +14 -0
- package/dist/stores/concerns/types.d.ts +31 -0
- package/dist/stores/concerns/types.js +1 -0
- package/dist/stores/concerns/useColumnOrder.svelte.d.ts +16 -0
- package/dist/stores/concerns/useColumnOrder.svelte.js +81 -0
- package/dist/stores/concerns/useColumnVisibility.svelte.d.ts +16 -0
- package/dist/stores/concerns/useColumnVisibility.svelte.js +58 -0
- package/dist/stores/concerns/useExpansion.svelte.d.ts +9 -0
- package/dist/stores/concerns/useExpansion.svelte.js +32 -0
- package/dist/stores/concerns/useFiltering.svelte.d.ts +20 -0
- package/dist/stores/concerns/useFiltering.svelte.js +109 -0
- package/dist/stores/concerns/useFocusManagement.svelte.d.ts +15 -0
- package/dist/stores/concerns/useFocusManagement.svelte.js +52 -0
- package/dist/stores/concerns/useGrouping.svelte.d.ts +15 -0
- package/dist/stores/concerns/useGrouping.svelte.js +86 -0
- package/dist/stores/concerns/useLiveUpdates.svelte.d.ts +45 -0
- package/dist/stores/concerns/useLiveUpdates.svelte.js +175 -0
- package/dist/stores/concerns/usePagination.svelte.d.ts +18 -0
- package/dist/stores/concerns/usePagination.svelte.js +54 -0
- package/dist/stores/concerns/usePersistence.svelte.d.ts +36 -0
- package/dist/stores/concerns/usePersistence.svelte.js +167 -0
- package/dist/stores/concerns/useRemoteData.svelte.d.ts +21 -0
- package/dist/stores/concerns/useRemoteData.svelte.js +64 -0
- package/dist/stores/concerns/useSearch.svelte.d.ts +8 -0
- package/dist/stores/concerns/useSearch.svelte.js +16 -0
- package/dist/stores/concerns/useSelection.svelte.d.ts +21 -0
- package/dist/stores/concerns/useSelection.svelte.js +110 -0
- package/dist/stores/concerns/useSorting.svelte.d.ts +11 -0
- package/dist/stores/concerns/useSorting.svelte.js +70 -0
- package/dist/stores/concerns/useSummary.svelte.d.ts +18 -0
- package/dist/stores/concerns/useSummary.svelte.js +96 -0
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.js +1 -0
- package/dist/style/index.css +137 -0
- package/dist/style/index.d.ts +2 -0
- package/dist/style/index.js +2 -0
- package/dist/style/table-theme.css +131 -0
- package/dist/style/themes/comfortable.css +20 -0
- package/dist/style/themes/compact.css +20 -0
- package/dist/translations/de.d.ts +177 -0
- package/dist/translations/de.js +176 -0
- package/dist/translations/en.d.ts +177 -0
- package/dist/translations/en.js +176 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/tableTypes.d.ts +262 -0
- package/dist/types/tableTypes.js +1 -0
- package/dist/utils/index.d.ts +165 -0
- package/dist/utils/index.js +330 -0
- package/dist/utils/sticky-measure.d.ts +54 -0
- package/dist/utils/sticky-measure.js +107 -0
- package/dist/utils/virtualizer.d.ts +43 -0
- package/dist/utils/virtualizer.js +43 -0
- package/dist/variants/index.d.ts +11 -0
- package/dist/variants/index.js +15 -0
- package/dist/variants/table-cells.variants.d.ts +827 -0
- package/dist/variants/table-cells.variants.js +627 -0
- package/dist/variants/table-features.variants.d.ts +547 -0
- package/dist/variants/table-features.variants.js +412 -0
- package/dist/variants/table-states.variants.d.ts +594 -0
- package/dist/variants/table-states.variants.js +394 -0
- package/dist/variants/table.system.d.ts +301 -0
- package/dist/variants/table.system.js +314 -0
- package/dist/variants/table.variants.d.ts +428 -0
- package/dist/variants/table.variants.js +360 -0
- package/package.json +93 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { resolveColumnId } from '../utils';
|
|
2
|
+
/**
|
|
3
|
+
* Validation utilities for column configurations.
|
|
4
|
+
*
|
|
5
|
+
* In the 2.x column shape, identification is the column's `id` (with a
|
|
6
|
+
* string-accessor fallback). Validation enforces that every column resolves
|
|
7
|
+
* to a non-empty id, that ids are unique within a set, and that no column
|
|
8
|
+
* fails the basic structural checks.
|
|
9
|
+
*/
|
|
10
|
+
// biome-ignore lint/complexity/noStaticOnlyClass: intentional namespace grouping of column-validation utilities.
|
|
11
|
+
export class ColumnValidation {
|
|
12
|
+
/**
|
|
13
|
+
* Validates a single column configuration
|
|
14
|
+
*/
|
|
15
|
+
static validateColumn(column) {
|
|
16
|
+
const errors = [];
|
|
17
|
+
// Identifier validation — `id` is the canonical identifier; for
|
|
18
|
+
// string-accessor columns it may be omitted (falls back to the accessor).
|
|
19
|
+
const id = resolveColumnId(column);
|
|
20
|
+
if (!id || typeof id !== 'string') {
|
|
21
|
+
errors.push('Column requires a non-empty `id` (or a string `accessor` to default the id from)');
|
|
22
|
+
}
|
|
23
|
+
// Accessor validation — synthetic columns omit it, but when present it
|
|
24
|
+
// must be either a string or a function.
|
|
25
|
+
if (column.accessor !== undefined) {
|
|
26
|
+
const accessorType = typeof column.accessor;
|
|
27
|
+
if (accessorType !== 'string' && accessorType !== 'function') {
|
|
28
|
+
errors.push('Column `accessor` must be a string property name or a function');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Title validation — empty string is the documented idiom for icon-only
|
|
32
|
+
// columns (e.g. `{ id: 'actions', title: '', component: ActionButtons }`),
|
|
33
|
+
// so only the type is enforced, not non-emptiness.
|
|
34
|
+
if (typeof column.title !== 'string') {
|
|
35
|
+
errors.push("Column `title` must be a string (use '' for icon-only columns)");
|
|
36
|
+
}
|
|
37
|
+
// Width validation
|
|
38
|
+
if (column.width && typeof column.width !== 'string') {
|
|
39
|
+
errors.push('Column width must be a string');
|
|
40
|
+
}
|
|
41
|
+
// MinWidth validation
|
|
42
|
+
if (column.minWidth && typeof column.minWidth !== 'string') {
|
|
43
|
+
errors.push('Column minWidth must be a string');
|
|
44
|
+
}
|
|
45
|
+
// Priority validation
|
|
46
|
+
if (column.priority && ![1, 2, 3].includes(column.priority)) {
|
|
47
|
+
errors.push('Column priority must be 1, 2, or 3');
|
|
48
|
+
}
|
|
49
|
+
// Align validation
|
|
50
|
+
if (column.align && !['left', 'center', 'right'].includes(column.align)) {
|
|
51
|
+
errors.push('Column align must be left, center, or right');
|
|
52
|
+
}
|
|
53
|
+
// DataType validation (only meaningful on data columns)
|
|
54
|
+
const validDataTypes = ['text', 'number', 'date', 'boolean', 'email', 'url'];
|
|
55
|
+
if ('dataType' in column && column.dataType && !validDataTypes.includes(column.dataType)) {
|
|
56
|
+
errors.push(`Column dataType must be one of: ${validDataTypes.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
isValid: errors.length === 0,
|
|
60
|
+
errors
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validates an array of columns
|
|
65
|
+
*/
|
|
66
|
+
static validateColumns(columns) {
|
|
67
|
+
const errors = [];
|
|
68
|
+
const ids = new Set();
|
|
69
|
+
// Check for empty array
|
|
70
|
+
if (!Array.isArray(columns) || columns.length === 0) {
|
|
71
|
+
errors.push('Columns array is required and must not be empty');
|
|
72
|
+
return { isValid: false, errors };
|
|
73
|
+
}
|
|
74
|
+
// Validate each column and check for duplicate ids
|
|
75
|
+
columns.forEach((column, index) => {
|
|
76
|
+
const validation = ColumnValidation.validateColumn(column);
|
|
77
|
+
if (!validation.isValid) {
|
|
78
|
+
errors.push(`Column ${index}: ${validation.errors.join(', ')}`);
|
|
79
|
+
}
|
|
80
|
+
const id = resolveColumnId(column);
|
|
81
|
+
if (id && ids.has(id)) {
|
|
82
|
+
errors.push(`Duplicate column id found: ${id}`);
|
|
83
|
+
}
|
|
84
|
+
else if (id) {
|
|
85
|
+
ids.add(id);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// Check for at least one visible column (priority 1 or 2)
|
|
89
|
+
const hasVisibleColumns = columns.some((col) => !col.priority || col.priority <= 2);
|
|
90
|
+
if (!hasVisibleColumns) {
|
|
91
|
+
errors.push('At least one column should have priority 1 or 2 for mobile visibility');
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
isValid: errors.length === 0,
|
|
95
|
+
errors
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Validates column configuration for specific use cases
|
|
100
|
+
*/
|
|
101
|
+
static validateForUseCase(columns, useCase) {
|
|
102
|
+
const warnings = [];
|
|
103
|
+
switch (useCase) {
|
|
104
|
+
case 'mobile': {
|
|
105
|
+
// Check for too many priority 1 columns
|
|
106
|
+
const priority1Count = columns.filter((col) => col.priority === 1).length;
|
|
107
|
+
if (priority1Count > 2) {
|
|
108
|
+
warnings.push(`Mobile: ${priority1Count} priority 1 columns may cause horizontal scrolling`);
|
|
109
|
+
}
|
|
110
|
+
// Check for very wide columns
|
|
111
|
+
const wideColumns = columns.filter((col) => col.width?.includes('px') && parseInt(col.width, 10) > 200);
|
|
112
|
+
if (wideColumns.length > 0) {
|
|
113
|
+
warnings.push('Mobile: Some columns have fixed widths > 200px which may cause layout issues');
|
|
114
|
+
}
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'desktop': {
|
|
118
|
+
// Check for flex columns without proper balance
|
|
119
|
+
const flexColumns = columns.filter((col) => col.flex === true);
|
|
120
|
+
const fixedColumns = columns.filter((col) => col.width && !col.flex);
|
|
121
|
+
if (flexColumns.length === 0 && fixedColumns.length === columns.length) {
|
|
122
|
+
warnings.push('Desktop: Consider adding at least one flexible column for better space utilization');
|
|
123
|
+
}
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'print': {
|
|
127
|
+
// Check for interactive elements
|
|
128
|
+
const interactiveColumns = columns.filter((col) => resolveColumnId(col) === 'actions' || col.component);
|
|
129
|
+
if (interactiveColumns.length > 0) {
|
|
130
|
+
warnings.push('Print: Interactive columns may not display well in print media');
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
isValid: true,
|
|
137
|
+
warnings
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Helper functions for common validation patterns
|
|
143
|
+
*/
|
|
144
|
+
export const ValidationHelpers = {
|
|
145
|
+
/**
|
|
146
|
+
* Checks if columns are suitable for mobile display
|
|
147
|
+
*/
|
|
148
|
+
isMobileFriendly: (columns) => {
|
|
149
|
+
const priority1Count = columns.filter((col) => col.priority === 1).length;
|
|
150
|
+
return priority1Count <= 2;
|
|
151
|
+
},
|
|
152
|
+
/**
|
|
153
|
+
* Gets recommended mobile columns (priority 1 and 2)
|
|
154
|
+
*/
|
|
155
|
+
getMobileColumns: (columns) => {
|
|
156
|
+
return columns.filter((col) => !col.priority || col.priority <= 2);
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* Suggests improvements for column configuration
|
|
160
|
+
*/
|
|
161
|
+
suggestImprovements: (columns) => {
|
|
162
|
+
const suggestions = [];
|
|
163
|
+
// Check for missing priorities
|
|
164
|
+
const noPriorityCount = columns.filter((col) => !col.priority).length;
|
|
165
|
+
if (noPriorityCount > 0) {
|
|
166
|
+
suggestions.push(`Consider adding priority to ${noPriorityCount} columns for better responsive behavior`);
|
|
167
|
+
}
|
|
168
|
+
// Check for actions column placement
|
|
169
|
+
const actionsColumn = columns.find((col) => resolveColumnId(col) === 'actions');
|
|
170
|
+
const actionsIndex = actionsColumn ? columns.indexOf(actionsColumn) : -1;
|
|
171
|
+
if (actionsColumn && actionsIndex !== columns.length - 1) {
|
|
172
|
+
suggestions.push('Actions column is typically placed as the last column');
|
|
173
|
+
}
|
|
174
|
+
// Check for sortable/searchable balance — synthetic columns are
|
|
175
|
+
// structurally excluded from both via the Column shape, so we only
|
|
176
|
+
// count data columns here.
|
|
177
|
+
const dataColumns = columns.filter((col) => col.accessor !== undefined);
|
|
178
|
+
const sortableCount = dataColumns.filter((col) => col.sortable !== false).length;
|
|
179
|
+
const searchableCount = dataColumns.filter((col) => col.searchable !== false).length;
|
|
180
|
+
if (sortableCount === 0) {
|
|
181
|
+
suggestions.push('Consider making at least one column sortable for better UX');
|
|
182
|
+
}
|
|
183
|
+
if (searchableCount === 0) {
|
|
184
|
+
suggestions.push('Consider making at least one column searchable for better UX');
|
|
185
|
+
}
|
|
186
|
+
return suggestions;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Column, DataAccessor } from '../types/tableTypes';
|
|
2
|
+
import { type ActionButtonsProps } from '../cells/ActionButtons.svelte';
|
|
3
|
+
import { type CopyButtonProps } from '../cells/CopyButton.svelte';
|
|
4
|
+
import { type CustomCellProps } from '../cells/CustomCell.svelte';
|
|
5
|
+
import { type DateCellProps } from '../cells/DateCell.svelte';
|
|
6
|
+
import { type LinkCellProps } from '../cells/LinkCell.svelte';
|
|
7
|
+
import { type NumberCellProps } from '../cells/NumberCell.svelte';
|
|
8
|
+
import { type StatusBadgeProps } from '../cells/StatusBadge.svelte';
|
|
9
|
+
import { type UserAvatarProps } from '../cells/UserAvatar.svelte';
|
|
10
|
+
/** Common column configuration properties shared across all factory methods. */
|
|
11
|
+
type BaseColumnProps = {
|
|
12
|
+
sortable?: boolean;
|
|
13
|
+
searchable?: boolean;
|
|
14
|
+
groupable?: boolean;
|
|
15
|
+
summable?: boolean;
|
|
16
|
+
dataType?: 'text' | 'number' | 'date' | 'boolean' | 'email' | 'url';
|
|
17
|
+
priority?: 1 | 2 | 3;
|
|
18
|
+
align?: 'left' | 'center' | 'right';
|
|
19
|
+
width?: string;
|
|
20
|
+
minWidth?: string;
|
|
21
|
+
flex?: boolean;
|
|
22
|
+
};
|
|
23
|
+
type UserAvatarFactoryOptions<Item> = BaseColumnProps & Partial<Omit<UserAvatarProps<Item>, 'item'>>;
|
|
24
|
+
type ActionButtonsFactoryOptions<Item> = BaseColumnProps & Omit<ActionButtonsProps<Item>, 'item'>;
|
|
25
|
+
type StatusBadgeFactoryOptions<Item> = BaseColumnProps & Partial<Omit<StatusBadgeProps<Item>, 'item'>>;
|
|
26
|
+
type CopyButtonFactoryOptions<Item> = BaseColumnProps & Partial<Omit<CopyButtonProps<Item>, 'item'>>;
|
|
27
|
+
type CustomCellFactoryOptions<Item> = BaseColumnProps & Partial<Omit<CustomCellProps<Item>, 'item'>>;
|
|
28
|
+
type DateCellFactoryOptions<Item> = BaseColumnProps & Partial<Omit<DateCellProps<Item>, 'item'>>;
|
|
29
|
+
type LinkCellFactoryOptions<Item> = BaseColumnProps & Partial<Omit<LinkCellProps<Item>, 'item'>>;
|
|
30
|
+
type NumberCellFactoryOptions<Item> = BaseColumnProps & Partial<Omit<NumberCellProps<Item>, 'item'>>;
|
|
31
|
+
/**
|
|
32
|
+
* Column factory functions for common cell types.
|
|
33
|
+
*
|
|
34
|
+
* Data-column factories (everything except {@link TableColumns.actions}) bind
|
|
35
|
+
* the cell to a primitive-valued property via a string accessor. The
|
|
36
|
+
* property name doubles as the column id — search, sort, group and summary
|
|
37
|
+
* all read through the accessor, so values stay consistent across views.
|
|
38
|
+
*
|
|
39
|
+
* The synthetic {@link TableColumns.actions} factory produces a column
|
|
40
|
+
* without an accessor — by definition it is not searchable, sortable, or
|
|
41
|
+
* groupable, and the type system reflects that.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const columns = [
|
|
46
|
+
* TableColumns.userAvatar<User>('name', 'Employee'),
|
|
47
|
+
* TableColumns.status<User>('status'),
|
|
48
|
+
* TableColumns.number<User>('salary', 'Salary', { summable: true }),
|
|
49
|
+
* TableColumns.date<User>('hireDate', 'Hired'),
|
|
50
|
+
* TableColumns.actions<User>('', { onView: (item) => goto(`/users/${item.id}`) }),
|
|
51
|
+
* ];
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare const TableColumns: {
|
|
55
|
+
/**
|
|
56
|
+
* Creates a UserAvatar column displaying an avatar alongside user name/email.
|
|
57
|
+
*/
|
|
58
|
+
userAvatar: <Item>(accessor: DataAccessor<Item>, title?: string, options?: UserAvatarFactoryOptions<Item>) => Column<Item>;
|
|
59
|
+
/**
|
|
60
|
+
* Creates an ActionButtons column (view/edit/delete). Synthetic — no data
|
|
61
|
+
* accessor, structurally excluded from search/sort/group.
|
|
62
|
+
*/
|
|
63
|
+
actions: <Item>(title?: string, options?: ActionButtonsFactoryOptions<Item>) => Column<Item>;
|
|
64
|
+
/**
|
|
65
|
+
* Creates a StatusBadge column displaying a colored badge. Centered, groupable.
|
|
66
|
+
*/
|
|
67
|
+
status: <Item>(accessor: DataAccessor<Item>, title?: string, options?: StatusBadgeFactoryOptions<Item>) => Column<Item>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a CopyButton column with a click-to-copy button. Centered, non-sortable.
|
|
70
|
+
*/
|
|
71
|
+
copy: <Item>(accessor: DataAccessor<Item>, title?: string, options?: CopyButtonFactoryOptions<Item>) => Column<Item>;
|
|
72
|
+
/**
|
|
73
|
+
* Creates a CustomCell column for generic text content with optional styling.
|
|
74
|
+
*/
|
|
75
|
+
custom: <Item>(accessor: DataAccessor<Item>, title: string, options?: CustomCellFactoryOptions<Item>) => Column<Item>;
|
|
76
|
+
/**
|
|
77
|
+
* Creates a DateCell column with locale-aware date formatting.
|
|
78
|
+
*/
|
|
79
|
+
date: <Item>(accessor: DataAccessor<Item>, title?: string, options?: DateCellFactoryOptions<Item>) => Column<Item>;
|
|
80
|
+
/**
|
|
81
|
+
* Creates a LinkCell column rendering an anchor tag.
|
|
82
|
+
*/
|
|
83
|
+
link: <Item>(accessor: DataAccessor<Item>, title?: string, options?: LinkCellFactoryOptions<Item>) => Column<Item>;
|
|
84
|
+
/**
|
|
85
|
+
* Creates a NumberCell column with locale-aware number formatting.
|
|
86
|
+
*/
|
|
87
|
+
number: <Item>(accessor: DataAccessor<Item>, title?: string, options?: NumberCellFactoryOptions<Item>) => Column<Item>;
|
|
88
|
+
/**
|
|
89
|
+
* Creates a plain text column with optional formatter. Auto-detects
|
|
90
|
+
* numeric-named accessors (e.g. `salary`, `amount`) and adjusts
|
|
91
|
+
* alignment/summability.
|
|
92
|
+
*/
|
|
93
|
+
text: <Item>(accessor: DataAccessor<Item>, title: string, options?: BaseColumnProps & {
|
|
94
|
+
formatter?: (value: unknown, item: Item) => string;
|
|
95
|
+
}) => Column<Item>;
|
|
96
|
+
};
|
|
97
|
+
export type { ActionButtonsFactoryOptions, BaseColumnProps, CopyButtonFactoryOptions, CustomCellFactoryOptions, DateCellFactoryOptions, LinkCellFactoryOptions, NumberCellFactoryOptions, StatusBadgeFactoryOptions, UserAvatarFactoryOptions };
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import ActionButtons, {} from '../cells/ActionButtons.svelte';
|
|
2
|
+
import CopyButton, {} from '../cells/CopyButton.svelte';
|
|
3
|
+
import CustomCell, {} from '../cells/CustomCell.svelte';
|
|
4
|
+
import DateCell, {} from '../cells/DateCell.svelte';
|
|
5
|
+
import LinkCell, {} from '../cells/LinkCell.svelte';
|
|
6
|
+
import NumberCell, {} from '../cells/NumberCell.svelte';
|
|
7
|
+
import StatusBadge, {} from '../cells/StatusBadge.svelte';
|
|
8
|
+
import UserAvatar, {} from '../cells/UserAvatar.svelte';
|
|
9
|
+
// ===================================================================
|
|
10
|
+
// Factory implementation
|
|
11
|
+
// ===================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Column factory functions for common cell types.
|
|
14
|
+
*
|
|
15
|
+
* Data-column factories (everything except {@link TableColumns.actions}) bind
|
|
16
|
+
* the cell to a primitive-valued property via a string accessor. The
|
|
17
|
+
* property name doubles as the column id — search, sort, group and summary
|
|
18
|
+
* all read through the accessor, so values stay consistent across views.
|
|
19
|
+
*
|
|
20
|
+
* The synthetic {@link TableColumns.actions} factory produces a column
|
|
21
|
+
* without an accessor — by definition it is not searchable, sortable, or
|
|
22
|
+
* groupable, and the type system reflects that.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const columns = [
|
|
27
|
+
* TableColumns.userAvatar<User>('name', 'Employee'),
|
|
28
|
+
* TableColumns.status<User>('status'),
|
|
29
|
+
* TableColumns.number<User>('salary', 'Salary', { summable: true }),
|
|
30
|
+
* TableColumns.date<User>('hireDate', 'Hired'),
|
|
31
|
+
* TableColumns.actions<User>('', { onView: (item) => goto(`/users/${item.id}`) }),
|
|
32
|
+
* ];
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export const TableColumns = {
|
|
36
|
+
/**
|
|
37
|
+
* Creates a UserAvatar column displaying an avatar alongside user name/email.
|
|
38
|
+
*/
|
|
39
|
+
userAvatar: (accessor, title = 'User', options = {}) => {
|
|
40
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
41
|
+
return {
|
|
42
|
+
accessor,
|
|
43
|
+
title,
|
|
44
|
+
component: UserAvatar,
|
|
45
|
+
componentProps: (item) => ({
|
|
46
|
+
item,
|
|
47
|
+
...componentProps
|
|
48
|
+
}),
|
|
49
|
+
sortable: sortable ?? true,
|
|
50
|
+
searchable: searchable ?? true,
|
|
51
|
+
groupable: groupable ?? true,
|
|
52
|
+
summable: summable ?? false,
|
|
53
|
+
dataType: dataType ?? 'text',
|
|
54
|
+
priority,
|
|
55
|
+
align,
|
|
56
|
+
width,
|
|
57
|
+
minWidth,
|
|
58
|
+
flex
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* Creates an ActionButtons column (view/edit/delete). Synthetic — no data
|
|
63
|
+
* accessor, structurally excluded from search/sort/group.
|
|
64
|
+
*/
|
|
65
|
+
actions: (title = 'Actions', options = {}) => {
|
|
66
|
+
const { priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
67
|
+
return {
|
|
68
|
+
id: 'actions',
|
|
69
|
+
title,
|
|
70
|
+
component: ActionButtons,
|
|
71
|
+
componentProps: (item) => ({
|
|
72
|
+
item,
|
|
73
|
+
...componentProps
|
|
74
|
+
}),
|
|
75
|
+
priority,
|
|
76
|
+
align: align ?? 'right',
|
|
77
|
+
width: width ?? '120px',
|
|
78
|
+
minWidth,
|
|
79
|
+
flex
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
/**
|
|
83
|
+
* Creates a StatusBadge column displaying a colored badge. Centered, groupable.
|
|
84
|
+
*/
|
|
85
|
+
status: (accessor, title = 'Status', options = {}) => {
|
|
86
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
87
|
+
return {
|
|
88
|
+
accessor,
|
|
89
|
+
title,
|
|
90
|
+
component: StatusBadge,
|
|
91
|
+
componentProps: (item) => ({
|
|
92
|
+
item,
|
|
93
|
+
statusKey: accessor,
|
|
94
|
+
...componentProps
|
|
95
|
+
}),
|
|
96
|
+
sortable: sortable ?? true,
|
|
97
|
+
searchable: searchable ?? true,
|
|
98
|
+
groupable: groupable ?? true,
|
|
99
|
+
summable: summable ?? false,
|
|
100
|
+
dataType: dataType ?? 'text',
|
|
101
|
+
priority,
|
|
102
|
+
align: align ?? 'center',
|
|
103
|
+
width: width ?? '100px',
|
|
104
|
+
minWidth,
|
|
105
|
+
flex
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* Creates a CopyButton column with a click-to-copy button. Centered, non-sortable.
|
|
110
|
+
*/
|
|
111
|
+
copy: (accessor, title = 'Copy', options = {}) => {
|
|
112
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
113
|
+
return {
|
|
114
|
+
accessor,
|
|
115
|
+
title,
|
|
116
|
+
component: CopyButton,
|
|
117
|
+
componentProps: (item) => ({
|
|
118
|
+
item,
|
|
119
|
+
valueKey: accessor,
|
|
120
|
+
...componentProps
|
|
121
|
+
}),
|
|
122
|
+
sortable: sortable ?? false,
|
|
123
|
+
searchable: searchable ?? false,
|
|
124
|
+
groupable: groupable ?? false,
|
|
125
|
+
summable: summable ?? false,
|
|
126
|
+
dataType: dataType ?? 'text',
|
|
127
|
+
priority,
|
|
128
|
+
align: align ?? 'center',
|
|
129
|
+
width: width ?? '100px',
|
|
130
|
+
minWidth,
|
|
131
|
+
flex
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Creates a CustomCell column for generic text content with optional styling.
|
|
136
|
+
*/
|
|
137
|
+
custom: (accessor, title, options = {}) => {
|
|
138
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
139
|
+
return {
|
|
140
|
+
accessor,
|
|
141
|
+
title,
|
|
142
|
+
component: CustomCell,
|
|
143
|
+
componentProps: (item) => ({
|
|
144
|
+
item,
|
|
145
|
+
...componentProps
|
|
146
|
+
}),
|
|
147
|
+
sortable: sortable ?? true,
|
|
148
|
+
searchable: searchable ?? true,
|
|
149
|
+
groupable: groupable ?? false,
|
|
150
|
+
summable: summable ?? false,
|
|
151
|
+
dataType: dataType ?? 'text',
|
|
152
|
+
priority,
|
|
153
|
+
align,
|
|
154
|
+
width,
|
|
155
|
+
minWidth,
|
|
156
|
+
flex
|
|
157
|
+
};
|
|
158
|
+
},
|
|
159
|
+
/**
|
|
160
|
+
* Creates a DateCell column with locale-aware date formatting.
|
|
161
|
+
*/
|
|
162
|
+
date: (accessor, title = 'Date', options = {}) => {
|
|
163
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
164
|
+
return {
|
|
165
|
+
accessor,
|
|
166
|
+
title,
|
|
167
|
+
component: DateCell,
|
|
168
|
+
componentProps: (item) => ({
|
|
169
|
+
item,
|
|
170
|
+
dateKey: accessor,
|
|
171
|
+
...componentProps
|
|
172
|
+
}),
|
|
173
|
+
sortable: sortable ?? true,
|
|
174
|
+
searchable: searchable ?? true,
|
|
175
|
+
groupable: groupable ?? true,
|
|
176
|
+
summable: summable ?? false,
|
|
177
|
+
dataType: dataType ?? 'date',
|
|
178
|
+
priority,
|
|
179
|
+
align,
|
|
180
|
+
width,
|
|
181
|
+
minWidth,
|
|
182
|
+
flex
|
|
183
|
+
};
|
|
184
|
+
},
|
|
185
|
+
/**
|
|
186
|
+
* Creates a LinkCell column rendering an anchor tag.
|
|
187
|
+
*/
|
|
188
|
+
link: (accessor, title = 'Link', options = {}) => {
|
|
189
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
190
|
+
return {
|
|
191
|
+
accessor,
|
|
192
|
+
title,
|
|
193
|
+
component: LinkCell,
|
|
194
|
+
componentProps: (item) => ({
|
|
195
|
+
item,
|
|
196
|
+
urlKey: accessor,
|
|
197
|
+
...componentProps
|
|
198
|
+
}),
|
|
199
|
+
sortable: sortable ?? true,
|
|
200
|
+
searchable: searchable ?? true,
|
|
201
|
+
groupable: groupable ?? false,
|
|
202
|
+
summable: summable ?? false,
|
|
203
|
+
dataType: dataType ?? 'url',
|
|
204
|
+
priority,
|
|
205
|
+
align,
|
|
206
|
+
width,
|
|
207
|
+
minWidth,
|
|
208
|
+
flex
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
/**
|
|
212
|
+
* Creates a NumberCell column with locale-aware number formatting.
|
|
213
|
+
*/
|
|
214
|
+
number: (accessor, title = 'Number', options = {}) => {
|
|
215
|
+
const { sortable, searchable, groupable, summable, dataType, priority, align, width, minWidth, flex, ...componentProps } = options;
|
|
216
|
+
return {
|
|
217
|
+
accessor,
|
|
218
|
+
title,
|
|
219
|
+
component: NumberCell,
|
|
220
|
+
componentProps: (item) => ({
|
|
221
|
+
item,
|
|
222
|
+
valueKey: accessor,
|
|
223
|
+
...componentProps
|
|
224
|
+
}),
|
|
225
|
+
sortable: sortable ?? true,
|
|
226
|
+
searchable: searchable ?? true,
|
|
227
|
+
groupable: groupable ?? true,
|
|
228
|
+
summable: summable ?? true,
|
|
229
|
+
dataType: dataType ?? 'number',
|
|
230
|
+
priority,
|
|
231
|
+
align: align ?? 'right',
|
|
232
|
+
width,
|
|
233
|
+
minWidth,
|
|
234
|
+
flex
|
|
235
|
+
};
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* Creates a plain text column with optional formatter. Auto-detects
|
|
239
|
+
* numeric-named accessors (e.g. `salary`, `amount`) and adjusts
|
|
240
|
+
* alignment/summability.
|
|
241
|
+
*/
|
|
242
|
+
text: (accessor, title, options = {}) => {
|
|
243
|
+
const { formatter, ...columnProps } = options;
|
|
244
|
+
const accessorStr = String(accessor);
|
|
245
|
+
const isNumericKey = /^(age|salary|price|amount|count|number|projectsCompleted|rating|score)$/i.test(accessorStr);
|
|
246
|
+
return {
|
|
247
|
+
accessor,
|
|
248
|
+
title,
|
|
249
|
+
formatter,
|
|
250
|
+
sortable: columnProps.sortable ?? true,
|
|
251
|
+
searchable: columnProps.searchable ?? true,
|
|
252
|
+
summable: columnProps.summable ?? (columnProps.dataType === 'number' || isNumericKey),
|
|
253
|
+
dataType: columnProps.dataType ?? (isNumericKey ? 'number' : 'text'),
|
|
254
|
+
groupable: columnProps.groupable ?? true,
|
|
255
|
+
priority: columnProps.priority,
|
|
256
|
+
align: columnProps.align ?? (isNumericKey ? 'right' : 'left'),
|
|
257
|
+
width: columnProps.width,
|
|
258
|
+
minWidth: columnProps.minWidth,
|
|
259
|
+
flex: columnProps.flex
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ActionButtonsFactoryOptions, BaseColumnProps, CopyButtonFactoryOptions, CustomCellFactoryOptions, DateCellFactoryOptions, LinkCellFactoryOptions, NumberCellFactoryOptions, StatusBadgeFactoryOptions, UserAvatarFactoryOptions } from '..';
|
|
2
|
+
import type { Column, DataAccessor } from '../types/tableTypes';
|
|
3
|
+
/**
|
|
4
|
+
* Typed column builder providing a fluent API for defining table columns.
|
|
5
|
+
* The generic parameter `Item` constrains accessor arguments to primitive
|
|
6
|
+
* properties of the data type, mirroring the runtime constraint that
|
|
7
|
+
* search/sort/group only meaningfully operate on stringifiable values.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* interface User { id: number; name: string; status: string; salary: number; }
|
|
12
|
+
*
|
|
13
|
+
* const columns = TypedColumnBuilder.for<User>()
|
|
14
|
+
* .userAvatar('name', 'Employee')
|
|
15
|
+
* .status('status')
|
|
16
|
+
* .number('salary', 'Salary')
|
|
17
|
+
* .actions()
|
|
18
|
+
* .build();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare class TypedColumnBuilder<Item> {
|
|
22
|
+
private columns;
|
|
23
|
+
userAvatar(accessor: DataAccessor<Item>, title?: string, options?: UserAvatarFactoryOptions<Item>): this;
|
|
24
|
+
actions(title?: string, options?: ActionButtonsFactoryOptions<Item>): this;
|
|
25
|
+
status(accessor: DataAccessor<Item>, title?: string, options?: StatusBadgeFactoryOptions<Item>): this;
|
|
26
|
+
copy(accessor: DataAccessor<Item>, title?: string, options?: CopyButtonFactoryOptions<Item>): this;
|
|
27
|
+
customCell(accessor: DataAccessor<Item>, title: string, options?: CustomCellFactoryOptions<Item>): this;
|
|
28
|
+
date(accessor: DataAccessor<Item>, title?: string, options?: DateCellFactoryOptions<Item>): this;
|
|
29
|
+
link(accessor: DataAccessor<Item>, title?: string, options?: LinkCellFactoryOptions<Item>): this;
|
|
30
|
+
number(accessor: DataAccessor<Item>, title?: string, options?: NumberCellFactoryOptions<Item>): this;
|
|
31
|
+
text(accessor: DataAccessor<Item>, title: string, options?: BaseColumnProps & {
|
|
32
|
+
formatter?: (value: unknown, item: Item) => string;
|
|
33
|
+
}): this;
|
|
34
|
+
custom(column: Column<Item>): this;
|
|
35
|
+
/**
|
|
36
|
+
* Returns the accumulated `Column<Item>[]` directly. Pair with the generic
|
|
37
|
+
* `Table<Item>` component to keep type-safety end-to-end without `as` casts.
|
|
38
|
+
*/
|
|
39
|
+
build(): Column<Item>[];
|
|
40
|
+
static for<T>(): TypedColumnBuilder<T>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { TableColumns } from '..';
|
|
2
|
+
/**
|
|
3
|
+
* Typed column builder providing a fluent API for defining table columns.
|
|
4
|
+
* The generic parameter `Item` constrains accessor arguments to primitive
|
|
5
|
+
* properties of the data type, mirroring the runtime constraint that
|
|
6
|
+
* search/sort/group only meaningfully operate on stringifiable values.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* interface User { id: number; name: string; status: string; salary: number; }
|
|
11
|
+
*
|
|
12
|
+
* const columns = TypedColumnBuilder.for<User>()
|
|
13
|
+
* .userAvatar('name', 'Employee')
|
|
14
|
+
* .status('status')
|
|
15
|
+
* .number('salary', 'Salary')
|
|
16
|
+
* .actions()
|
|
17
|
+
* .build();
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export class TypedColumnBuilder {
|
|
21
|
+
columns = [];
|
|
22
|
+
userAvatar(accessor, title = 'User', options = {}) {
|
|
23
|
+
this.columns.push(TableColumns.userAvatar(accessor, title, options));
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
actions(title = 'Actions', options = {}) {
|
|
27
|
+
this.columns.push(TableColumns.actions(title, options));
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
status(accessor, title = 'Status', options = {}) {
|
|
31
|
+
this.columns.push(TableColumns.status(accessor, title, options));
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
copy(accessor, title = 'Copy', options = {}) {
|
|
35
|
+
this.columns.push(TableColumns.copy(accessor, title, options));
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
customCell(accessor, title, options = {}) {
|
|
39
|
+
this.columns.push(TableColumns.custom(accessor, title, options));
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
date(accessor, title = 'Date', options = {}) {
|
|
43
|
+
this.columns.push(TableColumns.date(accessor, title, options));
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
link(accessor, title = 'Link', options = {}) {
|
|
47
|
+
this.columns.push(TableColumns.link(accessor, title, options));
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
number(accessor, title = 'Number', options = {}) {
|
|
51
|
+
this.columns.push(TableColumns.number(accessor, title, options));
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
text(accessor, title, options = {}) {
|
|
55
|
+
this.columns.push(TableColumns.text(accessor, title, options));
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
custom(column) {
|
|
59
|
+
this.columns.push(column);
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Returns the accumulated `Column<Item>[]` directly. Pair with the generic
|
|
64
|
+
* `Table<Item>` component to keep type-safety end-to-end without `as` casts.
|
|
65
|
+
*/
|
|
66
|
+
build() {
|
|
67
|
+
return [...this.columns];
|
|
68
|
+
}
|
|
69
|
+
static for() {
|
|
70
|
+
return new TypedColumnBuilder();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { default as ActionButtons } from '../cells/ActionButtons.svelte';
|
|
2
|
+
export { default as CopyButton } from '../cells/CopyButton.svelte';
|
|
3
|
+
export { default as CustomCell } from '../cells/CustomCell.svelte';
|
|
4
|
+
export { default as DateCell } from '../cells/DateCell.svelte';
|
|
5
|
+
export { default as LinkCell } from '../cells/LinkCell.svelte';
|
|
6
|
+
export { default as NumberCell } from '../cells/NumberCell.svelte';
|
|
7
|
+
export { default as StatusBadge } from '../cells/StatusBadge.svelte';
|
|
8
|
+
export { default as UserAvatar } from '../cells/UserAvatar.svelte';
|
|
9
|
+
export { ColumnValidation, ValidationHelpers } from './ColumnValidation';
|
|
10
|
+
export type { ActionButtonsFactoryOptions, BaseColumnProps, CopyButtonFactoryOptions, CustomCellFactoryOptions, DateCellFactoryOptions, LinkCellFactoryOptions, NumberCellFactoryOptions, StatusBadgeFactoryOptions, UserAvatarFactoryOptions } from './TableColumns';
|
|
11
|
+
export { TableColumns } from './TableColumns';
|
|
12
|
+
export { TypedColumnBuilder } from './TypedColumnBuilder';
|