sveltacular 1.0.26 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generic/pill/pill.svelte +7 -2
- package/dist/generic/pill/pill.svelte.d.ts +2 -0
- package/dist/tables/cell-renderers.d.ts +9 -1
- package/dist/tables/cell-renderers.js +123 -83
- package/dist/tables/data-grid-actions-cell.svelte +72 -0
- package/dist/tables/data-grid-actions-cell.svelte.d.ts +26 -0
- package/dist/tables/data-grid-cell.svelte +104 -0
- package/dist/tables/data-grid-cell.svelte.d.ts +18 -0
- package/dist/tables/data-grid-row.svelte +74 -0
- package/dist/tables/data-grid-row.svelte.d.ts +38 -0
- package/dist/tables/data-grid.svelte +37 -129
- package/dist/tables/data-grid.svelte.d.ts +7 -0
- package/dist/tables/example-status-cell.svelte +16 -0
- package/dist/tables/example-status-cell.svelte.d.ts +4 -0
- package/dist/tables/index.d.ts +2 -1
- package/dist/tables/index.js +1 -1
- package/dist/types/data.d.ts +17 -2
- package/package.json +1 -1
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
shape = 'rounded' as 'circular' | 'square' | 'rounded' | 'badge' | 'circle',
|
|
9
9
|
fill = 'solid' as 'solid' | 'outline',
|
|
10
10
|
compact = false,
|
|
11
|
-
label
|
|
11
|
+
label,
|
|
12
|
+
children
|
|
12
13
|
}: {
|
|
13
14
|
size?: FormFieldSizeOptions;
|
|
14
15
|
variant?: 'standard' | 'positive' | 'negative';
|
|
@@ -16,11 +17,15 @@
|
|
|
16
17
|
fill?: 'solid' | 'outline';
|
|
17
18
|
compact?: boolean;
|
|
18
19
|
label?: string;
|
|
20
|
+
children?: Snippet;
|
|
19
21
|
} = $props();
|
|
20
22
|
</script>
|
|
21
23
|
|
|
22
24
|
<div class="pill {size} {variant} {shape} {fill}" class:compact>
|
|
23
|
-
<span>
|
|
25
|
+
<span>
|
|
26
|
+
{label}
|
|
27
|
+
{@render children?.()}
|
|
28
|
+
</span>
|
|
24
29
|
</div>
|
|
25
30
|
|
|
26
31
|
<style>.pill {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import type { FormFieldSizeOptions } from '../../types/form.js';
|
|
2
3
|
type $$ComponentProps = {
|
|
3
4
|
size?: FormFieldSizeOptions;
|
|
@@ -6,6 +7,7 @@ type $$ComponentProps = {
|
|
|
6
7
|
fill?: 'solid' | 'outline';
|
|
7
8
|
compact?: boolean;
|
|
8
9
|
label?: string;
|
|
10
|
+
children?: Snippet;
|
|
9
11
|
};
|
|
10
12
|
declare const Pill: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
13
|
type Pill = ReturnType<typeof Pill>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { JsonObject, ColumnDef, TextColumn, NumberColumn, CurrencyColumn, DateColumn, DateTimeColumn, BooleanColumn, EmailColumn, CustomColumn } from '../types/data.js';
|
|
1
|
+
import type { JsonObject, ColumnDef, TextColumn, NumberColumn, CurrencyColumn, DateColumn, DateTimeColumn, BooleanColumn, EmailColumn, ArrayColumn, CustomColumn } from '../types/data.js';
|
|
2
2
|
export interface CellRenderContext<T extends JsonObject = JsonObject> {
|
|
3
3
|
row: T;
|
|
4
4
|
column: ColumnDef<T>;
|
|
@@ -15,6 +15,14 @@ export declare function formatDateCell<T extends JsonObject>(row: T, column: Dat
|
|
|
15
15
|
export declare function formatDateTimeCell<T extends JsonObject>(row: T, column: DateTimeColumn<T>): string;
|
|
16
16
|
export declare function formatBooleanCell<T extends JsonObject>(row: T, column: BooleanColumn<T>): string;
|
|
17
17
|
export declare function formatEmailCell<T extends JsonObject>(row: T, column: EmailColumn<T>): string;
|
|
18
|
+
export interface ArrayCellResult {
|
|
19
|
+
items: Array<{
|
|
20
|
+
text: string;
|
|
21
|
+
link: string | null;
|
|
22
|
+
}>;
|
|
23
|
+
separator: 'comma' | 'semicolon' | 'line' | 'pill';
|
|
24
|
+
}
|
|
25
|
+
export declare function formatArrayCell<T extends JsonObject>(row: T, column: ArrayColumn<T>): ArrayCellResult;
|
|
18
26
|
export declare function formatCustomCell<T extends JsonObject>(row: T, column: CustomColumn<T>): string;
|
|
19
27
|
export declare function formatCell<T extends JsonObject>(row: T, column: ColumnDef<T>): string;
|
|
20
28
|
export declare function getCellLink<T extends JsonObject>(row: T, column: ColumnDef<T>): string | null;
|
|
@@ -10,92 +10,101 @@ export function isNullish(value) {
|
|
|
10
10
|
export function isEmpty(value) {
|
|
11
11
|
return typeof value === 'string' && value.trim() === '';
|
|
12
12
|
}
|
|
13
|
+
function createFormatter(config) {
|
|
14
|
+
return (row, column) => {
|
|
15
|
+
const value = config.getValue(row, column);
|
|
16
|
+
// Check for null/undefined
|
|
17
|
+
if (isNullish(value) && 'nullText' in column && column.nullText) {
|
|
18
|
+
return column.nullText;
|
|
19
|
+
}
|
|
20
|
+
// Check for empty (if applicable)
|
|
21
|
+
if (config.checkEmpty && config.checkEmpty(value)) {
|
|
22
|
+
if ('emptyText' in column && column.emptyText) {
|
|
23
|
+
return column.emptyText;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Use custom format if provided
|
|
27
|
+
if (config.customFormat && 'format' in column && column.format) {
|
|
28
|
+
return column.format(value, row);
|
|
29
|
+
}
|
|
30
|
+
// Use default format
|
|
31
|
+
return config.defaultFormat(value);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
13
34
|
// Format text column
|
|
14
35
|
export function formatTextCell(row, column) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (column.format) {
|
|
23
|
-
return column.format(String(value), row);
|
|
24
|
-
}
|
|
25
|
-
return String(value ?? '');
|
|
36
|
+
const formatter = createFormatter({
|
|
37
|
+
getValue: (row, column) => getCellValue(row, column.key),
|
|
38
|
+
checkEmpty: isEmpty,
|
|
39
|
+
defaultFormat: (value) => String(value ?? ''),
|
|
40
|
+
customFormat: (value, row) => String(value)
|
|
41
|
+
});
|
|
42
|
+
return formatter(row, column);
|
|
26
43
|
}
|
|
27
44
|
// Format number column
|
|
28
45
|
export function formatNumberCell(row, column) {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
return numValue.toLocaleString();
|
|
46
|
+
const formatter = createFormatter({
|
|
47
|
+
getValue: (row, column) => {
|
|
48
|
+
const value = getCellValue(row, column.key);
|
|
49
|
+
return Number(value);
|
|
50
|
+
},
|
|
51
|
+
checkEmpty: (value) => isNaN(value),
|
|
52
|
+
defaultFormat: (value) => value.toLocaleString(),
|
|
53
|
+
customFormat: (value, row) => value.toString()
|
|
54
|
+
});
|
|
55
|
+
return formatter(row, column);
|
|
41
56
|
}
|
|
42
57
|
// Format currency column
|
|
43
58
|
export function formatCurrencyCell(row, column) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
currency: column.currency ?? 'USD'
|
|
58
|
-
}).format(numValue);
|
|
59
|
+
const formatter = createFormatter({
|
|
60
|
+
getValue: (row, column) => {
|
|
61
|
+
const value = getCellValue(row, column.key);
|
|
62
|
+
return Number(value);
|
|
63
|
+
},
|
|
64
|
+
checkEmpty: (value) => isNaN(value),
|
|
65
|
+
defaultFormat: (value) => new Intl.NumberFormat('en-US', {
|
|
66
|
+
style: 'currency',
|
|
67
|
+
currency: column.currency ?? 'USD'
|
|
68
|
+
}).format(value),
|
|
69
|
+
customFormat: (value, row) => value.toString()
|
|
70
|
+
});
|
|
71
|
+
return formatter(row, column);
|
|
59
72
|
}
|
|
60
73
|
// Format date column
|
|
61
74
|
export function formatDateCell(row, column) {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return String(value ?? '');
|
|
78
|
-
}
|
|
75
|
+
const formatter = createFormatter({
|
|
76
|
+
getValue: (row, column) => getCellValue(row, column.key),
|
|
77
|
+
checkEmpty: isEmpty,
|
|
78
|
+
defaultFormat: (value) => {
|
|
79
|
+
try {
|
|
80
|
+
const date = typeof value === 'string' ? new Date(value) : value;
|
|
81
|
+
return date.toISOString().substring(0, 10);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return String(value ?? '');
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
customFormat: (value, row) => String(value)
|
|
88
|
+
});
|
|
89
|
+
return formatter(row, column);
|
|
79
90
|
}
|
|
80
91
|
// Format datetime column
|
|
81
92
|
export function formatDateTimeCell(row, column) {
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return String(value ?? '');
|
|
98
|
-
}
|
|
93
|
+
const formatter = createFormatter({
|
|
94
|
+
getValue: (row, column) => getCellValue(row, column.key),
|
|
95
|
+
checkEmpty: isEmpty,
|
|
96
|
+
defaultFormat: (value) => {
|
|
97
|
+
try {
|
|
98
|
+
const date = typeof value === 'string' ? new Date(value) : value;
|
|
99
|
+
return date.toLocaleString();
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return String(value ?? '');
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
customFormat: (value, row) => String(value)
|
|
106
|
+
});
|
|
107
|
+
return formatter(row, column);
|
|
99
108
|
}
|
|
100
109
|
// Format boolean column
|
|
101
110
|
export function formatBooleanCell(row, column) {
|
|
@@ -114,23 +123,43 @@ export function formatBooleanCell(row, column) {
|
|
|
114
123
|
}
|
|
115
124
|
// Format email column
|
|
116
125
|
export function formatEmailCell(row, column) {
|
|
126
|
+
const formatter = createFormatter({
|
|
127
|
+
getValue: (row, column) => getCellValue(row, column.key),
|
|
128
|
+
checkEmpty: isEmpty,
|
|
129
|
+
defaultFormat: (value) => String(value ?? ''),
|
|
130
|
+
customFormat: (value, row) => String(value)
|
|
131
|
+
});
|
|
132
|
+
return formatter(row, column);
|
|
133
|
+
}
|
|
134
|
+
// Format array column
|
|
135
|
+
export function formatArrayCell(row, column) {
|
|
117
136
|
const value = getCellValue(row, column.key);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
const arr = Array.isArray(value) ? value : [];
|
|
138
|
+
const separator = column.separator ?? 'comma';
|
|
139
|
+
const items = arr.map((element, index) => {
|
|
140
|
+
let text;
|
|
141
|
+
if (column.format) {
|
|
142
|
+
text = column.format(element, row, index);
|
|
143
|
+
}
|
|
144
|
+
else if (column.displayKey && typeof element === 'object' && element !== null) {
|
|
145
|
+
text = String(element[column.displayKey] ?? '');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
text = String(element);
|
|
149
|
+
}
|
|
150
|
+
const link = column.link ? column.link(element, row, index) : null;
|
|
151
|
+
return { text, link };
|
|
152
|
+
});
|
|
153
|
+
return { items, separator };
|
|
128
154
|
}
|
|
129
155
|
// Format custom column
|
|
130
156
|
export function formatCustomCell(row, column) {
|
|
131
157
|
if (isNullish(row) && column.nullText) {
|
|
132
158
|
return column.nullText;
|
|
133
159
|
}
|
|
160
|
+
if (!column.render) {
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
134
163
|
const value = column.render(row);
|
|
135
164
|
return String(value ?? '');
|
|
136
165
|
}
|
|
@@ -152,14 +181,25 @@ export function formatCell(row, column) {
|
|
|
152
181
|
return formatBooleanCell(row, column);
|
|
153
182
|
case 'email':
|
|
154
183
|
return formatEmailCell(row, column);
|
|
184
|
+
case 'array':
|
|
185
|
+
// Array type returns structured data, not a string
|
|
186
|
+
// Use formatArrayCell directly instead
|
|
187
|
+
return '';
|
|
155
188
|
case 'custom':
|
|
156
189
|
return formatCustomCell(row, column);
|
|
157
190
|
}
|
|
158
191
|
}
|
|
159
192
|
// Get link for a cell if applicable
|
|
160
193
|
export function getCellLink(row, column) {
|
|
194
|
+
// Array columns handle their own links via formatArrayCell
|
|
195
|
+
if (column.type === 'array') {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
161
198
|
if ('link' in column && column.link) {
|
|
162
|
-
|
|
199
|
+
// Type guard to ensure we're not dealing with array column
|
|
200
|
+
if (typeof column.link === 'function') {
|
|
201
|
+
return column.link(row);
|
|
202
|
+
}
|
|
163
203
|
}
|
|
164
204
|
// Auto-link emails
|
|
165
205
|
if (column.type === 'email') {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { JsonObject } from '../types/data.js';
|
|
3
|
+
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
4
|
+
import TableCell from './table-cell.svelte';
|
|
5
|
+
import Button from '../forms/button/button.svelte';
|
|
6
|
+
import DropdownButton from '../navigation/dropdown-button/dropdown-button.svelte';
|
|
7
|
+
import DropdownItem from '../generic/dropdown-item/dropdown-item.svelte';
|
|
8
|
+
|
|
9
|
+
interface Action {
|
|
10
|
+
text: string;
|
|
11
|
+
variant?: ButtonVariant;
|
|
12
|
+
href?: (row: JsonObject) => string;
|
|
13
|
+
onClick?: (row: JsonObject) => unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface Actions {
|
|
17
|
+
text?: string;
|
|
18
|
+
type?: 'buttons' | 'dropdown';
|
|
19
|
+
variant?: ButtonVariant | 'default';
|
|
20
|
+
size?: FormFieldSizeOptions;
|
|
21
|
+
align?: 'left' | 'center' | 'right';
|
|
22
|
+
items: Action[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
actions,
|
|
27
|
+
row,
|
|
28
|
+
actionButtonVariant = 'outline',
|
|
29
|
+
actionButtonSize = 'sm',
|
|
30
|
+
actionAlign = 'center'
|
|
31
|
+
}: {
|
|
32
|
+
actions: Actions;
|
|
33
|
+
row: JsonObject;
|
|
34
|
+
actionButtonVariant?: ButtonVariant;
|
|
35
|
+
actionButtonSize?: FormFieldSizeOptions;
|
|
36
|
+
actionAlign?: 'left' | 'center' | 'right';
|
|
37
|
+
} = $props();
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<TableCell type="actions" align={actionAlign}>
|
|
41
|
+
{#if actions.type === 'dropdown'}
|
|
42
|
+
<DropdownButton text={actions.text ?? ''} variant="ghost">
|
|
43
|
+
{#each actions.items as action}
|
|
44
|
+
<DropdownItem
|
|
45
|
+
href={action.href ? action.href(row) : undefined}
|
|
46
|
+
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
47
|
+
>{action.text}</DropdownItem
|
|
48
|
+
>
|
|
49
|
+
{/each}
|
|
50
|
+
</DropdownButton>
|
|
51
|
+
{:else}
|
|
52
|
+
<div class="actions">
|
|
53
|
+
{#each actions.items as action}
|
|
54
|
+
{@const buttonVariant = action.variant ?? actionButtonVariant}
|
|
55
|
+
<Button
|
|
56
|
+
type="button"
|
|
57
|
+
variant={buttonVariant}
|
|
58
|
+
size={actionButtonSize}
|
|
59
|
+
href={action.href ? action.href(row) : undefined}
|
|
60
|
+
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
61
|
+
>
|
|
62
|
+
{action.text}
|
|
63
|
+
</Button>
|
|
64
|
+
{/each}
|
|
65
|
+
</div>
|
|
66
|
+
{/if}
|
|
67
|
+
</TableCell>
|
|
68
|
+
|
|
69
|
+
<style>.actions {
|
|
70
|
+
display: flex;
|
|
71
|
+
gap: 0.5rem;
|
|
72
|
+
}</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { JsonObject } from '../types/data.js';
|
|
2
|
+
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
3
|
+
interface Action {
|
|
4
|
+
text: string;
|
|
5
|
+
variant?: ButtonVariant;
|
|
6
|
+
href?: (row: JsonObject) => string;
|
|
7
|
+
onClick?: (row: JsonObject) => unknown;
|
|
8
|
+
}
|
|
9
|
+
interface Actions {
|
|
10
|
+
text?: string;
|
|
11
|
+
type?: 'buttons' | 'dropdown';
|
|
12
|
+
variant?: ButtonVariant | 'default';
|
|
13
|
+
size?: FormFieldSizeOptions;
|
|
14
|
+
align?: 'left' | 'center' | 'right';
|
|
15
|
+
items: Action[];
|
|
16
|
+
}
|
|
17
|
+
type $$ComponentProps = {
|
|
18
|
+
actions: Actions;
|
|
19
|
+
row: JsonObject;
|
|
20
|
+
actionButtonVariant?: ButtonVariant;
|
|
21
|
+
actionButtonSize?: FormFieldSizeOptions;
|
|
22
|
+
actionAlign?: 'left' | 'center' | 'right';
|
|
23
|
+
};
|
|
24
|
+
declare const DataGridActionsCell: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
25
|
+
type DataGridActionsCell = ReturnType<typeof DataGridActionsCell>;
|
|
26
|
+
export default DataGridActionsCell;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ColumnDef, JsonObject } from '../types/data.js';
|
|
4
|
+
import TableCell from './table-cell.svelte';
|
|
5
|
+
import Pill from '../generic/pill/pill.svelte';
|
|
6
|
+
import {
|
|
7
|
+
formatCell,
|
|
8
|
+
getCellLink,
|
|
9
|
+
getCellAlignment,
|
|
10
|
+
getCellTypeClass,
|
|
11
|
+
getCellValue,
|
|
12
|
+
formatArrayCell
|
|
13
|
+
} from './cell-renderers.js';
|
|
14
|
+
|
|
15
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
16
|
+
row: T;
|
|
17
|
+
value: unknown;
|
|
18
|
+
column: ColumnDef<T>;
|
|
19
|
+
rowIndex: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
row,
|
|
24
|
+
column,
|
|
25
|
+
rowIndex,
|
|
26
|
+
cellSnippet = undefined,
|
|
27
|
+
width = undefined
|
|
28
|
+
}: {
|
|
29
|
+
row: JsonObject;
|
|
30
|
+
column: ColumnDef;
|
|
31
|
+
rowIndex: number;
|
|
32
|
+
cellSnippet?: Snippet<[CellContext]>;
|
|
33
|
+
width?: number | string;
|
|
34
|
+
} = $props();
|
|
35
|
+
|
|
36
|
+
let cellValue = $derived(getCellValue(row, column.key));
|
|
37
|
+
let cellAlign = $derived(getCellAlignment(column));
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<TableCell type={getCellTypeClass(column)} {width} align={cellAlign}>
|
|
41
|
+
{#if cellSnippet}
|
|
42
|
+
{@render cellSnippet({ row, value: cellValue, column, rowIndex })}
|
|
43
|
+
{:else if column.type === 'custom' && column.component}
|
|
44
|
+
{@const CellComponent = column.component}
|
|
45
|
+
<CellComponent {row} value={cellValue} column={column} {rowIndex} />
|
|
46
|
+
{:else if column.type === 'array'}
|
|
47
|
+
{@const arrayResult = formatArrayCell(row, column)}
|
|
48
|
+
<span class="array-cell array-{arrayResult.separator}">
|
|
49
|
+
{#each arrayResult.items as item, i}
|
|
50
|
+
{#if arrayResult.separator === 'pill'}
|
|
51
|
+
<Pill compact>
|
|
52
|
+
{#if item.link}<a href={item.link}>{item.text}</a>{:else}{item.text}{/if}
|
|
53
|
+
</Pill>
|
|
54
|
+
{:else if arrayResult.separator === 'line'}
|
|
55
|
+
<div>
|
|
56
|
+
{#if item.link}<a href={item.link}>{item.text}</a>{:else}{item.text}{/if}
|
|
57
|
+
</div>
|
|
58
|
+
{:else}
|
|
59
|
+
{#if i > 0}
|
|
60
|
+
{#if arrayResult.separator === 'comma'},
|
|
61
|
+
{:else if arrayResult.separator === 'semicolon'};
|
|
62
|
+
{/if}
|
|
63
|
+
{/if}
|
|
64
|
+
{#if item.link}<a href={item.link}>{item.text}</a>{:else}{item.text}{/if}
|
|
65
|
+
{/if}
|
|
66
|
+
{/each}
|
|
67
|
+
</span>
|
|
68
|
+
{:else if column.type === 'check' || column.type === 'boolean'}
|
|
69
|
+
{#if row[column.key]}
|
|
70
|
+
<Pill shape="circle" variant="positive" compact label="✔" />
|
|
71
|
+
{/if}
|
|
72
|
+
{:else}
|
|
73
|
+
{@const cellLink = getCellLink(row, column)}
|
|
74
|
+
{#if cellLink}
|
|
75
|
+
<a href={cellLink}>{formatCell(row, column)}</a>
|
|
76
|
+
{:else}
|
|
77
|
+
{formatCell(row, column)}
|
|
78
|
+
{/if}
|
|
79
|
+
{/if}
|
|
80
|
+
</TableCell>
|
|
81
|
+
|
|
82
|
+
<style>a {
|
|
83
|
+
color: var(--table-link-fg, rgb(0, 0, 200));
|
|
84
|
+
text-decoration: none;
|
|
85
|
+
}
|
|
86
|
+
a:hover {
|
|
87
|
+
text-decoration: underline;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.array-cell {
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
align-items: flex-start;
|
|
93
|
+
flex-wrap: wrap;
|
|
94
|
+
}
|
|
95
|
+
.array-cell.array-comma, .array-cell.array-semicolon {
|
|
96
|
+
gap: 0;
|
|
97
|
+
}
|
|
98
|
+
.array-cell.array-line {
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
gap: 0.25rem;
|
|
101
|
+
}
|
|
102
|
+
.array-cell.array-pill {
|
|
103
|
+
gap: 0.25rem;
|
|
104
|
+
}</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ColumnDef, JsonObject } from '../types/data.js';
|
|
3
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
4
|
+
row: T;
|
|
5
|
+
value: unknown;
|
|
6
|
+
column: ColumnDef<T>;
|
|
7
|
+
rowIndex: number;
|
|
8
|
+
}
|
|
9
|
+
type $$ComponentProps = {
|
|
10
|
+
row: JsonObject;
|
|
11
|
+
column: ColumnDef;
|
|
12
|
+
rowIndex: number;
|
|
13
|
+
cellSnippet?: Snippet<[CellContext]>;
|
|
14
|
+
width?: number | string;
|
|
15
|
+
};
|
|
16
|
+
declare const DataGridCell: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
17
|
+
type DataGridCell = ReturnType<typeof DataGridCell>;
|
|
18
|
+
export default DataGridCell;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ColumnDef, JsonObject } from '../types/data.js';
|
|
4
|
+
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
5
|
+
import TableRow from './table-row.svelte';
|
|
6
|
+
import TableSelectionCell from './table-selection-cell.svelte';
|
|
7
|
+
import DataGridCell from './data-grid-cell.svelte';
|
|
8
|
+
import DataGridActionsCell from './data-grid-actions-cell.svelte';
|
|
9
|
+
|
|
10
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
11
|
+
row: T;
|
|
12
|
+
value: unknown;
|
|
13
|
+
column: ColumnDef<T>;
|
|
14
|
+
rowIndex: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface Action {
|
|
18
|
+
text: string;
|
|
19
|
+
variant?: ButtonVariant;
|
|
20
|
+
href?: (row: JsonObject) => string;
|
|
21
|
+
onClick?: (row: JsonObject) => unknown;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface Actions {
|
|
25
|
+
text?: string;
|
|
26
|
+
type?: 'buttons' | 'dropdown';
|
|
27
|
+
variant?: ButtonVariant | 'default';
|
|
28
|
+
size?: FormFieldSizeOptions;
|
|
29
|
+
align?: 'left' | 'center' | 'right';
|
|
30
|
+
items: Action[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
row,
|
|
35
|
+
rowIndex,
|
|
36
|
+
visibleCols,
|
|
37
|
+
hasSelectionCol = false,
|
|
38
|
+
hasActionCol = false,
|
|
39
|
+
actions = undefined,
|
|
40
|
+
cells = undefined,
|
|
41
|
+
actionButtonVariant = 'outline',
|
|
42
|
+
actionButtonSize = 'sm',
|
|
43
|
+
actionAlign = 'center'
|
|
44
|
+
}: {
|
|
45
|
+
row: JsonObject;
|
|
46
|
+
rowIndex: number;
|
|
47
|
+
visibleCols: ColumnDef[];
|
|
48
|
+
hasSelectionCol?: boolean;
|
|
49
|
+
hasActionCol?: boolean;
|
|
50
|
+
actions?: Actions;
|
|
51
|
+
cells?: Record<string, Snippet<[CellContext]>>;
|
|
52
|
+
actionButtonVariant?: ButtonVariant;
|
|
53
|
+
actionButtonSize?: FormFieldSizeOptions;
|
|
54
|
+
actionAlign?: 'left' | 'center' | 'right';
|
|
55
|
+
} = $props();
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<TableRow {row} {rowIndex} selectable={hasSelectionCol}>
|
|
59
|
+
{#if hasSelectionCol}
|
|
60
|
+
<TableSelectionCell {row} {rowIndex} />
|
|
61
|
+
{/if}
|
|
62
|
+
{#each visibleCols as col}
|
|
63
|
+
<DataGridCell
|
|
64
|
+
{row}
|
|
65
|
+
column={col}
|
|
66
|
+
{rowIndex}
|
|
67
|
+
cellSnippet={cells?.[col.key]}
|
|
68
|
+
width={col.width}
|
|
69
|
+
/>
|
|
70
|
+
{/each}
|
|
71
|
+
{#if hasActionCol && actions}
|
|
72
|
+
<DataGridActionsCell {actions} {row} {actionButtonVariant} {actionButtonSize} {actionAlign} />
|
|
73
|
+
{/if}
|
|
74
|
+
</TableRow>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ColumnDef, JsonObject } from '../types/data.js';
|
|
3
|
+
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
4
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
5
|
+
row: T;
|
|
6
|
+
value: unknown;
|
|
7
|
+
column: ColumnDef<T>;
|
|
8
|
+
rowIndex: number;
|
|
9
|
+
}
|
|
10
|
+
interface Action {
|
|
11
|
+
text: string;
|
|
12
|
+
variant?: ButtonVariant;
|
|
13
|
+
href?: (row: JsonObject) => string;
|
|
14
|
+
onClick?: (row: JsonObject) => unknown;
|
|
15
|
+
}
|
|
16
|
+
interface Actions {
|
|
17
|
+
text?: string;
|
|
18
|
+
type?: 'buttons' | 'dropdown';
|
|
19
|
+
variant?: ButtonVariant | 'default';
|
|
20
|
+
size?: FormFieldSizeOptions;
|
|
21
|
+
align?: 'left' | 'center' | 'right';
|
|
22
|
+
items: Action[];
|
|
23
|
+
}
|
|
24
|
+
type $$ComponentProps = {
|
|
25
|
+
row: JsonObject;
|
|
26
|
+
rowIndex: number;
|
|
27
|
+
visibleCols: ColumnDef[];
|
|
28
|
+
hasSelectionCol?: boolean;
|
|
29
|
+
hasActionCol?: boolean;
|
|
30
|
+
actions?: Actions;
|
|
31
|
+
cells?: Record<string, Snippet<[CellContext]>>;
|
|
32
|
+
actionButtonVariant?: ButtonVariant;
|
|
33
|
+
actionButtonSize?: FormFieldSizeOptions;
|
|
34
|
+
actionAlign?: 'left' | 'center' | 'right';
|
|
35
|
+
};
|
|
36
|
+
declare const DataGridRow: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
37
|
+
type DataGridRow = ReturnType<typeof DataGridRow>;
|
|
38
|
+
export default DataGridRow;
|
|
@@ -2,33 +2,29 @@
|
|
|
2
2
|
import TableCell from './table-cell.svelte';
|
|
3
3
|
import TableHeaderCell from './table-header-cell.svelte';
|
|
4
4
|
import TableHeader from './table-header.svelte';
|
|
5
|
-
import TableRow from './table-row.svelte';
|
|
6
5
|
import Table from './table.svelte';
|
|
7
|
-
import TableSelectionCell from './table-selection-cell.svelte';
|
|
8
6
|
import TableSelectionHeaderCell from './table-selection-header-cell.svelte';
|
|
7
|
+
import DataGridRow from './data-grid-row.svelte';
|
|
9
8
|
import type { ColumnDef, JsonObject, PaginationProperties } from '../types/data.js';
|
|
10
|
-
import Button from '../forms/button/button.svelte';
|
|
11
|
-
import DropdownItem from '../generic/dropdown-item/dropdown-item.svelte';
|
|
12
9
|
import Empty from '../generic/empty/empty.svelte';
|
|
13
|
-
import Pill from '../generic/pill/pill.svelte';
|
|
14
10
|
import Icon from '../icons/icon.svelte';
|
|
15
|
-
import DropdownButton from '../navigation/dropdown-button/dropdown-button.svelte';
|
|
16
11
|
import Pagination from '../navigation/pagination/pagination.svelte';
|
|
17
12
|
import Loading from '../placeholders/loading.svelte';
|
|
18
13
|
import TableCaption from './table-caption.svelte';
|
|
19
|
-
import {
|
|
20
|
-
formatCell,
|
|
21
|
-
getCellLink,
|
|
22
|
-
getCellAlignment,
|
|
23
|
-
getCellTypeClass,
|
|
24
|
-
sortRows
|
|
25
|
-
} from './cell-renderers.js';
|
|
14
|
+
import { getCellAlignment, sortRows } from './cell-renderers.js';
|
|
26
15
|
import type { Snippet } from 'svelte';
|
|
27
16
|
import { useVirtualList } from '../helpers/use-virtual-list.svelte.js';
|
|
28
17
|
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
29
18
|
|
|
30
19
|
type PaginationEvent = (pagination: PaginationProperties) => void;
|
|
31
20
|
|
|
21
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
22
|
+
row: T;
|
|
23
|
+
value: unknown;
|
|
24
|
+
column: ColumnDef<T>;
|
|
25
|
+
rowIndex: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
32
28
|
interface Action {
|
|
33
29
|
text: string;
|
|
34
30
|
variant?: ButtonVariant;
|
|
@@ -61,6 +57,7 @@
|
|
|
61
57
|
onSelectionChange = undefined,
|
|
62
58
|
selectedCount = $bindable(0),
|
|
63
59
|
children = undefined,
|
|
60
|
+
cells = undefined,
|
|
64
61
|
virtualScroll = false,
|
|
65
62
|
rowHeight = 48,
|
|
66
63
|
maxHeight = '600px'
|
|
@@ -80,6 +77,7 @@
|
|
|
80
77
|
onSelectionChange?: (selectedRows: JsonObject[]) => void;
|
|
81
78
|
selectedCount?: number;
|
|
82
79
|
children?: Snippet;
|
|
80
|
+
cells?: Record<string, Snippet<[CellContext]>>;
|
|
83
81
|
virtualScroll?: boolean;
|
|
84
82
|
rowHeight?: number;
|
|
85
83
|
maxHeight?: string;
|
|
@@ -257,7 +255,7 @@
|
|
|
257
255
|
: ''}
|
|
258
256
|
>
|
|
259
257
|
{#if !filteredRows?.length}
|
|
260
|
-
<
|
|
258
|
+
<tr>
|
|
261
259
|
<TableCell colspan={colCount}>
|
|
262
260
|
<div class="empty" role="status" aria-live="polite">
|
|
263
261
|
{#if rows === undefined}
|
|
@@ -269,7 +267,7 @@
|
|
|
269
267
|
{/if}
|
|
270
268
|
</div>
|
|
271
269
|
</TableCell>
|
|
272
|
-
</
|
|
270
|
+
</tr>
|
|
273
271
|
{:else if virtualScroll && !pagination && virtual}
|
|
274
272
|
<!-- Virtual scrolling mode -->
|
|
275
273
|
<tr style="height: {virtual.totalHeight}px; position: relative;">
|
|
@@ -280,57 +278,18 @@
|
|
|
280
278
|
<div
|
|
281
279
|
style="position: absolute; top: {vItem.offsetTop}px; height: {vItem.height}px; width: 100%; display: table; table-layout: fixed;"
|
|
282
280
|
>
|
|
283
|
-
<
|
|
284
|
-
{
|
|
285
|
-
|
|
286
|
-
{
|
|
287
|
-
{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
{#if row[col.key]}
|
|
296
|
-
<Pill shape="circle" variant="positive" compact label="✔" />
|
|
297
|
-
{/if}
|
|
298
|
-
{:else}
|
|
299
|
-
{cellValue}
|
|
300
|
-
{/if}
|
|
301
|
-
</TableCell>
|
|
302
|
-
{/each}
|
|
303
|
-
{#if hasActionCol && actions}
|
|
304
|
-
<TableCell type="actions" align={actionAlign}>
|
|
305
|
-
{#if actions.type === 'dropdown'}
|
|
306
|
-
<DropdownButton text={actions.text ?? ''} variant="ghost">
|
|
307
|
-
{#each actions.items as action}
|
|
308
|
-
<DropdownItem
|
|
309
|
-
href={action.href ? action.href(row) : undefined}
|
|
310
|
-
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
311
|
-
>{action.text}</DropdownItem
|
|
312
|
-
>
|
|
313
|
-
{/each}
|
|
314
|
-
</DropdownButton>
|
|
315
|
-
{:else}
|
|
316
|
-
<div class="actions">
|
|
317
|
-
{#each actions.items as action}
|
|
318
|
-
{@const buttonVariant = action.variant ?? actionButtonVariant}
|
|
319
|
-
<Button
|
|
320
|
-
collapse={true}
|
|
321
|
-
type="button"
|
|
322
|
-
variant={buttonVariant}
|
|
323
|
-
size={actionButtonSize}
|
|
324
|
-
href={action.href ? action.href(row) : undefined}
|
|
325
|
-
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
326
|
-
label={action.text}
|
|
327
|
-
/>
|
|
328
|
-
{/each}
|
|
329
|
-
</div>
|
|
330
|
-
{/if}
|
|
331
|
-
</TableCell>
|
|
332
|
-
{/if}
|
|
333
|
-
</TableRow>
|
|
281
|
+
<DataGridRow
|
|
282
|
+
{row}
|
|
283
|
+
rowIndex={index}
|
|
284
|
+
{visibleCols}
|
|
285
|
+
{hasSelectionCol}
|
|
286
|
+
{hasActionCol}
|
|
287
|
+
{actions}
|
|
288
|
+
{cells}
|
|
289
|
+
{actionButtonVariant}
|
|
290
|
+
{actionButtonSize}
|
|
291
|
+
{actionAlign}
|
|
292
|
+
/>
|
|
334
293
|
</div>
|
|
335
294
|
{/each}
|
|
336
295
|
</td>
|
|
@@ -338,56 +297,18 @@
|
|
|
338
297
|
{:else}
|
|
339
298
|
<!-- Regular rendering mode -->
|
|
340
299
|
{#each filteredRows as row, index}
|
|
341
|
-
<
|
|
342
|
-
{
|
|
343
|
-
|
|
344
|
-
{
|
|
345
|
-
{
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
{#if row[col.key]}
|
|
354
|
-
<Pill shape="circle" variant="positive" compact label="✔" />
|
|
355
|
-
{/if}
|
|
356
|
-
{:else}
|
|
357
|
-
{cellValue}
|
|
358
|
-
{/if}
|
|
359
|
-
</TableCell>
|
|
360
|
-
{/each}
|
|
361
|
-
{#if hasActionCol && actions}
|
|
362
|
-
<TableCell type="actions" align={actionAlign}>
|
|
363
|
-
{#if actions.type === 'dropdown'}
|
|
364
|
-
<DropdownButton text={actions.text ?? ''} variant="ghost">
|
|
365
|
-
{#each actions.items as action}
|
|
366
|
-
<DropdownItem
|
|
367
|
-
href={action.href ? action.href(row) : undefined}
|
|
368
|
-
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
369
|
-
>{action.text}</DropdownItem
|
|
370
|
-
>
|
|
371
|
-
{/each}
|
|
372
|
-
</DropdownButton>
|
|
373
|
-
{:else}
|
|
374
|
-
<div class="actions">
|
|
375
|
-
{#each actions.items as action}
|
|
376
|
-
{@const buttonVariant = action.variant ?? actionButtonVariant}
|
|
377
|
-
<Button
|
|
378
|
-
type="button"
|
|
379
|
-
variant={buttonVariant}
|
|
380
|
-
size={actionButtonSize}
|
|
381
|
-
href={action.href ? action.href(row) : undefined}
|
|
382
|
-
onClick={action.onClick ? () => action.onClick?.(row) : undefined}
|
|
383
|
-
label={action.text}
|
|
384
|
-
/>
|
|
385
|
-
{/each}
|
|
386
|
-
</div>
|
|
387
|
-
{/if}
|
|
388
|
-
</TableCell>
|
|
389
|
-
{/if}
|
|
390
|
-
</TableRow>
|
|
300
|
+
<DataGridRow
|
|
301
|
+
{row}
|
|
302
|
+
rowIndex={index}
|
|
303
|
+
{visibleCols}
|
|
304
|
+
{hasSelectionCol}
|
|
305
|
+
{hasActionCol}
|
|
306
|
+
{actions}
|
|
307
|
+
{cells}
|
|
308
|
+
{actionButtonVariant}
|
|
309
|
+
{actionButtonSize}
|
|
310
|
+
{actionAlign}
|
|
311
|
+
/>
|
|
391
312
|
{/each}
|
|
392
313
|
{/if}
|
|
393
314
|
</tbody>
|
|
@@ -418,14 +339,6 @@
|
|
|
418
339
|
letter-spacing: 0.2rem;
|
|
419
340
|
}
|
|
420
341
|
|
|
421
|
-
a {
|
|
422
|
-
color: var(--table-link-fg, rgb(0, 0, 200));
|
|
423
|
-
text-decoration: none;
|
|
424
|
-
}
|
|
425
|
-
a:hover {
|
|
426
|
-
text-decoration: underline;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
342
|
tfoot {
|
|
430
343
|
background: var(--table-footer-bg);
|
|
431
344
|
color: var(--table-footer-fg);
|
|
@@ -442,9 +355,4 @@ td.footer-cell :global(.pagination) {
|
|
|
442
355
|
display: flex;
|
|
443
356
|
justify-content: center;
|
|
444
357
|
align-items: center;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
.actions {
|
|
448
|
-
display: flex;
|
|
449
|
-
gap: 0.5rem;
|
|
450
358
|
}</style>
|
|
@@ -2,6 +2,12 @@ import type { ColumnDef, JsonObject, PaginationProperties } from '../types/data.
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { ButtonVariant, FormFieldSizeOptions } from '../types/form.js';
|
|
4
4
|
type PaginationEvent = (pagination: PaginationProperties) => void;
|
|
5
|
+
interface CellContext<T extends JsonObject = JsonObject> {
|
|
6
|
+
row: T;
|
|
7
|
+
value: unknown;
|
|
8
|
+
column: ColumnDef<T>;
|
|
9
|
+
rowIndex: number;
|
|
10
|
+
}
|
|
5
11
|
interface Action {
|
|
6
12
|
text: string;
|
|
7
13
|
variant?: ButtonVariant;
|
|
@@ -32,6 +38,7 @@ type $$ComponentProps = {
|
|
|
32
38
|
onSelectionChange?: (selectedRows: JsonObject[]) => void;
|
|
33
39
|
selectedCount?: number;
|
|
34
40
|
children?: Snippet;
|
|
41
|
+
cells?: Record<string, Snippet<[CellContext]>>;
|
|
35
42
|
virtualScroll?: boolean;
|
|
36
43
|
rowHeight?: number;
|
|
37
44
|
maxHeight?: string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CellRendererProps } from '../types/data.js';
|
|
3
|
+
import Pill from '../generic/pill/pill.svelte';
|
|
4
|
+
|
|
5
|
+
type StatusValue = 'active' | 'completed' | 'on-hold';
|
|
6
|
+
|
|
7
|
+
let { value }: CellRendererProps = $props();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
{#if value === 'active'}
|
|
11
|
+
<Pill variant="positive" compact label="✓ Active" />
|
|
12
|
+
{:else if value === 'completed'}
|
|
13
|
+
<Pill variant="standard" compact label="✓ Completed" />
|
|
14
|
+
{:else}
|
|
15
|
+
<Pill variant="negative" compact label="⚠ On Hold" />
|
|
16
|
+
{/if}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CellRendererProps } from '../types/data.js';
|
|
2
|
+
declare const ExampleStatusCell: import("svelte").Component<CellRendererProps<import("../types/data.js").JsonObject>, {}, "">;
|
|
3
|
+
type ExampleStatusCell = ReturnType<typeof ExampleStatusCell>;
|
|
4
|
+
export default ExampleStatusCell;
|
package/dist/tables/index.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export { default as TableRow } from './table-row.svelte';
|
|
|
7
7
|
export { default as TableCaption } from './table-caption.svelte';
|
|
8
8
|
export { createTableContext, getTableContext, TableContext } from './table-context.svelte.js';
|
|
9
9
|
export type { TableContextConfig } from './table-context.svelte.js';
|
|
10
|
-
export { formatCell, formatTextCell, formatNumberCell, formatCurrencyCell, formatDateCell, formatDateTimeCell, formatBooleanCell, formatEmailCell, formatCustomCell, getCellValue, getCellLink, getCellAlignment, getCellTypeClass, sortRows, compareValues } from './cell-renderers.js';
|
|
10
|
+
export { formatCell, formatTextCell, formatNumberCell, formatCurrencyCell, formatDateCell, formatDateTimeCell, formatBooleanCell, formatEmailCell, formatArrayCell, formatCustomCell, getCellValue, getCellLink, getCellAlignment, getCellTypeClass, sortRows, compareValues } from './cell-renderers.js';
|
|
11
|
+
export type { ArrayCellResult, CellRenderContext } from './cell-renderers.js';
|
package/dist/tables/index.js
CHANGED
|
@@ -9,4 +9,4 @@ export { default as TableCaption } from './table-caption.svelte';
|
|
|
9
9
|
// Context and utilities
|
|
10
10
|
export { createTableContext, getTableContext, TableContext } from './table-context.svelte.js';
|
|
11
11
|
// Cell renderers and utilities
|
|
12
|
-
export { formatCell, formatTextCell, formatNumberCell, formatCurrencyCell, formatDateCell, formatDateTimeCell, formatBooleanCell, formatEmailCell, formatCustomCell, getCellValue, getCellLink, getCellAlignment, getCellTypeClass, sortRows, compareValues } from './cell-renderers.js';
|
|
12
|
+
export { formatCell, formatTextCell, formatNumberCell, formatCurrencyCell, formatDateCell, formatDateTimeCell, formatBooleanCell, formatEmailCell, formatArrayCell, formatCustomCell, getCellValue, getCellLink, getCellAlignment, getCellTypeClass, sortRows, compareValues } from './cell-renderers.js';
|
package/dist/types/data.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Component } from 'svelte';
|
|
1
2
|
export type JsonValue = string | number | boolean | null | {
|
|
2
3
|
[key: string]: JsonValue;
|
|
3
4
|
} | JsonValue[];
|
|
@@ -50,11 +51,25 @@ export interface EmailColumn<T extends JsonObject = JsonObject> extends BaseColu
|
|
|
50
51
|
type: 'email';
|
|
51
52
|
format?: (value: string, row: T) => string;
|
|
52
53
|
}
|
|
54
|
+
export interface ArrayColumn<T extends JsonObject = JsonObject> extends BaseColumn<T> {
|
|
55
|
+
type: 'array';
|
|
56
|
+
displayKey?: string;
|
|
57
|
+
format?: (element: unknown, row: T, index: number) => string;
|
|
58
|
+
link?: (element: unknown, row: T, index: number) => string | null;
|
|
59
|
+
separator?: 'comma' | 'semicolon' | 'line' | 'pill';
|
|
60
|
+
}
|
|
61
|
+
export interface CellRendererProps<T extends JsonObject = JsonObject> {
|
|
62
|
+
row: T;
|
|
63
|
+
value: unknown;
|
|
64
|
+
column: ColumnDef<T>;
|
|
65
|
+
rowIndex: number;
|
|
66
|
+
}
|
|
53
67
|
export interface CustomColumn<T extends JsonObject = JsonObject> extends BaseColumn<T> {
|
|
54
68
|
type: 'custom';
|
|
55
|
-
render
|
|
69
|
+
render?: (row: T) => string | number | boolean;
|
|
70
|
+
component?: Component<CellRendererProps<T>>;
|
|
56
71
|
}
|
|
57
|
-
export type ColumnDef<T extends JsonObject = JsonObject> = TextColumn<T> | NumberColumn<T> | CurrencyColumn<T> | DateColumn<T> | DateTimeColumn<T> | BooleanColumn<T> | EmailColumn<T> | CustomColumn<T>;
|
|
72
|
+
export type ColumnDef<T extends JsonObject = JsonObject> = TextColumn<T> | NumberColumn<T> | CurrencyColumn<T> | DateColumn<T> | DateTimeColumn<T> | BooleanColumn<T> | EmailColumn<T> | ArrayColumn<T> | CustomColumn<T>;
|
|
58
73
|
export type DataCol = {
|
|
59
74
|
key: string;
|
|
60
75
|
label: string;
|