@warkypublic/svelix 0.1.44 → 0.1.46

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.
@@ -0,0 +1,61 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { CardGridColumn, CardSortOption, CardGridContextMenuItem } from './cardGrid.js';
3
+ import type { GridColumnSortOrder, GridColumnFilters } from '../Types/generic_grid.js';
4
+ interface Props {
5
+ columns: CardGridColumn[];
6
+ displayColumns?: string[];
7
+ cardMinWidth?: number;
8
+ cardGap?: number;
9
+ /**
10
+ * Maximum number of columns shown on the front face.
11
+ * When `resolvedColumns.length` exceeds this, a flip button appears and the
12
+ * remaining columns are shown on the card's back face.
13
+ */
14
+ cardMaxFrontColumns?: number;
15
+ /** Front-face snippet: (record, index, selected, focused) */
16
+ card?: Snippet<[Record<string, unknown>, number, boolean, boolean]>;
17
+ /** Back-face snippet for flip mode: (record, index, selected, focused) */
18
+ cardBack?: Snippet<[Record<string, unknown>, number, boolean, boolean]>;
19
+ empty?: Snippet;
20
+ skeleton?: Snippet;
21
+ dataSource?: 'resolvespec' | 'headerspec' | 'local';
22
+ dataSourceOptions?: {
23
+ url?: string;
24
+ authToken?: string;
25
+ schema?: string;
26
+ entity?: string;
27
+ uniqueID?: string;
28
+ hotfields?: string[];
29
+ extraOptions?: Record<string, unknown>;
30
+ };
31
+ data?: Record<string, unknown>[] | (() => Promise<Record<string, unknown>[]>);
32
+ pageSize?: number;
33
+ uniqueID?: string;
34
+ searchValue?: string;
35
+ onSearchValueChange?: (v: string) => void;
36
+ serverSideSearch?: boolean;
37
+ searchColumns?: string[];
38
+ searchPlaceholder?: string;
39
+ sortOrder?: GridColumnSortOrder;
40
+ onSortOrderChange?: (order: GridColumnSortOrder) => void;
41
+ sortOptions?: CardSortOption[];
42
+ filters?: GridColumnFilters;
43
+ onFilterChange?: (filters: GridColumnFilters) => void;
44
+ selectedItems?: Record<string, unknown>[];
45
+ onSelectedItemsChange?: (items: Record<string, unknown>[]) => void;
46
+ multiSelect?: boolean;
47
+ onCardClick?: (record: Record<string, unknown>, index: number) => void;
48
+ onCardDblClick?: (record: Record<string, unknown>, index: number) => void;
49
+ onCardContextMenu?: (record: Record<string, unknown>, index: number, x: number, y: number) => void;
50
+ menuItems?: CardGridContextMenuItem[];
51
+ total?: number;
52
+ loading?: boolean;
53
+ onLoadError?: (error: string) => void;
54
+ class?: string;
55
+ toolbarEnd?: Snippet;
56
+ }
57
+ declare const CardGrid: import("svelte").Component<Props, {
58
+ refresh: () => void;
59
+ }, "loading" | "total">;
60
+ type CardGrid = ReturnType<typeof CardGrid>;
61
+ export default CardGrid;
@@ -0,0 +1,299 @@
1
+ <script lang="ts">
2
+ import type { CardGridColumn } from './cardGrid.js';
3
+ import type { GridColumnFilters } from '../Types/generic_grid.js';
4
+
5
+ interface Props {
6
+ columns: CardGridColumn[];
7
+ filters: GridColumnFilters;
8
+ onApply: (filters: GridColumnFilters) => void;
9
+ onCancel: () => void;
10
+ }
11
+
12
+ const { columns, filters, onApply, onCancel }: Props = $props();
13
+
14
+ type Op = NonNullable<GridColumnFilters[string]['op']>;
15
+
16
+ const ALL_OPERATORS: { value: Op; label: string }[] = [
17
+ { value: 'contains', label: 'Contains' },
18
+ { value: 'equals', label: 'Equals' },
19
+ { value: 'notEquals', label: 'Not equals' },
20
+ { value: 'startsWith', label: 'Starts with' },
21
+ { value: 'endsWith', label: 'Ends with' },
22
+ { value: 'greaterThan', label: '>' },
23
+ { value: 'greaterThanOrEqual', label: '>=' },
24
+ { value: 'lessThan', label: '<' },
25
+ { value: 'lessThanOrEqual', label: '<=' },
26
+ { value: 'between', label: 'Between' },
27
+ { value: 'notBetween', label: 'Not between' },
28
+ { value: 'in', label: 'In (comma-sep)' },
29
+ { value: 'notIn', label: 'Not in' },
30
+ { value: 'isNull', label: 'Is empty' },
31
+ { value: 'isNotNull', label: 'Is not empty' },
32
+ ];
33
+
34
+ const filterableColumns = $derived(columns.filter((c) => !c.disableFilter));
35
+
36
+ interface FilterRow {
37
+ colId: string;
38
+ op: Op;
39
+ value: string;
40
+ value2: string;
41
+ }
42
+
43
+ function filtersToRows(f: GridColumnFilters): FilterRow[] {
44
+ return Object.entries(f).map(([colId, entry]) => ({
45
+ colId,
46
+ op: entry.op ?? 'contains',
47
+ value: entry.value ?? '',
48
+ value2: entry.value2 ?? '',
49
+ }));
50
+ }
51
+
52
+ let rows = $state<FilterRow[]>([]);
53
+
54
+ $effect(() => {
55
+ rows = filtersToRows(filters);
56
+ });
57
+
58
+ function addRow() {
59
+ const firstCol = filterableColumns[0];
60
+ if (!firstCol) return;
61
+ rows = [...rows, { colId: firstCol.id, op: 'contains', value: '', value2: '' }];
62
+ }
63
+
64
+ function removeRow(index: number) {
65
+ rows = rows.filter((_, i) => i !== index);
66
+ }
67
+
68
+ function apply() {
69
+ const next: GridColumnFilters = {};
70
+ for (const row of rows) {
71
+ if (!row.colId) continue;
72
+ const needsValue = row.op !== 'isNull' && row.op !== 'isNotNull';
73
+ if (needsValue && !row.value) continue;
74
+ const col = columns.find((c) => c.id === row.colId);
75
+ const entry: GridColumnFilters[string] = {
76
+ value: row.value,
77
+ op: row.op,
78
+ ...(col?.dataKey ? { dataKey: col.dataKey } : {}),
79
+ };
80
+ if ((row.op === 'between' || row.op === 'notBetween') && row.value2) {
81
+ entry.value2 = row.value2;
82
+ }
83
+ next[row.colId] = entry;
84
+ }
85
+ onApply(next);
86
+ }
87
+
88
+ function clear() {
89
+ onApply({});
90
+ }
91
+
92
+ const needsValue = (op: Op) => op !== 'isNull' && op !== 'isNotNull';
93
+ const needsValue2 = (op: Op) => op === 'between' || op === 'notBetween';
94
+ </script>
95
+
96
+ <div class="fp-panel">
97
+ <div class="fp-header">
98
+ <span class="fp-title">Filters</span>
99
+ <button class="fp-add-btn" onclick={addRow} type="button">+ Add filter</button>
100
+ </div>
101
+
102
+ {#if rows.length === 0}
103
+ <p class="fp-empty">No filters applied.</p>
104
+ {/if}
105
+
106
+ {#each rows as row, i (i)}
107
+ <div class="fp-row">
108
+ <select
109
+ class="fp-select"
110
+ bind:value={row.colId}
111
+ aria-label="Column"
112
+ >
113
+ {#each filterableColumns as col (col.id)}
114
+ <option value={col.id}>{col.title}</option>
115
+ {/each}
116
+ </select>
117
+
118
+ <select
119
+ class="fp-select fp-select-op"
120
+ bind:value={row.op}
121
+ aria-label="Operator"
122
+ >
123
+ {#each ALL_OPERATORS as op (op.value)}
124
+ <option value={op.value}>{op.label}</option>
125
+ {/each}
126
+ </select>
127
+
128
+ {#if needsValue(row.op)}
129
+ <input
130
+ class="fp-input"
131
+ type="text"
132
+ bind:value={row.value}
133
+ placeholder="Value"
134
+ aria-label="Filter value"
135
+ />
136
+ {/if}
137
+
138
+ {#if needsValue2(row.op)}
139
+ <input
140
+ class="fp-input"
141
+ type="text"
142
+ bind:value={row.value2}
143
+ placeholder="To"
144
+ aria-label="Filter value 2"
145
+ />
146
+ {/if}
147
+
148
+ <button
149
+ class="fp-remove-btn"
150
+ onclick={() => removeRow(i)}
151
+ type="button"
152
+ aria-label="Remove filter"
153
+ >✕</button>
154
+ </div>
155
+ {/each}
156
+
157
+ <div class="fp-actions">
158
+ <button class="fp-btn fp-btn-clear" onclick={clear} type="button">Clear all</button>
159
+ <div class="fp-actions-right">
160
+ <button class="fp-btn" onclick={onCancel} type="button">Cancel</button>
161
+ <button class="fp-btn fp-btn-apply" onclick={apply} type="button">Apply</button>
162
+ </div>
163
+ </div>
164
+ </div>
165
+
166
+ <style>
167
+ .fp-panel {
168
+ background: var(--cg-surface-raised, var(--color-surface-50, #fff));
169
+ border: 1px solid var(--cg-border, var(--color-surface-200, #e2e8f0));
170
+ border-radius: 10px;
171
+ box-shadow: 0 8px 24px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.07);
172
+ min-width: 460px;
173
+ padding: 14px;
174
+ display: flex;
175
+ flex-direction: column;
176
+ gap: 8px;
177
+ color: var(--cg-text, var(--color-surface-900, #0f172a));
178
+ }
179
+
180
+ :global(.dark) .fp-panel {
181
+ box-shadow: 0 8px 24px rgba(0,0,0,.4), 0 2px 6px rgba(0,0,0,.3);
182
+ }
183
+
184
+ .fp-header {
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: space-between;
188
+ }
189
+
190
+ .fp-title {
191
+ font-weight: 600;
192
+ font-size: 0.875rem;
193
+ }
194
+
195
+ .fp-add-btn {
196
+ font-size: 0.8rem;
197
+ color: var(--cg-accent, var(--color-primary-500, #6366f1));
198
+ background: none;
199
+ border: none;
200
+ cursor: pointer;
201
+ padding: 2px 4px;
202
+ }
203
+
204
+ .fp-empty {
205
+ color: var(--cg-text-muted, var(--color-surface-500, #64748b));
206
+ font-size: 0.85rem;
207
+ margin: 4px 0;
208
+ }
209
+
210
+ .fp-row {
211
+ display: flex;
212
+ gap: 6px;
213
+ align-items: center;
214
+ flex-wrap: wrap;
215
+ }
216
+
217
+ .fp-select {
218
+ padding: 5px 7px;
219
+ border: 1px solid var(--cg-border, var(--color-surface-200, #e2e8f0));
220
+ border-radius: 6px;
221
+ font-size: 0.8rem;
222
+ background: var(--cg-surface-raised, #fff);
223
+ color: var(--cg-text, #0f172a);
224
+ cursor: pointer;
225
+ }
226
+
227
+ .fp-select-op {
228
+ min-width: 120px;
229
+ }
230
+
231
+ .fp-input {
232
+ padding: 5px 8px;
233
+ border: 1px solid var(--cg-border, var(--color-surface-200, #e2e8f0));
234
+ border-radius: 6px;
235
+ font-size: 0.8rem;
236
+ min-width: 100px;
237
+ flex: 1;
238
+ background: var(--cg-surface-raised, #fff);
239
+ color: var(--cg-text, #0f172a);
240
+ }
241
+ .fp-input::placeholder { color: var(--cg-text-muted, #94a3b8); }
242
+
243
+ .fp-remove-btn {
244
+ background: none;
245
+ border: none;
246
+ cursor: pointer;
247
+ color: var(--cg-text-muted, #94a3b8);
248
+ padding: 2px 4px;
249
+ font-size: 0.875rem;
250
+ flex-shrink: 0;
251
+ }
252
+
253
+ .fp-remove-btn:hover {
254
+ color: var(--color-error-500, #ef4444);
255
+ }
256
+
257
+ .fp-actions {
258
+ display: flex;
259
+ justify-content: space-between;
260
+ align-items: center;
261
+ padding-top: 6px;
262
+ border-top: 1px solid var(--cg-border, var(--color-surface-200, #e2e8f0));
263
+ margin-top: 2px;
264
+ }
265
+
266
+ .fp-actions-right {
267
+ display: flex;
268
+ gap: 6px;
269
+ }
270
+
271
+ .fp-btn {
272
+ padding: 5px 12px;
273
+ border-radius: 6px;
274
+ font-size: 0.8rem;
275
+ cursor: pointer;
276
+ border: 1px solid var(--cg-border, var(--color-surface-200, #e2e8f0));
277
+ background: var(--cg-surface-raised, #fff);
278
+ color: var(--cg-text, #0f172a);
279
+ transition: background 120ms;
280
+ }
281
+ .fp-btn:hover { background: var(--cg-border-subtle, var(--color-surface-100, #f1f5f9)); }
282
+
283
+ .fp-btn-apply {
284
+ background: var(--cg-accent, var(--color-primary-500, #6366f1));
285
+ color: #fff;
286
+ border-color: var(--cg-accent, var(--color-primary-500, #6366f1));
287
+ }
288
+ .fp-btn-apply:hover {
289
+ background: var(--color-primary-600, #4f46e5);
290
+ border-color: var(--color-primary-600, #4f46e5);
291
+ }
292
+
293
+ .fp-btn-clear {
294
+ color: var(--color-error-500, #ef4444);
295
+ border-color: transparent;
296
+ background: none;
297
+ }
298
+ .fp-btn-clear:hover { background: color-mix(in oklab, var(--color-error-500, #ef4444) 10%, transparent); }
299
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { CardGridColumn } from './cardGrid.js';
2
+ import type { GridColumnFilters } from '../Types/generic_grid.js';
3
+ interface Props {
4
+ columns: CardGridColumn[];
5
+ filters: GridColumnFilters;
6
+ onApply: (filters: GridColumnFilters) => void;
7
+ onCancel: () => void;
8
+ }
9
+ declare const CardGridFilterPanel: import("svelte").Component<Props, {}, "">;
10
+ type CardGridFilterPanel = ReturnType<typeof CardGridFilterPanel>;
11
+ export default CardGridFilterPanel;
@@ -0,0 +1,303 @@
1
+ <script lang="ts">
2
+ import type { CardGridColumn } from './cardGrid.js';
3
+
4
+ interface Props {
5
+ record: Record<string, unknown>;
6
+ columns: CardGridColumn[];
7
+ selected: boolean;
8
+ focused: boolean;
9
+ }
10
+
11
+ const { record, columns, selected, focused }: Props = $props();
12
+
13
+ // First column → title, second → subtitle, rest → detail rows
14
+ const titleCol = $derived(columns[0]);
15
+ const subtitleCol = $derived(columns.length > 1 ? columns[1] : undefined);
16
+ const detailCols = $derived(columns.slice(subtitleCol ? 2 : 1));
17
+
18
+ function getVal(key: string, row: Record<string, unknown>): unknown {
19
+ const parts = key.split('.');
20
+ let val: unknown = row;
21
+ for (const part of parts) {
22
+ if (val == null || typeof val !== 'object') return undefined;
23
+ val = (val as Record<string, unknown>)[part];
24
+ }
25
+ return val;
26
+ }
27
+
28
+ function formatVal(val: unknown, col: CardGridColumn): string {
29
+ if (val == null || val === '') return '—';
30
+ switch (col.format) {
31
+ case 'currency': {
32
+ const n = Number(val);
33
+ if (!isNaN(n))
34
+ return new Intl.NumberFormat(undefined, {
35
+ style: 'currency',
36
+ currency: 'ZAR',
37
+ maximumFractionDigits: 0,
38
+ }).format(n);
39
+ break;
40
+ }
41
+ case 'number': {
42
+ const n = Number(val);
43
+ if (!isNaN(n)) return n.toLocaleString();
44
+ break;
45
+ }
46
+ case 'percentage': {
47
+ const n = Number(val);
48
+ if (!isNaN(n)) return `${(n * 100).toFixed(1)}%`;
49
+ break;
50
+ }
51
+ case 'date': {
52
+ const d = val instanceof Date ? val : new Date(String(val));
53
+ if (!isNaN(d.getTime())) return d.toLocaleDateString();
54
+ break;
55
+ }
56
+ case 'datetime': {
57
+ const d = val instanceof Date ? val : new Date(String(val));
58
+ if (!isNaN(d.getTime())) return d.toLocaleString();
59
+ break;
60
+ }
61
+ }
62
+ return String(val);
63
+ }
64
+
65
+ // Status chip logic — keyed on common English status words
66
+ const STATUS_MAP: Record<string, 'success' | 'warning' | 'error' | 'neutral'> = {
67
+ active: 'success',
68
+ enabled: 'success',
69
+ approved: 'success',
70
+ confirmed: 'success',
71
+ completed: 'success',
72
+ done: 'success',
73
+ live: 'success',
74
+ pending: 'warning',
75
+ review: 'warning',
76
+ draft: 'warning',
77
+ in_progress: 'warning',
78
+ processing: 'warning',
79
+ queued: 'warning',
80
+ inactive: 'error',
81
+ disabled: 'error',
82
+ cancelled: 'error',
83
+ rejected: 'error',
84
+ failed: 'error',
85
+ error: 'error',
86
+ blocked: 'error',
87
+ archived: 'neutral',
88
+ closed: 'neutral',
89
+ deprecated: 'neutral',
90
+ };
91
+
92
+ function isStatusCol(col: CardGridColumn): boolean {
93
+ const id = col.id.toLowerCase();
94
+ return id.includes('status') || id.includes('state') || id === 'type';
95
+ }
96
+
97
+ function statusVariant(val: unknown): 'success' | 'warning' | 'error' | 'neutral' | null {
98
+ if (val == null) return null;
99
+ return STATUS_MAP[String(val).toLowerCase().replace(/[\s-]/g, '_')] ?? null;
100
+ }
101
+ </script>
102
+
103
+ <article class="dc-card" class:dc-selected={selected} class:dc-focused={focused}>
104
+ <!-- Header -->
105
+ {#if titleCol}
106
+ {@const titleKey = titleCol.dataKey ?? titleCol.id}
107
+ {@const titleVal = getVal(titleKey, record)}
108
+ <div class="dc-header">
109
+ <p class="dc-title">{titleVal ?? '—'}</p>
110
+ {#if subtitleCol}
111
+ {@const subKey = subtitleCol.dataKey ?? subtitleCol.id}
112
+ {@const subVal = getVal(subKey, record)}
113
+ <p class="dc-subtitle">{formatVal(subVal, subtitleCol)}</p>
114
+ {/if}
115
+ </div>
116
+ {/if}
117
+
118
+ <!-- Detail rows -->
119
+ {#if detailCols.length > 0}
120
+ <div class="dc-divider"></div>
121
+ <dl class="dc-fields">
122
+ {#each detailCols as col (col.id)}
123
+ {@const key = col.dataKey ?? col.id}
124
+ {@const raw = getVal(key, record)}
125
+ {@const isChip = isStatusCol(col)}
126
+ {@const chip = isChip ? statusVariant(raw) : null}
127
+ <div class="dc-field">
128
+ <dt class="dc-label">{col.title}</dt>
129
+ <dd class="dc-value">
130
+ {#if chip}
131
+ <span class="dc-chip dc-chip-{chip}">{raw ?? '—'}</span>
132
+ {:else}
133
+ {formatVal(raw, col)}
134
+ {/if}
135
+ </dd>
136
+ </div>
137
+ {/each}
138
+ </dl>
139
+ {/if}
140
+ </article>
141
+
142
+ <style>
143
+ .dc-card {
144
+ padding: 0;
145
+ font-size: 0.875rem;
146
+ height: 100%;
147
+ display: flex;
148
+ flex-direction: column;
149
+ }
150
+
151
+ /* ── Header ───────────────────────────────────────────────────────── */
152
+
153
+ .dc-header {
154
+ padding: 14px 16px 12px;
155
+ display: flex;
156
+ flex-direction: column;
157
+ gap: 3px;
158
+ }
159
+
160
+ .dc-title {
161
+ font-size: 0.9375rem;
162
+ font-weight: 600;
163
+ color: var(--color-surface-900, #1e293b);
164
+ line-height: 1.3;
165
+ margin: 0;
166
+ white-space: nowrap;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ }
170
+
171
+ :global(.dark) .dc-title {
172
+ color: var(--color-surface-50, #f8fafc);
173
+ }
174
+
175
+ .dc-subtitle {
176
+ font-size: 0.8rem;
177
+ color: var(--color-surface-500, #64748b);
178
+ margin: 0;
179
+ white-space: nowrap;
180
+ overflow: hidden;
181
+ text-overflow: ellipsis;
182
+ }
183
+
184
+ :global(.dark) .dc-subtitle {
185
+ color: var(--color-surface-400, #94a3b8);
186
+ }
187
+
188
+ /* ── Divider ──────────────────────────────────────────────────────── */
189
+
190
+ .dc-divider {
191
+ height: 1px;
192
+ background: var(--cg-border-subtle, #f4f6f9);
193
+ margin: 0 16px;
194
+ }
195
+
196
+ :global(.dark) .dc-divider {
197
+ background: var(--cg-border, var(--color-surface-700, #334155));
198
+ }
199
+
200
+ /* ── Fields grid ──────────────────────────────────────────────────── */
201
+
202
+ .dc-fields {
203
+ padding: 10px 16px 14px;
204
+ display: flex;
205
+ flex-direction: column;
206
+ gap: 5px;
207
+ margin: 0;
208
+ flex: 1;
209
+ }
210
+
211
+ .dc-field {
212
+ display: grid;
213
+ grid-template-columns: minmax(60px, 38%) 1fr;
214
+ gap: 8px;
215
+ align-items: baseline;
216
+ }
217
+
218
+ .dc-label {
219
+ font-size: 0.75rem;
220
+ color: var(--color-surface-400, #94a3b8);
221
+ white-space: nowrap;
222
+ overflow: hidden;
223
+ text-overflow: ellipsis;
224
+ }
225
+
226
+ :global(.dark) .dc-label {
227
+ color: var(--color-surface-500, #64748b);
228
+ }
229
+
230
+ .dc-value {
231
+ font-size: 0.8125rem;
232
+ font-weight: 500;
233
+ color: var(--color-surface-800, #1e293b);
234
+ text-align: right;
235
+ word-break: break-word;
236
+ min-width: 0;
237
+ margin: 0;
238
+ }
239
+
240
+ :global(.dark) .dc-value {
241
+ color: var(--color-surface-100, #f1f5f9);
242
+ }
243
+
244
+ /* ── Status chips ─────────────────────────────────────────────────── */
245
+
246
+ .dc-chip {
247
+ display: inline-flex;
248
+ align-items: center;
249
+ gap: 4px;
250
+ padding: 1px 7px;
251
+ border-radius: 999px;
252
+ font-size: 0.72rem;
253
+ font-weight: 600;
254
+ letter-spacing: 0.01em;
255
+ text-transform: capitalize;
256
+ }
257
+
258
+ .dc-chip::before {
259
+ content: '';
260
+ display: inline-block;
261
+ width: 5px;
262
+ height: 5px;
263
+ border-radius: 50%;
264
+ background: currentColor;
265
+ flex-shrink: 0;
266
+ }
267
+
268
+ .dc-chip-success {
269
+ background: var(--color-success-100, #dcfce7);
270
+ color: var(--color-success-700, #15803d);
271
+ }
272
+ :global(.dark) .dc-chip-success {
273
+ background: color-mix(in oklab, var(--color-success-700, #15803d) 20%, transparent);
274
+ color: var(--color-success-400, #4ade80);
275
+ }
276
+
277
+ .dc-chip-warning {
278
+ background: var(--color-warning-100, #fef9c3);
279
+ color: var(--color-warning-700, #a16207);
280
+ }
281
+ :global(.dark) .dc-chip-warning {
282
+ background: color-mix(in oklab, var(--color-warning-700, #a16207) 20%, transparent);
283
+ color: var(--color-warning-400, #facc15);
284
+ }
285
+
286
+ .dc-chip-error {
287
+ background: var(--color-error-100, #fee2e2);
288
+ color: var(--color-error-700, #b91c1c);
289
+ }
290
+ :global(.dark) .dc-chip-error {
291
+ background: color-mix(in oklab, var(--color-error-700, #b91c1c) 20%, transparent);
292
+ color: var(--color-error-400, #f87171);
293
+ }
294
+
295
+ .dc-chip-neutral {
296
+ background: var(--color-surface-100, #f1f5f9);
297
+ color: var(--color-surface-600, #475569);
298
+ }
299
+ :global(.dark) .dc-chip-neutral {
300
+ background: var(--color-surface-700, #334155);
301
+ color: var(--color-surface-300, #94a3b8);
302
+ }
303
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { CardGridColumn } from './cardGrid.js';
2
+ interface Props {
3
+ record: Record<string, unknown>;
4
+ columns: CardGridColumn[];
5
+ selected: boolean;
6
+ focused: boolean;
7
+ }
8
+ declare const DefaultCard: import("svelte").Component<Props, {}, "">;
9
+ type DefaultCard = ReturnType<typeof DefaultCard>;
10
+ export default DefaultCard;