@shotleybuilder/svelte-gridlite-kit 0.1.0

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.
Files changed (43) hide show
  1. package/README.md +260 -0
  2. package/dist/GridLite.svelte +1361 -0
  3. package/dist/GridLite.svelte.d.ts +42 -0
  4. package/dist/components/CellContextMenu.svelte +209 -0
  5. package/dist/components/CellContextMenu.svelte.d.ts +28 -0
  6. package/dist/components/ColumnMenu.svelte +234 -0
  7. package/dist/components/ColumnMenu.svelte.d.ts +29 -0
  8. package/dist/components/ColumnPicker.svelte +403 -0
  9. package/dist/components/ColumnPicker.svelte.d.ts +29 -0
  10. package/dist/components/FilterBar.svelte +390 -0
  11. package/dist/components/FilterBar.svelte.d.ts +38 -0
  12. package/dist/components/FilterCondition.svelte +643 -0
  13. package/dist/components/FilterCondition.svelte.d.ts +35 -0
  14. package/dist/components/GroupBar.svelte +463 -0
  15. package/dist/components/GroupBar.svelte.d.ts +33 -0
  16. package/dist/components/RowDetailModal.svelte +213 -0
  17. package/dist/components/RowDetailModal.svelte.d.ts +25 -0
  18. package/dist/components/SortBar.svelte +232 -0
  19. package/dist/components/SortBar.svelte.d.ts +30 -0
  20. package/dist/components/SortCondition.svelte +129 -0
  21. package/dist/components/SortCondition.svelte.d.ts +30 -0
  22. package/dist/index.d.ts +23 -0
  23. package/dist/index.js +29 -0
  24. package/dist/query/builder.d.ts +160 -0
  25. package/dist/query/builder.js +432 -0
  26. package/dist/query/live.d.ts +50 -0
  27. package/dist/query/live.js +118 -0
  28. package/dist/query/schema.d.ts +30 -0
  29. package/dist/query/schema.js +75 -0
  30. package/dist/state/migrations.d.ts +29 -0
  31. package/dist/state/migrations.js +113 -0
  32. package/dist/state/views.d.ts +54 -0
  33. package/dist/state/views.js +130 -0
  34. package/dist/styles/gridlite.css +966 -0
  35. package/dist/types.d.ts +164 -0
  36. package/dist/types.js +2 -0
  37. package/dist/utils/filters.d.ts +14 -0
  38. package/dist/utils/filters.js +49 -0
  39. package/dist/utils/formatters.d.ts +16 -0
  40. package/dist/utils/formatters.js +39 -0
  41. package/dist/utils/fuzzy.d.ts +47 -0
  42. package/dist/utils/fuzzy.js +142 -0
  43. package/package.json +76 -0
@@ -0,0 +1,643 @@
1
+ <script>import { fuzzyMatch, highlightMatches } from "../utils/fuzzy.js";
2
+ import { getOperatorsForType } from "../utils/filters.js";
3
+ import { onMount, tick } from "svelte";
4
+ export let condition;
5
+ export let columns;
6
+ export let columnConfigs = [];
7
+ export let columnValues = [];
8
+ export let numericRange = null;
9
+ export let onUpdate;
10
+ export let onRemove;
11
+ let searchTerm = "";
12
+ let showDropdown = false;
13
+ let highlightedIndex = 0;
14
+ let searchInputRef;
15
+ let dropdownRef;
16
+ let showValueSuggestions = false;
17
+ let valueSuggestionIndex = 0;
18
+ let valueInputRef;
19
+ let valueSuggestionsRef;
20
+ onMount(() => {
21
+ function handleClickOutside(event) {
22
+ if (dropdownRef && !dropdownRef.contains(event.target)) {
23
+ showDropdown = false;
24
+ }
25
+ if (valueSuggestionsRef && !valueSuggestionsRef.contains(event.target)) {
26
+ showValueSuggestions = false;
27
+ }
28
+ }
29
+ document.addEventListener("click", handleClickOutside);
30
+ return () => document.removeEventListener("click", handleClickOutside);
31
+ });
32
+ function getColumnLabel(col) {
33
+ const cfg = columnConfigs.find((c) => c.name === col.name);
34
+ return cfg?.label ?? col.name;
35
+ }
36
+ function getColumnDataType(col) {
37
+ const cfg = columnConfigs.find((c) => c.name === col.name);
38
+ return cfg?.dataType ?? col.dataType;
39
+ }
40
+ $: selectedColumn = condition.field ? columns.find((c) => c.name === condition.field) : null;
41
+ $: selectedColumnLabel = (() => {
42
+ if (!condition.field) return "";
43
+ return selectedColumn ? getColumnLabel(selectedColumn) : condition.field;
44
+ })();
45
+ $: columnDataType = (() => {
46
+ if (!selectedColumn) return "text";
47
+ return getColumnDataType(selectedColumn);
48
+ })();
49
+ $: selectOptions = (() => {
50
+ if (!selectedColumn) return [];
51
+ const cfg = columnConfigs.find((c) => c.name === selectedColumn.name);
52
+ return cfg?.selectOptions ?? [];
53
+ })();
54
+ $: operatorOptions = getOperatorsForType(columnDataType);
55
+ $: {
56
+ if (condition.field && operatorOptions.length > 0) {
57
+ const currentOperatorValid = operatorOptions.some((op) => op.value === condition.operator);
58
+ if (!currentOperatorValid) {
59
+ onUpdate({ ...condition, operator: "equals" });
60
+ }
61
+ }
62
+ }
63
+ $: valueDisabled = condition.operator === "is_empty" || condition.operator === "is_not_empty";
64
+ $: filteredColumns = (() => {
65
+ if (!searchTerm.trim()) {
66
+ return columns.map((col) => ({
67
+ column: col,
68
+ matchedIndices: [],
69
+ score: 0
70
+ }));
71
+ }
72
+ const results = [];
73
+ for (const col of columns) {
74
+ const label = getColumnLabel(col);
75
+ const match = fuzzyMatch(searchTerm, label);
76
+ if (match) {
77
+ results.push({ column: col, matchedIndices: match.matchedIndices, score: match.score });
78
+ }
79
+ }
80
+ return results.sort((a, b) => b.score - a.score);
81
+ })();
82
+ $: if (filteredColumns) {
83
+ highlightedIndex = 0;
84
+ }
85
+ $: canShowSuggestions = columnValues.length > 0 && !valueDisabled;
86
+ $: filteredValueSuggestions = (() => {
87
+ if (!columnValues || columnValues.length === 0) return [];
88
+ const currentValue = String(condition.value || "");
89
+ if (!currentValue.trim()) {
90
+ return columnValues.slice(0, 50).map((val) => ({
91
+ value: val,
92
+ matchedIndices: [],
93
+ score: 0
94
+ }));
95
+ }
96
+ const results = [];
97
+ for (const val of columnValues) {
98
+ const match = fuzzyMatch(currentValue, val);
99
+ if (match) {
100
+ results.push({ value: val, matchedIndices: match.matchedIndices, score: match.score });
101
+ }
102
+ }
103
+ return results.sort((a, b) => b.score - a.score).slice(0, 50);
104
+ })();
105
+ $: if (filteredValueSuggestions) {
106
+ valueSuggestionIndex = 0;
107
+ }
108
+ function selectColumn(col) {
109
+ onUpdate({ ...condition, field: col.name });
110
+ showDropdown = false;
111
+ searchTerm = "";
112
+ }
113
+ function openDropdown() {
114
+ showDropdown = true;
115
+ searchTerm = "";
116
+ highlightedIndex = 0;
117
+ tick().then(() => {
118
+ searchInputRef?.focus();
119
+ });
120
+ }
121
+ function handleSearchKeydown(event) {
122
+ switch (event.key) {
123
+ case "ArrowDown":
124
+ event.preventDefault();
125
+ highlightedIndex = Math.min(highlightedIndex + 1, filteredColumns.length - 1);
126
+ scrollToHighlighted();
127
+ break;
128
+ case "ArrowUp":
129
+ event.preventDefault();
130
+ highlightedIndex = Math.max(highlightedIndex - 1, 0);
131
+ scrollToHighlighted();
132
+ break;
133
+ case "Enter":
134
+ event.preventDefault();
135
+ if (filteredColumns[highlightedIndex]) {
136
+ selectColumn(filteredColumns[highlightedIndex].column);
137
+ }
138
+ break;
139
+ case "Escape":
140
+ event.preventDefault();
141
+ showDropdown = false;
142
+ searchTerm = "";
143
+ break;
144
+ case "Tab":
145
+ showDropdown = false;
146
+ break;
147
+ }
148
+ }
149
+ async function scrollToHighlighted() {
150
+ await tick();
151
+ const highlighted = dropdownRef?.querySelector(".field-option.highlighted");
152
+ if (highlighted) {
153
+ highlighted.scrollIntoView({ block: "nearest" });
154
+ }
155
+ }
156
+ function handleOperatorChange(event) {
157
+ const operator = event.target.value;
158
+ onUpdate({ ...condition, operator });
159
+ }
160
+ function handleValueChange(event) {
161
+ const value = event.target.value;
162
+ onUpdate({ ...condition, value });
163
+ if (canShowSuggestions) {
164
+ showValueSuggestions = true;
165
+ }
166
+ }
167
+ function handleValueFocus() {
168
+ if (canShowSuggestions) {
169
+ showValueSuggestions = true;
170
+ valueSuggestionIndex = 0;
171
+ }
172
+ }
173
+ function selectValueSuggestion(value) {
174
+ onUpdate({ ...condition, value });
175
+ showValueSuggestions = false;
176
+ }
177
+ function handleValueKeydown(event) {
178
+ if (!showValueSuggestions || filteredValueSuggestions.length === 0) return;
179
+ switch (event.key) {
180
+ case "ArrowDown":
181
+ event.preventDefault();
182
+ valueSuggestionIndex = Math.min(
183
+ valueSuggestionIndex + 1,
184
+ filteredValueSuggestions.length - 1
185
+ );
186
+ scrollToHighlightedSuggestion();
187
+ break;
188
+ case "ArrowUp":
189
+ event.preventDefault();
190
+ valueSuggestionIndex = Math.max(valueSuggestionIndex - 1, 0);
191
+ scrollToHighlightedSuggestion();
192
+ break;
193
+ case "Enter":
194
+ event.preventDefault();
195
+ if (filteredValueSuggestions[valueSuggestionIndex]) {
196
+ selectValueSuggestion(filteredValueSuggestions[valueSuggestionIndex].value);
197
+ }
198
+ break;
199
+ case "Escape":
200
+ event.preventDefault();
201
+ showValueSuggestions = false;
202
+ break;
203
+ case "Tab":
204
+ showValueSuggestions = false;
205
+ break;
206
+ }
207
+ }
208
+ async function scrollToHighlightedSuggestion() {
209
+ await tick();
210
+ const highlighted = valueSuggestionsRef?.querySelector(".suggestion-option.highlighted");
211
+ if (highlighted) {
212
+ highlighted.scrollIntoView({ block: "nearest" });
213
+ }
214
+ }
215
+ </script>
216
+
217
+ <div class="filter-condition">
218
+ <div class="field-picker-wrapper" bind:this={dropdownRef}>
219
+ <button
220
+ class="field-picker-trigger"
221
+ class:has-value={condition.field}
222
+ on:click={openDropdown}
223
+ type="button"
224
+ >
225
+ <span class="field-picker-text">
226
+ {selectedColumnLabel || 'Select field...'}
227
+ </span>
228
+ <svg class="chevron-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
229
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
230
+ </svg>
231
+ </button>
232
+
233
+ {#if showDropdown}
234
+ <div class="field-dropdown">
235
+ <div class="field-search-wrapper">
236
+ <input
237
+ bind:this={searchInputRef}
238
+ type="text"
239
+ class="field-search"
240
+ placeholder="Search fields..."
241
+ bind:value={searchTerm}
242
+ on:keydown={handleSearchKeydown}
243
+ />
244
+ </div>
245
+
246
+ <div class="field-options">
247
+ {#each filteredColumns as { column, matchedIndices }, i}
248
+ {@const label = getColumnLabel(column)}
249
+ <button
250
+ class="field-option"
251
+ class:highlighted={i === highlightedIndex}
252
+ class:selected={column.name === condition.field}
253
+ on:click={() => selectColumn(column)}
254
+ on:mouseenter={() => (highlightedIndex = i)}
255
+ type="button"
256
+ >
257
+ {#if matchedIndices.length > 0}
258
+ {#each highlightMatches(label, matchedIndices) as segment}
259
+ {#if segment.isMatch}
260
+ <mark class="match-highlight">{segment.text}</mark>
261
+ {:else}
262
+ {segment.text}
263
+ {/if}
264
+ {/each}
265
+ {:else}
266
+ {label}
267
+ {/if}
268
+ </button>
269
+ {:else}
270
+ <div class="no-results">No matching fields</div>
271
+ {/each}
272
+ </div>
273
+ </div>
274
+ {/if}
275
+ </div>
276
+
277
+ <select class="operator-select" value={condition.operator} on:change={handleOperatorChange}>
278
+ {#each operatorOptions as option}
279
+ <option value={option.value}>{option.label}</option>
280
+ {/each}
281
+ </select>
282
+
283
+ <div class="value-input-wrapper" bind:this={valueSuggestionsRef}>
284
+ {#if columnDataType === 'boolean'}
285
+ <select
286
+ class="value-input"
287
+ value={condition.value || ''}
288
+ on:change={handleValueChange}
289
+ disabled={valueDisabled}
290
+ >
291
+ <option value="">Select...</option>
292
+ <option value="true">True</option>
293
+ <option value="false">False</option>
294
+ </select>
295
+ {:else if columnDataType === 'select' && selectOptions.length > 0}
296
+ <select
297
+ class="value-input"
298
+ value={condition.value || ''}
299
+ on:change={handleValueChange}
300
+ disabled={valueDisabled}
301
+ >
302
+ <option value="">Select...</option>
303
+ {#each selectOptions as opt}
304
+ <option value={opt.value}>{opt.label}</option>
305
+ {/each}
306
+ </select>
307
+ {:else if columnDataType === 'date'}
308
+ <input
309
+ bind:this={valueInputRef}
310
+ type="date"
311
+ class="value-input"
312
+ value={condition.value || ''}
313
+ on:input={handleValueChange}
314
+ disabled={valueDisabled}
315
+ />
316
+ {:else if columnDataType === 'number'}
317
+ <input
318
+ bind:this={valueInputRef}
319
+ type="number"
320
+ class="value-input"
321
+ value={condition.value || ''}
322
+ on:input={handleValueChange}
323
+ disabled={valueDisabled}
324
+ placeholder={valueDisabled ? 'N/A' : numericRange ? `${numericRange.min} - ${numericRange.max}` : 'Enter number...'}
325
+ />
326
+ {#if numericRange && !valueDisabled}
327
+ <div class="numeric-range-hint">
328
+ Range: {numericRange.min} - {numericRange.max}
329
+ </div>
330
+ {/if}
331
+ {:else}
332
+ <input
333
+ bind:this={valueInputRef}
334
+ type="text"
335
+ class="value-input"
336
+ value={condition.value || ''}
337
+ on:input={handleValueChange}
338
+ on:focus={handleValueFocus}
339
+ on:keydown={handleValueKeydown}
340
+ disabled={valueDisabled}
341
+ placeholder={valueDisabled ? 'N/A' : 'Enter value...'}
342
+ autocomplete="off"
343
+ />
344
+
345
+ {#if showValueSuggestions && filteredValueSuggestions.length > 0}
346
+ <div class="value-suggestions">
347
+ {#each filteredValueSuggestions as { value, matchedIndices }, i}
348
+ <button
349
+ class="suggestion-option"
350
+ class:highlighted={i === valueSuggestionIndex}
351
+ on:click={() => selectValueSuggestion(value)}
352
+ on:mouseenter={() => (valueSuggestionIndex = i)}
353
+ type="button"
354
+ >
355
+ {#if matchedIndices.length > 0}
356
+ {#each highlightMatches(value, matchedIndices) as segment}
357
+ {#if segment.isMatch}
358
+ <mark class="match-highlight">{segment.text}</mark>
359
+ {:else}
360
+ {segment.text}
361
+ {/if}
362
+ {/each}
363
+ {:else}
364
+ {value}
365
+ {/if}
366
+ </button>
367
+ {/each}
368
+ {#if columnValues.length > 50}
369
+ <div class="suggestions-overflow">
370
+ and {columnValues.length - 50} more...
371
+ </div>
372
+ {/if}
373
+ </div>
374
+ {/if}
375
+ {/if}
376
+ </div>
377
+
378
+ <button class="remove-btn" on:click={onRemove} title="Remove condition" type="button">
379
+ <svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
380
+ <path
381
+ stroke-linecap="round"
382
+ stroke-linejoin="round"
383
+ stroke-width="2"
384
+ d="M6 18L18 6M6 6l12 12"
385
+ />
386
+ </svg>
387
+ </button>
388
+ </div>
389
+
390
+ <style>
391
+ .filter-condition {
392
+ display: flex;
393
+ gap: 0.5rem;
394
+ align-items: center;
395
+ padding: 0.5rem;
396
+ background: #f9fafb;
397
+ border-radius: 0.375rem;
398
+ }
399
+
400
+ .field-picker-wrapper {
401
+ position: relative;
402
+ flex: 1;
403
+ min-width: 150px;
404
+ }
405
+
406
+ .field-picker-trigger {
407
+ display: flex;
408
+ align-items: center;
409
+ justify-content: space-between;
410
+ width: 100%;
411
+ padding: 0.375rem 0.75rem;
412
+ font-size: 0.875rem;
413
+ text-align: left;
414
+ border: 1px solid #d1d5db;
415
+ border-radius: 0.375rem;
416
+ background: white;
417
+ cursor: pointer;
418
+ transition: border-color 0.15s;
419
+ }
420
+
421
+ .field-picker-trigger:hover {
422
+ border-color: #9ca3af;
423
+ }
424
+
425
+ .field-picker-trigger:focus {
426
+ outline: none;
427
+ border-color: #3b82f6;
428
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
429
+ }
430
+
431
+ .field-picker-trigger:not(.has-value) .field-picker-text {
432
+ color: #9ca3af;
433
+ }
434
+
435
+ .field-picker-text {
436
+ flex: 1;
437
+ overflow: hidden;
438
+ text-overflow: ellipsis;
439
+ white-space: nowrap;
440
+ }
441
+
442
+ .chevron-icon {
443
+ width: 1rem;
444
+ height: 1rem;
445
+ color: #6b7280;
446
+ flex-shrink: 0;
447
+ }
448
+
449
+ .field-dropdown {
450
+ position: absolute;
451
+ top: calc(100% + 4px);
452
+ left: 0;
453
+ width: 100%;
454
+ min-width: 200px;
455
+ background: white;
456
+ border: 1px solid #d1d5db;
457
+ border-radius: 0.375rem;
458
+ box-shadow:
459
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
460
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
461
+ z-index: 50;
462
+ overflow: hidden;
463
+ }
464
+
465
+ .field-search-wrapper {
466
+ display: flex;
467
+ align-items: center;
468
+ gap: 0.25rem;
469
+ padding: 0.5rem;
470
+ border-bottom: 1px solid #e5e7eb;
471
+ }
472
+
473
+ .field-search {
474
+ flex: 1;
475
+ padding: 0.375rem 0.5rem;
476
+ font-size: 0.875rem;
477
+ border: 1px solid #d1d5db;
478
+ border-radius: 0.25rem;
479
+ outline: none;
480
+ }
481
+
482
+ .field-search:focus {
483
+ border-color: #3b82f6;
484
+ box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
485
+ }
486
+
487
+ .field-options {
488
+ max-height: 200px;
489
+ overflow-y: auto;
490
+ }
491
+
492
+ .field-option {
493
+ display: block;
494
+ width: 100%;
495
+ padding: 0.5rem 0.75rem;
496
+ font-size: 0.875rem;
497
+ text-align: left;
498
+ background: none;
499
+ border: none;
500
+ cursor: pointer;
501
+ transition: background-color 0.1s;
502
+ }
503
+
504
+ .field-option:hover,
505
+ .field-option.highlighted {
506
+ background: #f3f4f6;
507
+ }
508
+
509
+ .field-option.selected {
510
+ background: #eff6ff;
511
+ color: #1d4ed8;
512
+ }
513
+
514
+ .field-option.highlighted.selected {
515
+ background: #dbeafe;
516
+ }
517
+
518
+ .match-highlight {
519
+ background: #fef08a;
520
+ color: inherit;
521
+ padding: 0;
522
+ border-radius: 1px;
523
+ }
524
+
525
+ .no-results {
526
+ padding: 0.75rem;
527
+ text-align: center;
528
+ color: #6b7280;
529
+ font-size: 0.875rem;
530
+ }
531
+
532
+ .operator-select,
533
+ .value-input {
534
+ padding: 0.375rem 0.75rem;
535
+ font-size: 0.875rem;
536
+ border: 1px solid #d1d5db;
537
+ border-radius: 0.375rem;
538
+ background: white;
539
+ }
540
+
541
+ .operator-select {
542
+ flex: 0.8;
543
+ min-width: 100px;
544
+ }
545
+
546
+ .value-input-wrapper {
547
+ position: relative;
548
+ flex: 1;
549
+ min-width: 120px;
550
+ }
551
+
552
+ .value-input-wrapper .value-input {
553
+ width: 100%;
554
+ }
555
+
556
+ .value-input {
557
+ flex: 1;
558
+ min-width: 120px;
559
+ }
560
+
561
+ .value-input:disabled {
562
+ background: #f3f4f6;
563
+ color: #9ca3af;
564
+ cursor: not-allowed;
565
+ }
566
+
567
+ .value-suggestions {
568
+ position: absolute;
569
+ top: calc(100% + 4px);
570
+ left: 0;
571
+ right: 0;
572
+ max-height: 200px;
573
+ overflow-y: auto;
574
+ background: white;
575
+ border: 1px solid #d1d5db;
576
+ border-radius: 0.375rem;
577
+ box-shadow:
578
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
579
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
580
+ z-index: 50;
581
+ }
582
+
583
+ .suggestion-option {
584
+ display: block;
585
+ width: 100%;
586
+ padding: 0.5rem 0.75rem;
587
+ font-size: 0.875rem;
588
+ text-align: left;
589
+ background: none;
590
+ border: none;
591
+ cursor: pointer;
592
+ transition: background-color 0.1s;
593
+ }
594
+
595
+ .suggestion-option:hover,
596
+ .suggestion-option.highlighted {
597
+ background: #f3f4f6;
598
+ }
599
+
600
+ .suggestions-overflow {
601
+ padding: 0.5rem 0.75rem;
602
+ font-size: 0.75rem;
603
+ color: #6b7280;
604
+ text-align: center;
605
+ border-top: 1px solid #e5e7eb;
606
+ background: #f9fafb;
607
+ }
608
+
609
+ .numeric-range-hint {
610
+ position: absolute;
611
+ top: calc(100% + 4px);
612
+ left: 0;
613
+ right: 0;
614
+ padding: 0.375rem 0.75rem;
615
+ font-size: 0.75rem;
616
+ color: #6b7280;
617
+ background: #f9fafb;
618
+ border: 1px solid #e5e7eb;
619
+ border-radius: 0.375rem;
620
+ text-align: center;
621
+ }
622
+
623
+ .remove-btn {
624
+ flex-shrink: 0;
625
+ padding: 0.375rem;
626
+ background: none;
627
+ border: none;
628
+ color: #6b7280;
629
+ cursor: pointer;
630
+ border-radius: 0.25rem;
631
+ transition: all 0.2s;
632
+ }
633
+
634
+ .remove-btn:hover {
635
+ background: #fee2e2;
636
+ color: #dc2626;
637
+ }
638
+
639
+ .icon {
640
+ width: 1rem;
641
+ height: 1rem;
642
+ }
643
+ </style>
@@ -0,0 +1,35 @@
1
+ import { SvelteComponent } from "svelte";
2
+ /**
3
+ * FilterCondition — Individual filter row with column picker, operator dropdown, value input.
4
+ *
5
+ * PGLite-native: uses ColumnMetadata instead of TanStack ColumnDef.
6
+ * Value suggestions and numeric ranges are provided by the parent FilterBar
7
+ * (which fetches them via SELECT DISTINCT / MIN/MAX SQL queries).
8
+ */
9
+ import type { FilterCondition, ColumnMetadata, ColumnConfig } from '../types.js';
10
+ declare const __propDef: {
11
+ props: {
12
+ condition: FilterCondition;
13
+ columns: ColumnMetadata[];
14
+ columnConfigs?: ColumnConfig[];
15
+ columnValues?: string[];
16
+ numericRange?: {
17
+ min: number;
18
+ max: number;
19
+ } | null;
20
+ onUpdate: (condition: FilterCondition) => void;
21
+ onRemove: () => void;
22
+ };
23
+ events: {
24
+ [evt: string]: CustomEvent<any>;
25
+ };
26
+ slots: {};
27
+ exports?: {} | undefined;
28
+ bindings?: string | undefined;
29
+ };
30
+ export type FilterConditionProps = typeof __propDef.props;
31
+ export type FilterConditionEvents = typeof __propDef.events;
32
+ export type FilterConditionSlots = typeof __propDef.slots;
33
+ export default class FilterCondition extends SvelteComponent<FilterConditionProps, FilterConditionEvents, FilterConditionSlots> {
34
+ }
35
+ export {};