@viniaraujo68/plinth 0.3.1 → 0.5.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 (103) hide show
  1. package/README.md +189 -19
  2. package/dist/components/ErrorDisplay.svelte +30 -16
  3. package/dist/components/ErrorDisplay.svelte.d.ts +4 -0
  4. package/dist/components/JsonView.svelte +43 -0
  5. package/dist/components/JsonView.svelte.d.ts +4 -0
  6. package/dist/components/JsonViewFrame.svelte +654 -0
  7. package/dist/components/JsonViewFrame.svelte.d.ts +31 -0
  8. package/dist/components/Paginator.svelte +34 -8
  9. package/dist/components/Paginator.svelte.d.ts +10 -0
  10. package/dist/components/RequestErrorDisplay.svelte +43 -0
  11. package/dist/components/RequestErrorDisplay.svelte.d.ts +11 -0
  12. package/dist/components/Tabs.svelte +204 -0
  13. package/dist/components/Tabs.svelte.d.ts +76 -0
  14. package/dist/components/VirtualJsonView.svelte +67 -0
  15. package/dist/components/VirtualJsonView.svelte.d.ts +4 -0
  16. package/dist/components/index.d.ts +8 -1
  17. package/dist/components/index.js +11 -5
  18. package/dist/components/json-view.d.ts +70 -0
  19. package/dist/components/json-view.js +302 -0
  20. package/dist/components/request-error.d.ts +8 -0
  21. package/dist/components/request-error.js +55 -0
  22. package/dist/components/tabs.d.ts +5 -0
  23. package/dist/components/tabs.js +1 -0
  24. package/dist/http.d.ts +10 -5
  25. package/dist/http.js +34 -6
  26. package/dist/i18n/LocaleToggle.svelte +45 -0
  27. package/dist/i18n/LocaleToggle.svelte.d.ts +48 -0
  28. package/dist/i18n/i18n.svelte.d.ts +56 -0
  29. package/dist/i18n/i18n.svelte.js +94 -0
  30. package/dist/i18n/index.d.ts +3 -0
  31. package/dist/i18n/index.js +7 -0
  32. package/dist/i18n/translate.d.ts +30 -0
  33. package/dist/i18n/translate.js +38 -0
  34. package/dist/index.d.ts +1 -1
  35. package/dist/index.js +1 -1
  36. package/dist/redirect.d.ts +40 -0
  37. package/dist/redirect.js +59 -0
  38. package/dist/routing.svelte.d.ts +1 -0
  39. package/dist/routing.svelte.js +3 -0
  40. package/dist/shell/AppShell.svelte +265 -93
  41. package/dist/shell/AppShell.svelte.d.ts +3 -2
  42. package/dist/shell/NavigationProgress.svelte +85 -0
  43. package/dist/shell/NavigationProgress.svelte.d.ts +31 -0
  44. package/dist/shell/TopBar.svelte +191 -0
  45. package/dist/shell/TopBar.svelte.d.ts +41 -0
  46. package/dist/shell/UserAvatar.svelte +50 -0
  47. package/dist/shell/UserAvatar.svelte.d.ts +14 -0
  48. package/dist/shell/index.d.ts +2 -0
  49. package/dist/shell/index.js +7 -3
  50. package/dist/shell/initials.d.ts +6 -0
  51. package/dist/shell/initials.js +13 -0
  52. package/dist/table/DataTable.svelte +199 -9
  53. package/dist/table/DataTable.svelte.d.ts +28 -5
  54. package/dist/table/FilterBar.svelte +417 -0
  55. package/dist/table/FilterBar.svelte.d.ts +34 -0
  56. package/dist/table/FilterRuleEditor.svelte +290 -0
  57. package/dist/table/FilterRuleEditor.svelte.d.ts +33 -0
  58. package/dist/table/filter-labels.d.ts +23 -0
  59. package/dist/table/filter-labels.js +30 -0
  60. package/dist/table/filter.d.ts +27 -0
  61. package/dist/table/filter.js +279 -0
  62. package/dist/table/index.d.ts +4 -1
  63. package/dist/table/index.js +5 -2
  64. package/dist/table/types.d.ts +49 -0
  65. package/dist/toast/Toaster.svelte +7 -3
  66. package/dist/toast/index.d.ts +1 -1
  67. package/dist/toast/toast-manager.svelte.d.ts +29 -1
  68. package/dist/toast/toast-manager.svelte.js +61 -1
  69. package/dist/url-state/codec.d.ts +15 -0
  70. package/dist/url-state/codec.js +1 -0
  71. package/dist/url-state/index.d.ts +5 -0
  72. package/dist/url-state/index.js +4 -0
  73. package/dist/url-state/params-codec.d.ts +73 -0
  74. package/dist/url-state/params-codec.js +116 -0
  75. package/dist/url-state/search-params.d.ts +4 -0
  76. package/dist/url-state/search-params.js +28 -0
  77. package/dist/url-state/synced-state.svelte.d.ts +20 -0
  78. package/dist/url-state/synced-state.svelte.js +88 -0
  79. package/dist/url-state/url-store.svelte.d.ts +12 -0
  80. package/dist/url-state/url-store.svelte.js +56 -0
  81. package/dist/virtual/DataList.svelte +215 -0
  82. package/dist/virtual/DataList.svelte.d.ts +52 -0
  83. package/dist/virtual/VirtualList.svelte +150 -0
  84. package/dist/virtual/VirtualList.svelte.d.ts +42 -0
  85. package/dist/virtual/index.d.ts +7 -0
  86. package/dist/virtual/index.js +6 -0
  87. package/dist/virtual/keyed-cache.d.ts +7 -0
  88. package/dist/virtual/keyed-cache.js +20 -0
  89. package/dist/virtual/labels.d.ts +12 -0
  90. package/dist/virtual/labels.js +6 -0
  91. package/dist/virtual/paging.d.ts +5 -0
  92. package/dist/virtual/paging.js +11 -0
  93. package/dist/virtual/range.d.ts +9 -0
  94. package/dist/virtual/range.js +31 -0
  95. package/dist/virtual/size-tree.d.ts +10 -0
  96. package/dist/virtual/size-tree.js +56 -0
  97. package/dist/virtual/virtualizer.svelte.d.ts +38 -0
  98. package/dist/virtual/virtualizer.svelte.js +295 -0
  99. package/dist/virtual/windowed-data.svelte.d.ts +38 -0
  100. package/dist/virtual/windowed-data.svelte.js +139 -0
  101. package/dist/virtual/windowed-virtualizer.svelte.d.ts +9 -0
  102. package/dist/virtual/windowed-virtualizer.svelte.js +22 -0
  103. package/package.json +13 -1
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from "svelte";
2
2
  import type { ClassValue } from "svelte/elements";
3
- import type { Column, ColumnState, SortState } from "./types.js";
3
+ import { type PaginatorLabels } from "../components/Paginator.svelte";
4
+ import type { FilterLabels } from "./filter-labels.js";
5
+ import type { Column, ColumnState, FilterGroup, SortState } from "./types.js";
4
6
  declare function $$render<T>(): {
5
7
  props: {
6
8
  rows: readonly T[];
@@ -80,9 +82,25 @@ declare function $$render<T>(): {
80
82
  moveColumnLabel?: (column: Column<T>, direction: "up" | "down") => string;
81
83
  /** Names a column's resize handle for a screen reader. */
82
84
  resizeLabel?: (column: Column<T>) => string;
85
+ filters?: FilterGroup;
86
+ filterBar?: boolean;
87
+ filterGroups?: boolean;
88
+ filterLabels?: Partial<FilterLabels>;
89
+ loading?: boolean;
90
+ loadingRows?: number;
91
+ loadingLabel?: string;
92
+ error?: unknown;
93
+ errorState?: Snippet<[unknown, (() => void) | undefined]>;
94
+ errorLabel?: string;
95
+ retryLabel?: string;
96
+ onRetry?: () => void;
97
+ pageSize?: number;
98
+ page?: number;
99
+ pageSizes?: number[];
100
+ paginatorLabels?: Partial<PaginatorLabels>;
83
101
  };
84
102
  exports: {};
85
- bindings: "sort" | "columnState";
103
+ bindings: "sort" | "page" | "pageSize" | "columnState" | "filters";
86
104
  slots: {};
87
105
  events: {};
88
106
  };
@@ -90,7 +108,7 @@ declare class __sveltets_Render<T> {
90
108
  props(): ReturnType<typeof $$render<T>>['props'];
91
109
  events(): ReturnType<typeof $$render<T>>['events'];
92
110
  slots(): ReturnType<typeof $$render<T>>['slots'];
93
- bindings(): "sort" | "columnState";
111
+ bindings(): "sort" | "page" | "pageSize" | "columnState" | "filters";
94
112
  exports(): {};
95
113
  }
96
114
  interface $$IsomorphicComponent {
@@ -133,8 +151,13 @@ interface $$IsomorphicComponent {
133
151
  * release neither loses a stored layout nor ends up somewhere nobody put it. Sorting by a column the
134
152
  * reader hid keeps working: the order is about the rows, not about what is on screen.
135
153
  *
136
- * It stays short of a data grid — no filtering, no virtualization, no saved views. A table that
137
- * needs those needs a different component.
154
+ * Columns that declare a `filter` get a chip bar in the table's bar, bound through `filters`; the
155
+ * rules are applied before the sort, and the same rules drive `filterRows` for a caller that filters
156
+ * outside the table. `pageSize` pages the filtered, sorted rows with a `Paginator` under the table,
157
+ * and the position handed to `cell` and `card` stays the row's place in the whole order.
158
+ *
159
+ * It stays short of a data grid — no virtualization, no saved views. A table that needs those needs a
160
+ * different component.
138
161
  *
139
162
  * ```svelte
140
163
  * <DataTable
@@ -0,0 +1,417 @@
1
+ <script lang="ts" generics="T">
2
+ import { tick } from "svelte";
3
+ import type { ClassValue } from "svelte/elements";
4
+ import Dropdown from "../components/Dropdown.svelte";
5
+ import { DEFAULT_FILTER_LABELS, type FilterLabels } from "./filter-labels.js";
6
+ import {
7
+ addNode,
8
+ emptyFilter,
9
+ filterableColumns,
10
+ isFilterEmpty,
11
+ isGroup,
12
+ isRuleActive,
13
+ removeNode,
14
+ replaceNode,
15
+ setCombinator,
16
+ type FilterableColumn,
17
+ type NodePath,
18
+ } from "./filter.js";
19
+ import FilterRuleEditor from "./FilterRuleEditor.svelte";
20
+ import type { Column, FilterCombinator, FilterGroup, FilterRule } from "./types.js";
21
+
22
+ interface Props {
23
+ columns: readonly Column<T>[];
24
+ filter?: FilterGroup;
25
+ onchange?: (filter: FilterGroup) => void;
26
+ groups?: boolean;
27
+ labels?: Partial<FilterLabels>;
28
+ class?: ClassValue;
29
+ }
30
+
31
+ let {
32
+ columns,
33
+ filter = $bindable(emptyFilter()),
34
+ onchange,
35
+ groups = true,
36
+ labels,
37
+ class: className,
38
+ }: Props = $props();
39
+
40
+ const text = $derived({ ...DEFAULT_FILTER_LABELS, ...labels });
41
+ const fields = $derived(filterableColumns(columns));
42
+ const byKey = $derived(new Map(fields.map((column) => [column.key, column])));
43
+ const hasRules = $derived(!isFilterEmpty(columns, filter));
44
+
45
+ const dropdowns: Record<string, ReturnType<typeof Dropdown> | undefined> = $state({});
46
+
47
+ const pathKey = (path: NodePath) => path.join(".");
48
+
49
+ const commit = (next: FilterGroup) => {
50
+ filter = next;
51
+ onchange?.(next);
52
+ };
53
+
54
+ const other = (combinator: FilterCombinator): FilterCombinator =>
55
+ combinator === "and" ? "or" : "and";
56
+
57
+ const add = (groupPath: NodePath, rule: FilterRule) => {
58
+ commit(addNode(filter, groupPath, rule));
59
+ dropdowns[`add:${pathKey(groupPath)}`]?.close();
60
+ };
61
+
62
+ const edit = (path: NodePath, rule: FilterRule) => {
63
+ commit(replaceNode(filter, path, rule));
64
+ dropdowns[`edit:${pathKey(path)}`]?.close();
65
+ };
66
+
67
+ const addGroup = async () => {
68
+ const path = [filter.children.length];
69
+ commit(addNode(filter, [], emptyFilter(other(filter.combinator))));
70
+ await tick();
71
+ dropdowns[`add:${pathKey(path)}`]?.open();
72
+ };
73
+
74
+ const valueText = (column: FilterableColumn<T>, rule: FilterRule): string => {
75
+ const columnFilter = column.filter;
76
+ if (Array.isArray(rule.value)) {
77
+ if (columnFilter.kind !== "choice") return rule.value.join(", ");
78
+ const labelOf = new Map(columnFilter.options.map((option) => [option.value, option.label]));
79
+ return rule.value.map((value) => labelOf.get(value) ?? value).join(", ");
80
+ }
81
+ if (typeof rule.value === "number" && columnFilter.kind === "number" && columnFilter.format)
82
+ return columnFilter.format(rule.value);
83
+ return String(rule.value);
84
+ };
85
+
86
+ const operatorText = (column: FilterableColumn<T>, rule: FilterRule) =>
87
+ text.operator(rule.operator, column as Column<never>);
88
+
89
+ const describe = (column: FilterableColumn<T>, rule: FilterRule) =>
90
+ `${column.label} ${operatorText(column, rule)} ${valueText(column, rule)}`;
91
+ </script>
92
+
93
+ {#snippet plus()}
94
+ <svg
95
+ viewBox="0 0 24 24"
96
+ fill="none"
97
+ stroke="currentColor"
98
+ stroke-width="2.25"
99
+ stroke-linecap="round"
100
+ aria-hidden="true"
101
+ >
102
+ <path d="M12 5v14M5 12h14" />
103
+ </svg>
104
+ {/snippet}
105
+
106
+ {#snippet cross()}
107
+ <svg
108
+ viewBox="0 0 24 24"
109
+ fill="none"
110
+ stroke="currentColor"
111
+ stroke-width="2.25"
112
+ stroke-linecap="round"
113
+ aria-hidden="true"
114
+ >
115
+ <path d="M18 6 6 18M6 6l12 12" />
116
+ </svg>
117
+ {/snippet}
118
+
119
+ {#snippet connector(group: FilterGroup, path: NodePath)}
120
+ <button
121
+ type="button"
122
+ class="plinth-filter-connector"
123
+ data-combinator={group.combinator}
124
+ aria-label={text.toggleCombinator(other(group.combinator))}
125
+ onclick={() => commit(setCombinator(filter, path, other(group.combinator)))}
126
+ >
127
+ {text.combinator(group.combinator)}
128
+ </button>
129
+ {/snippet}
130
+
131
+ {#snippet chip(rule: FilterRule, path: NodePath)}
132
+ {@const column = byKey.get(rule.key)!}
133
+ {@const description = describe(column, rule)}
134
+ <span class="plinth-filter-chip">
135
+ <Dropdown
136
+ bind:this={dropdowns[`edit:${pathKey(path)}`]}
137
+ class="plinth-filter-chip-body"
138
+ panelClass="plinth-filter-panel"
139
+ aria-label={text.edit(description)}
140
+ >
141
+ <span class="plinth-filter-chip-field">{column.label}</span>
142
+ <span class="plinth-filter-chip-operator">{operatorText(column, rule)}</span>
143
+ <span class="plinth-filter-chip-value">{valueText(column, rule)}</span>
144
+ {#snippet content()}
145
+ <FilterRuleEditor
146
+ {columns}
147
+ {fields}
148
+ {rule}
149
+ labels={text}
150
+ onapply={(next) => edit(path, next)}
151
+ />
152
+ {/snippet}
153
+ </Dropdown>
154
+ <button
155
+ type="button"
156
+ class="plinth-filter-chip-remove"
157
+ aria-label={text.remove(description)}
158
+ onclick={() => commit(removeNode(filter, path))}
159
+ >
160
+ {@render cross()}
161
+ </button>
162
+ </span>
163
+ {/snippet}
164
+
165
+ {#snippet addButton(path: NodePath, labelled: boolean)}
166
+ <Dropdown
167
+ bind:this={dropdowns[`add:${pathKey(path)}`]}
168
+ class={["plinth-filter-add", labelled && "plinth-filter-add-labelled"]}
169
+ panelClass="plinth-filter-panel"
170
+ aria-label={text.add}
171
+ >
172
+ {@render plus()}
173
+ {#if labelled}<span>{text.add}</span>{/if}
174
+ {#snippet content()}
175
+ <FilterRuleEditor {columns} {fields} labels={text} onapply={(rule) => add(path, rule)} />
176
+ {/snippet}
177
+ </Dropdown>
178
+ {/snippet}
179
+
180
+ {#snippet groupBody(group: FilterGroup, path: NodePath)}
181
+ {@const visible = group.children
182
+ .map((node, index) => ({ node, index }))
183
+ .filter(({ node }) => isGroup(node) || isRuleActive(columns, node))}
184
+ {#each visible as { node, index }, position (index)}
185
+ {#if position > 0}{@render connector(group, path)}{/if}
186
+ {#if isGroup(node)}
187
+ <span class="plinth-filter-group" role="group" aria-label={text.group}>
188
+ {@render groupBody(node, [...path, index])}
189
+ {@render addButton([...path, index], false)}
190
+ <button
191
+ type="button"
192
+ class="plinth-filter-group-remove"
193
+ aria-label={text.removeGroup}
194
+ onclick={() => commit(removeNode(filter, [...path, index]))}
195
+ >
196
+ {@render cross()}
197
+ </button>
198
+ </span>
199
+ {:else}
200
+ {@render chip(node, [...path, index])}
201
+ {/if}
202
+ {/each}
203
+ {/snippet}
204
+
205
+ <div class={["plinth-filter-bar", className]}>
206
+ {@render groupBody(filter, [])}
207
+ {@render addButton([], true)}
208
+ {#if groups}
209
+ <button type="button" class="plinth-filter-add plinth-filter-add-labelled" onclick={addGroup}>
210
+ {@render plus()}
211
+ <span>{text.addGroup}</span>
212
+ </button>
213
+ {/if}
214
+ {#if hasRules || filter.children.length > 0}
215
+ <button
216
+ type="button"
217
+ class="plinth-filter-clear"
218
+ onclick={() => commit(emptyFilter(filter.combinator))}
219
+ >
220
+ {text.clear}
221
+ </button>
222
+ {/if}
223
+ </div>
224
+
225
+ <style>
226
+ .plinth-filter-bar {
227
+ display: flex;
228
+ flex-wrap: wrap;
229
+ align-items: center;
230
+ gap: 0.375rem;
231
+ min-width: 0;
232
+ max-width: 100%;
233
+ font-size: 0.8125rem;
234
+ }
235
+
236
+ .plinth-filter-chip {
237
+ display: inline-flex;
238
+ align-items: stretch;
239
+ min-width: 0;
240
+ max-width: 100%;
241
+ border: 1px solid color-mix(in oklch, var(--color-base-content) 14%, transparent);
242
+ border-radius: var(--radius-field, 0.5rem);
243
+ background: var(--color-base-100);
244
+ box-shadow: 0 1px 0 color-mix(in oklch, var(--color-base-content) 4%, transparent);
245
+ }
246
+
247
+ .plinth-filter-chip:hover {
248
+ border-color: color-mix(in oklch, var(--color-base-content) 24%, transparent);
249
+ }
250
+
251
+ :global(.plinth-filter-chip-body) {
252
+ display: inline-flex;
253
+ align-items: baseline;
254
+ gap: 0.3em;
255
+ min-width: 0;
256
+ overflow: hidden;
257
+ padding: 0.2rem 0.25rem 0.2rem 0.55rem;
258
+ border-radius: var(--radius-field, 0.5rem) 0 0 var(--radius-field, 0.5rem);
259
+ cursor: pointer;
260
+ }
261
+
262
+ :global(.plinth-filter-chip-body:focus-visible) {
263
+ outline: 2px solid var(--color-primary);
264
+ outline-offset: 1px;
265
+ }
266
+
267
+ .plinth-filter-chip-field {
268
+ flex: none;
269
+ color: color-mix(in oklch, var(--color-base-content) 62%, transparent);
270
+ }
271
+
272
+ .plinth-filter-chip-operator {
273
+ flex: none;
274
+ color: var(--color-primary);
275
+ font-weight: 600;
276
+ }
277
+
278
+ .plinth-filter-chip-value {
279
+ min-width: 0;
280
+ max-width: 16rem;
281
+ overflow: hidden;
282
+ font-weight: 600;
283
+ text-overflow: ellipsis;
284
+ white-space: nowrap;
285
+ }
286
+
287
+ .plinth-filter-chip-remove,
288
+ .plinth-filter-group-remove {
289
+ display: inline-grid;
290
+ place-items: center;
291
+ flex: none;
292
+ width: 1.5rem;
293
+ color: color-mix(in oklch, var(--color-base-content) 45%, transparent);
294
+ cursor: pointer;
295
+ }
296
+
297
+ .plinth-filter-chip-remove {
298
+ border-radius: 0 var(--radius-field, 0.5rem) var(--radius-field, 0.5rem) 0;
299
+ }
300
+
301
+ .plinth-filter-chip-remove:hover,
302
+ .plinth-filter-group-remove:hover {
303
+ color: var(--color-error);
304
+ background: color-mix(in oklch, var(--color-error) 10%, transparent);
305
+ }
306
+
307
+ .plinth-filter-chip-remove :global(svg),
308
+ .plinth-filter-group-remove :global(svg) {
309
+ width: 0.75rem;
310
+ height: 0.75rem;
311
+ }
312
+
313
+ .plinth-filter-connector {
314
+ padding: 0.05rem 0.4rem;
315
+ border-radius: 999px;
316
+ font-size: 0.6875rem;
317
+ font-weight: 700;
318
+ letter-spacing: 0.04em;
319
+ text-transform: uppercase;
320
+ cursor: pointer;
321
+ transition:
322
+ background-color 120ms,
323
+ color 120ms;
324
+ }
325
+
326
+ .plinth-filter-connector[data-combinator="and"] {
327
+ background: color-mix(in oklch, var(--color-base-content) 7%, transparent);
328
+ color: color-mix(in oklch, var(--color-base-content) 65%, transparent);
329
+ }
330
+
331
+ .plinth-filter-connector[data-combinator="or"] {
332
+ background: color-mix(in oklch, var(--color-primary) 14%, transparent);
333
+ color: var(--color-primary);
334
+ }
335
+
336
+ .plinth-filter-connector:hover {
337
+ background: color-mix(in oklch, var(--color-primary) 22%, transparent);
338
+ color: var(--color-primary);
339
+ }
340
+
341
+ .plinth-filter-group {
342
+ display: inline-flex;
343
+ flex-wrap: wrap;
344
+ align-items: center;
345
+ gap: 0.375rem;
346
+ min-width: 0;
347
+ max-width: 100%;
348
+ padding: 0.2rem 0.2rem 0.2rem 0.45rem;
349
+ border: 1px dashed color-mix(in oklch, var(--color-primary) 40%, transparent);
350
+ border-radius: calc(var(--radius-field, 0.5rem) + 0.2rem);
351
+ background: color-mix(in oklch, var(--color-primary) 5%, transparent);
352
+ }
353
+
354
+ .plinth-filter-group-remove {
355
+ height: 1.5rem;
356
+ border-radius: var(--radius-field, 0.5rem);
357
+ }
358
+
359
+ :global(.plinth-filter-add) {
360
+ display: inline-flex;
361
+ align-items: center;
362
+ justify-content: center;
363
+ gap: 0.25rem;
364
+ min-width: 1.6rem;
365
+ height: 1.6rem;
366
+ padding: 0 0.3rem;
367
+ border: 1px dashed color-mix(in oklch, var(--color-base-content) 25%, transparent);
368
+ border-radius: var(--radius-field, 0.5rem);
369
+ color: color-mix(in oklch, var(--color-base-content) 65%, transparent);
370
+ cursor: pointer;
371
+ transition:
372
+ border-color 120ms,
373
+ color 120ms,
374
+ background-color 120ms;
375
+ }
376
+
377
+ :global(.plinth-filter-add-labelled) {
378
+ padding: 0 0.6rem 0 0.45rem;
379
+ }
380
+
381
+ :global(.plinth-filter-add:hover),
382
+ :global(.plinth-filter-add[aria-expanded="true"]) {
383
+ border-color: var(--color-primary);
384
+ background: color-mix(in oklch, var(--color-primary) 6%, transparent);
385
+ color: var(--color-primary);
386
+ }
387
+
388
+ :global(.plinth-filter-add svg) {
389
+ width: 0.8rem;
390
+ height: 0.8rem;
391
+ }
392
+
393
+ .plinth-filter-clear {
394
+ padding: 0 0.4rem;
395
+ color: color-mix(in oklch, var(--color-base-content) 55%, transparent);
396
+ cursor: pointer;
397
+ }
398
+
399
+ .plinth-filter-clear:hover {
400
+ color: var(--color-error);
401
+ text-decoration: underline;
402
+ }
403
+
404
+ :global(.plinth-filter-panel) {
405
+ width: 17rem;
406
+ max-height: 26rem;
407
+ margin: 0.3rem 0 0;
408
+ padding: 0.5rem;
409
+ overflow-y: auto;
410
+ border: 1px solid color-mix(in oklch, var(--color-base-content) 10%, transparent);
411
+ border-radius: var(--radius-box, 1rem);
412
+ background: var(--color-base-100);
413
+ box-shadow:
414
+ 0 10px 30px -10px color-mix(in oklch, var(--color-base-content) 30%, transparent),
415
+ 0 2px 6px -2px color-mix(in oklch, var(--color-base-content) 12%, transparent);
416
+ }
417
+ </style>
@@ -0,0 +1,34 @@
1
+ import type { ClassValue } from "svelte/elements";
2
+ import { type FilterLabels } from "./filter-labels.js";
3
+ import type { Column, FilterGroup } from "./types.js";
4
+ declare function $$render<T>(): {
5
+ props: {
6
+ columns: readonly Column<T>[];
7
+ filter?: FilterGroup;
8
+ onchange?: (filter: FilterGroup) => void;
9
+ groups?: boolean;
10
+ labels?: Partial<FilterLabels>;
11
+ class?: ClassValue;
12
+ };
13
+ exports: {};
14
+ bindings: "filter";
15
+ slots: {};
16
+ events: {};
17
+ };
18
+ declare class __sveltets_Render<T> {
19
+ props(): ReturnType<typeof $$render<T>>['props'];
20
+ events(): ReturnType<typeof $$render<T>>['events'];
21
+ slots(): ReturnType<typeof $$render<T>>['slots'];
22
+ bindings(): "filter";
23
+ exports(): {};
24
+ }
25
+ interface $$IsomorphicComponent {
26
+ new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
27
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
28
+ } & ReturnType<__sveltets_Render<T>['exports']>;
29
+ <T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
30
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
31
+ }
32
+ declare const FilterBar: $$IsomorphicComponent;
33
+ type FilterBar<T> = InstanceType<typeof FilterBar<T>>;
34
+ export default FilterBar;