@ibobbyts/svelte-ui-utils 0.4.7 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -110
- package/dist/data-table/FilterControl.svelte +208 -27
- package/dist/data-table/FilterControl.svelte.d.ts.map +1 -1
- package/dist/data-table/filter.d.ts +3 -1
- package/dist/data-table/filter.d.ts.map +1 -1
- package/dist/data-table/filter.js +5 -1
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.d.ts.map +1 -1
- package/dist/data-table/types.d.ts +60 -3
- package/dist/data-table/types.d.ts.map +1 -1
- package/dist/dropdown/Dropdown.svelte +27 -11
- package/dist/dropdown/Dropdown.svelte.d.ts +1 -1
- package/dist/dropdown/Dropdown.svelte.d.ts.map +1 -1
- package/dist/dropdown/index.d.ts +3 -0
- package/dist/dropdown/index.d.ts.map +1 -1
- package/dist/dropdown/index.js +2 -0
- package/dist/dropdown/load-options.d.ts +65 -0
- package/dist/dropdown/load-options.d.ts.map +1 -0
- package/dist/dropdown/load-options.js +57 -0
- package/dist/dropdown/selection.d.ts +14 -0
- package/dist/dropdown/selection.d.ts.map +1 -0
- package/dist/dropdown/selection.js +16 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/style.css +39 -282
- package/package.json +2 -11
- package/dist/dropdown-search/DropdownSearch.svelte +0 -725
- package/dist/dropdown-search/DropdownSearch.svelte.d.ts +0 -62
- package/dist/dropdown-search/DropdownSearch.svelte.d.ts.map +0 -1
- package/dist/dropdown-search/DropdownSearchMultiSelect.svelte +0 -94
- package/dist/dropdown-search/DropdownSearchMultiSelect.svelte.d.ts +0 -54
- package/dist/dropdown-search/DropdownSearchMultiSelect.svelte.d.ts.map +0 -1
- package/dist/dropdown-search/index.d.ts +0 -7
- package/dist/dropdown-search/index.d.ts.map +0 -1
- package/dist/dropdown-search/index.js +0 -4
- package/dist/dropdown-search/state.d.ts +0 -17
- package/dist/dropdown-search/state.d.ts.map +0 -1
- package/dist/dropdown-search/state.js +0 -51
- package/dist/dropdown-search/types.d.ts +0 -39
- package/dist/dropdown-search/types.d.ts.map +0 -1
- package/dist/dropdown-search/types.js +0 -1
package/README.md
CHANGED
|
@@ -40,7 +40,6 @@ import '@ibobbyts/svelte-ui-utils/style.css';
|
|
|
40
40
|
<script lang="ts">
|
|
41
41
|
import { ToastManager, toast } from '@ibobbyts/svelte-ui-utils/toast';
|
|
42
42
|
import { Dropdown } from '@ibobbyts/svelte-ui-utils/dropdown';
|
|
43
|
-
import { DropdownSearch, DropdownSearchMultiSelect } from '@ibobbyts/svelte-ui-utils/dropdown-search';
|
|
44
43
|
import { Dialog, ConfirmDialog, InputDialog, CsvUploadDialog, ImagePreviewDialog, PasswordCopyDialog } from '@ibobbyts/svelte-ui-utils/dialog';
|
|
45
44
|
import { DataTable, DateRangeFilter, FilterTable, NumberRangeFilter } from '@ibobbyts/svelte-ui-utils/table';
|
|
46
45
|
</script>
|
|
@@ -49,7 +48,7 @@ import '@ibobbyts/svelte-ui-utils/style.css';
|
|
|
49
48
|
The package root also re-exports the public modules:
|
|
50
49
|
|
|
51
50
|
```ts
|
|
52
|
-
import { ToastManager, Dropdown,
|
|
51
|
+
import { ToastManager, Dropdown, Dialog, DataTable } from '@ibobbyts/svelte-ui-utils';
|
|
53
52
|
```
|
|
54
53
|
|
|
55
54
|
## Toast
|
|
@@ -85,103 +84,6 @@ moves. Set `placement="up"` or `placement="down"` to force a direction. Use
|
|
|
85
84
|
`fitViewport={false}` to disable the default panel-height constraint for the
|
|
86
85
|
chosen side.
|
|
87
86
|
|
|
88
|
-
## DropdownSearch
|
|
89
|
-
|
|
90
|
-
`DropdownSearch` is the free-text input entry with server-driven validation
|
|
91
|
-
(`exactMatch`), input statuses, focus options, footer text, a clear button, and
|
|
92
|
-
multiselect chips. For a trigger-style dropdown that combines single or multi
|
|
93
|
-
select with async search and dynamic result groups, use the unified `Dropdown`
|
|
94
|
-
search mode instead.
|
|
95
|
-
|
|
96
|
-
```svelte
|
|
97
|
-
<script lang="ts">
|
|
98
|
-
import { DropdownSearch } from '@ibobbyts/svelte-ui-utils/dropdown-search';
|
|
99
|
-
|
|
100
|
-
async function loadOptions(query, { limit, signal }) {
|
|
101
|
-
const response = await fetch(`/api/search?q=${encodeURIComponent(query)}&limit=${limit}`, { signal });
|
|
102
|
-
return response.json();
|
|
103
|
-
}
|
|
104
|
-
</script>
|
|
105
|
-
|
|
106
|
-
<DropdownSearch
|
|
107
|
-
language="en_us"
|
|
108
|
-
placeholder="Search"
|
|
109
|
-
debounceMs={500}
|
|
110
|
-
clearLabel="Clear search"
|
|
111
|
-
width="24rem"
|
|
112
|
-
maxWidth="100%"
|
|
113
|
-
{loadOptions}
|
|
114
|
-
searchOnExternalValueChange={true}
|
|
115
|
-
closeOnValid={true}
|
|
116
|
-
/>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
`loadOptions` returns `{ options, exactMatch }`. An item uses this shape:
|
|
120
|
-
|
|
121
|
-
```ts
|
|
122
|
-
{
|
|
123
|
-
value: '123',
|
|
124
|
-
label: 'Jane Doe',
|
|
125
|
-
param_dict: { ID: 'M-123' }
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
`label` is the display text and `value` is the submitted string identifier;
|
|
130
|
-
extra fields such as `param_dict` are preserved as business metadata. The
|
|
131
|
-
free-text `value` prop and `onChange` detail stay the raw input text, so they
|
|
132
|
-
never collide with the submitted `item.value`.
|
|
133
|
-
|
|
134
|
-
The input is valid when the server returns one unique `exactMatch`, or when the
|
|
135
|
-
user selects an item. Non-empty text without a unique match is invalid.
|
|
136
|
-
Set `validate={false}` when the field should only show selectable options and
|
|
137
|
-
stay visually neutral instead of turning green or red. In that mode the
|
|
138
|
-
component ignores `exactMatch` for status and auto-selection.
|
|
139
|
-
Use `searchOnExternalValueChange` for scanner or programmatic input workflows.
|
|
140
|
-
Set `closeOnValid={true}` to hide the result list after validation finds a
|
|
141
|
-
usable exact match. The default is `false`, so existing validated searches keep
|
|
142
|
-
showing their current result list until the field closes or the user selects an
|
|
143
|
-
option.
|
|
144
|
-
Use `showOptionsOnFocus={true}` with `focusOptions` to show a controlled set of
|
|
145
|
-
options as soon as the field receives focus, including when the current value is
|
|
146
|
-
empty or already valid. Pass `footerText` to render a non-selectable note below
|
|
147
|
-
the options, separated by a divider.
|
|
148
|
-
When the input has text, `DropdownSearch` shows an internal clear button on the
|
|
149
|
-
right side of the field. Use `clearLabel` to localize that button's accessible
|
|
150
|
-
label, or use `language` to select the package default.
|
|
151
|
-
Use `width`, `minWidth`, and `maxWidth` to size the control directly when a
|
|
152
|
-
wrapper is not convenient.
|
|
153
|
-
Server-side code and Node tests that only need pure helpers should import from
|
|
154
|
-
`@ibobbyts/svelte-ui-utils/dropdown-search/state` so they do not load Svelte
|
|
155
|
-
component files.
|
|
156
|
-
|
|
157
|
-
Set `multiselect={true}` when the search box should collect multiple selected
|
|
158
|
-
items as chips. `DropdownSearchMultiSelect` is a convenience wrapper with the
|
|
159
|
-
same controlled contract:
|
|
160
|
-
|
|
161
|
-
```svelte
|
|
162
|
-
<script lang="ts">
|
|
163
|
-
import { DropdownSearchMultiSelect, type DropdownSearchItem } from '@ibobbyts/svelte-ui-utils/dropdown-search';
|
|
164
|
-
|
|
165
|
-
let selectedMembers: DropdownSearchItem[] = [];
|
|
166
|
-
</script>
|
|
167
|
-
|
|
168
|
-
<DropdownSearchMultiSelect
|
|
169
|
-
language="en_us"
|
|
170
|
-
placeholder="Search members"
|
|
171
|
-
selectedItems={selectedMembers}
|
|
172
|
-
selectedItemsLabel="Selected members"
|
|
173
|
-
removeSelectedItemLabel={(item) => `Remove ${item.label}`}
|
|
174
|
-
{loadOptions}
|
|
175
|
-
onSelectedItemsChange={(items) => {
|
|
176
|
-
selectedMembers = items;
|
|
177
|
-
}}
|
|
178
|
-
/>
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
In multiselect mode, the text input remains a search query. Selecting an item
|
|
182
|
-
adds or removes it from `selectedItems`, clears the query, and emits both
|
|
183
|
-
`onChange` and `onSelectedItemsChange`.
|
|
184
|
-
|
|
185
87
|
## SortableList
|
|
186
88
|
|
|
187
89
|
`SortableList` provides controlled vertical HTML5 drag-and-drop ordering. Each
|
|
@@ -417,8 +319,8 @@ the menu to its longest option while keeping the selected edge aligned.
|
|
|
417
319
|
`DataTable` uses this same component for its page-size picker.
|
|
418
320
|
|
|
419
321
|
Set `search={true}` with `loadOptions` to load remote options as the user
|
|
420
|
-
types. The default `
|
|
421
|
-
expanded menu. Set `
|
|
322
|
+
types. The default `inputStyle="dropdown"` keeps the search field inside the
|
|
323
|
+
expanded menu. Set `inputStyle="input"` to render a directly editable input;
|
|
422
324
|
results appear while it is focused and hide on blur. In input style, the
|
|
423
325
|
optional `getItemLabel` callback controls the displayed label while `value`
|
|
424
326
|
and `onChange` continue to represent submitted option values. The input style
|
|
@@ -603,6 +505,54 @@ render source and `loadOptions` is never called. Type the loader with
|
|
|
603
505
|
`DropdownLoadOptions`/`DropdownLoadOptionsResult`, exported from the package
|
|
604
506
|
root.
|
|
605
507
|
|
|
508
|
+
### loadOptions factories
|
|
509
|
+
|
|
510
|
+
Most `loadOptions` implementations only differ in the item source: filter a
|
|
511
|
+
local array, or POST one JSON endpoint. The factories exported from
|
|
512
|
+
`@ibobbyts/svelte-ui-utils/dropdown` (and the package root) build loaders that
|
|
513
|
+
fit both the root `Dropdown` search mode and the data-table
|
|
514
|
+
`filter.dropdownSearch` control:
|
|
515
|
+
|
|
516
|
+
```ts
|
|
517
|
+
import { createFetchLoadOptions, createLocalLoadOptions } from '@ibobbyts/svelte-ui-utils';
|
|
518
|
+
|
|
519
|
+
// Local list: filter, map to options, slice to the limit.
|
|
520
|
+
const loadFromRoster = createLocalLoadOptions(
|
|
521
|
+
() => rosterUsers,
|
|
522
|
+
{
|
|
523
|
+
toOption: (user) => ({ value: String(user.id), label: user.displayName }),
|
|
524
|
+
matches: (user, query) => matchesPinyin(user.displayName, query),
|
|
525
|
+
limit: 5
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
// JSON endpoint: URL, body builder, payload decoding, abort and error policy.
|
|
530
|
+
const loadFromApi = createFetchLoadOptions({
|
|
531
|
+
url: '/api/members/search',
|
|
532
|
+
buildBody: (query, limit) => ({ groupId, query, limit }),
|
|
533
|
+
mapOptions: (payload) => (payload as { options: MemberOption[] }).options ?? [],
|
|
534
|
+
throwOnError: true
|
|
535
|
+
});
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`createLocalLoadOptions(source, config?)` accepts a static array or a getter
|
|
539
|
+
re-evaluated on every search. `toOption` converts domain items (omit it when
|
|
540
|
+
the items already satisfy the `{ label, value }` contract); `matches` receives
|
|
541
|
+
the raw item and the trimmed query, and defaults to a case-insensitive
|
|
542
|
+
substring match over the converted option's `label`/`searchText`, where an
|
|
543
|
+
empty query matches everything. `limit` caps the context limit.
|
|
544
|
+
|
|
545
|
+
`createFetchLoadOptions(config)` skips the request for a blank query, posts
|
|
546
|
+
JSON (default body `{ query, limit }`), passes `context.signal` through, and
|
|
547
|
+
decodes the payload with `mapOptions` before slicing to the limit. HTTP and
|
|
548
|
+
network failures resolve with no options by default; `throwOnError: true`
|
|
549
|
+
rethrows them (aborted requests always resolve with no options) so wrappers
|
|
550
|
+
that surface errors keep working.
|
|
551
|
+
|
|
552
|
+
Multiselect handlers can also stop repeating the `string | string[]` narrowing:
|
|
553
|
+
`toMultiSelection(selection)` and `toSingleSelection(selection)` normalize a
|
|
554
|
+
`Dropdown` `onChange` argument to the shape the handler needs.
|
|
555
|
+
|
|
606
556
|
## DataTable
|
|
607
557
|
|
|
608
558
|
```svelte
|
|
@@ -766,10 +716,8 @@ for the left column and a controlled filter created with the `filter` helper:
|
|
|
766
716
|
filter.dropdownSearch({
|
|
767
717
|
value: searchValue,
|
|
768
718
|
selectedItem,
|
|
769
|
-
status: searchStatus,
|
|
770
719
|
width: '24rem',
|
|
771
720
|
maxWidth: '100%',
|
|
772
|
-
clearLabel: 'Clear search',
|
|
773
721
|
loadOptions,
|
|
774
722
|
onChange: (detail) => updateSearch(detail)
|
|
775
723
|
}),
|
|
@@ -786,6 +734,29 @@ for the left column and a controlled filter created with the `filter` helper:
|
|
|
786
734
|
and `var(--suu-radius)` corner radius as a bordered `DataTable`. Set
|
|
787
735
|
`bordered={false}` to remove both the border and outer corner radius.
|
|
788
736
|
|
|
737
|
+
`filter.text` renders a free-text search input for `keyword contains`-style
|
|
738
|
+
filtering. Unlike `filter.dropdownSearch` it has no selection semantics: the
|
|
739
|
+
value is the raw input text, and matching stays in the consuming app:
|
|
740
|
+
|
|
741
|
+
```svelte
|
|
742
|
+
{
|
|
743
|
+
key: 'location',
|
|
744
|
+
title: 'Location',
|
|
745
|
+
filter: filter.text({
|
|
746
|
+
value: locationQuery,
|
|
747
|
+
placeholder: 'Search location',
|
|
748
|
+
ariaLabel: 'Location filter',
|
|
749
|
+
onChange: (value) => (locationQuery = value)
|
|
750
|
+
})
|
|
751
|
+
}
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
Every keystroke reports by default; pass `debounceMs` to batch changes (Enter
|
|
755
|
+
flushes the pending draft immediately). The input stays a controlled input:
|
|
756
|
+
applying the new value from `onChange` keeps typing intact, and resetting
|
|
757
|
+
`value` clears the field. Width follows the `width`/`minWidth`/`maxWidth`
|
|
758
|
+
props when the full-row default is not what you want.
|
|
759
|
+
|
|
789
760
|
`filter.select` uses the shared `Dropdown` component, so select filters keep the
|
|
790
761
|
same menu, keyboard, and visual behavior as standalone dropdowns.
|
|
791
762
|
|
|
@@ -811,13 +782,6 @@ same menu, keyboard, and visual behavior as standalone dropdowns.
|
|
|
811
782
|
}
|
|
812
783
|
```
|
|
813
784
|
|
|
814
|
-
If a dropdown-style filter appears clipped, check the parent containers first.
|
|
815
|
-
`DropdownSearch` renders its result list as an absolutely positioned child, so
|
|
816
|
-
any ancestor with `overflow: hidden`, `overflow: auto`, or `overflow: scroll`
|
|
817
|
-
can clip the menu even when the menu has a high `z-index`. Keep the nearest
|
|
818
|
-
filter container at `overflow: visible`, or move the clipping/scrolling behavior
|
|
819
|
-
to a parent that does not wrap the dropdown menu directly.
|
|
820
|
-
|
|
821
785
|
`dateRange` renders two browser date inputs, preset buttons, and quick month/year
|
|
822
786
|
selects. The presets are `last 24 hours`, `last 7 days`, `last 30 days`,
|
|
823
787
|
`today`, `this week`, `this month`, and `this year`. Manual changes and quick
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
<svelte:options runes={false} />
|
|
2
2
|
|
|
3
3
|
<script lang="ts">
|
|
4
|
+
import { onDestroy } from 'svelte';
|
|
4
5
|
import Dropdown from '../dropdown/Dropdown.svelte';
|
|
5
6
|
import DropdownMultiSelect from '../dropdown/DropdownMultiSelect.svelte';
|
|
6
|
-
import
|
|
7
|
+
import type {
|
|
8
|
+
DropdownLoadContext,
|
|
9
|
+
DropdownLoadOptionsResult,
|
|
10
|
+
DropdownOption,
|
|
11
|
+
DropdownSelection
|
|
12
|
+
} from '../dropdown/types.js';
|
|
7
13
|
import type { UiLanguage } from '../i18n.js';
|
|
8
14
|
import DateRangeFilter from './DateRangeFilter.svelte';
|
|
9
15
|
import NumberRangeFilter from './NumberRangeFilter.svelte';
|
|
10
|
-
import type { FilterControl } from './types.js';
|
|
16
|
+
import type { DropdownSearchChangeDetail, DropdownSearchItem, FilterControl } from './types.js';
|
|
11
17
|
|
|
12
18
|
export let control: FilterControl;
|
|
13
19
|
export let language: UiLanguage = 'en_us';
|
|
@@ -32,6 +38,171 @@
|
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
|
|
41
|
+
// The removed DropdownSearch spoke free text in `value` while the root
|
|
42
|
+
// Dropdown reports option identifiers. This adapter keeps the legacy
|
|
43
|
+
// `{ value: label, selectedItem, selectedItems, status }` detail by resolving
|
|
44
|
+
// each identifier back to the item that loadOptions returned.
|
|
45
|
+
let dropdownSearchQuery = '';
|
|
46
|
+
const dropdownSearchItems = new Map<string, DropdownSearchItem>();
|
|
47
|
+
|
|
48
|
+
function resolveDropdownSearchItemLabel(item: DropdownSearchItem): string {
|
|
49
|
+
return control.type === 'dropdownSearch' && control.getItemLabel
|
|
50
|
+
? control.getItemLabel(item)
|
|
51
|
+
: item.label;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// The root Dropdown types labels against its own option shape; the options it
|
|
55
|
+
// hands back are the very `DropdownSearchItem` objects we returned, so the
|
|
56
|
+
// structural widening is lossless for consumers' getItemLabel callbacks.
|
|
57
|
+
function dropdownSearchOptionLabel(option: DropdownOption): string {
|
|
58
|
+
return resolveDropdownSearchItemLabel(option as DropdownSearchItem);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function findDropdownSearchItem(identifier: string): DropdownSearchItem | undefined {
|
|
62
|
+
const cached = dropdownSearchItems.get(identifier);
|
|
63
|
+
if (cached !== undefined) {
|
|
64
|
+
return cached;
|
|
65
|
+
}
|
|
66
|
+
if (control.type === 'dropdownSearch' && control.selectedItem?.value === identifier) {
|
|
67
|
+
return control.selectedItem;
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function loadDropdownSearchOptions(
|
|
73
|
+
rawQuery: string,
|
|
74
|
+
context: DropdownLoadContext
|
|
75
|
+
): Promise<DropdownLoadOptionsResult> {
|
|
76
|
+
if (control.type !== 'dropdownSearch') {
|
|
77
|
+
return { options: [] };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const query = rawQuery.trim();
|
|
81
|
+
// minLength has no root Dropdown counterpart, so the wrapper keeps the old
|
|
82
|
+
// "below threshold returns no options" contract itself.
|
|
83
|
+
if (query.length < (control.minLength ?? 1)) {
|
|
84
|
+
return { options: [] };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = await control.loadOptions(query, context);
|
|
88
|
+
// Stale responses must not seed the identifier cache either.
|
|
89
|
+
if (context.signal.aborted) {
|
|
90
|
+
return { options: [] };
|
|
91
|
+
}
|
|
92
|
+
const items = result?.options ?? [];
|
|
93
|
+
for (const item of items) {
|
|
94
|
+
dropdownSearchItems.set(item.value, item);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { options: items };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function handleDropdownSearchQueryChange(query: string) {
|
|
101
|
+
dropdownSearchQuery = query;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function handleDropdownSearchChange(selection: DropdownSelection) {
|
|
105
|
+
if (control.type !== 'dropdownSearch') {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const identifier = Array.isArray(selection) ? (selection[0] ?? '') : selection;
|
|
110
|
+
// The root Dropdown reports an empty identifier when the user types over a
|
|
111
|
+
// controlled selection (input/value divergence). That divergent-clear is
|
|
112
|
+
// dropped so `onChange` stays a selection-change (submit) event; a real
|
|
113
|
+
// selection always carries a non-empty identifier.
|
|
114
|
+
if (!identifier) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const item = findDropdownSearchItem(identifier);
|
|
118
|
+
const detail: DropdownSearchChangeDetail = {
|
|
119
|
+
value: item ? resolveDropdownSearchItemLabel(item) : identifier,
|
|
120
|
+
selectedItem: item ?? null,
|
|
121
|
+
selectedItems: [],
|
|
122
|
+
status: item ? 'valid' : dropdownSearchQuery.trim() ? 'invalid' : 'empty'
|
|
123
|
+
};
|
|
124
|
+
void control.onChange(detail);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// External value/selected-item changes rebuild the root Dropdown instance:
|
|
128
|
+
// controlled `value` resets its internal query, results, and draft, and
|
|
129
|
+
// `selectedOptions` then displays the new selection.
|
|
130
|
+
$: dropdownSearchKey = control.type === 'dropdownSearch'
|
|
131
|
+
? `${control.value}\u0000${control.selectedItem?.value ?? ''}`
|
|
132
|
+
: '';
|
|
133
|
+
// A selected item displays through `selectedOptions`; a free-text external
|
|
134
|
+
// value has no option to resolve and falls back to the Dropdown value itself.
|
|
135
|
+
$: dropdownSearchValue = control.type === 'dropdownSearch'
|
|
136
|
+
? control.selectedItem
|
|
137
|
+
? control.selectedItem.value
|
|
138
|
+
: control.value
|
|
139
|
+
: '';
|
|
140
|
+
// The raw item is handed to the Dropdown untouched so its `getItemLabel` prop
|
|
141
|
+
// is the single label conversion on the display path.
|
|
142
|
+
$: dropdownSearchSelectedOptions = control.type === 'dropdownSearch' && control.selectedItem
|
|
143
|
+
? [control.selectedItem]
|
|
144
|
+
: [];
|
|
145
|
+
|
|
146
|
+
// Free-text filter input: with debounceMs > 0 the draft lives here until the
|
|
147
|
+
// timer fires or Enter flushes it; the controlled `value` only catches up
|
|
148
|
+
// once the parent applies onChange, and Svelte leaves the DOM value alone
|
|
149
|
+
// until then so typing is never clobbered mid-draft.
|
|
150
|
+
let textInputTimer: ReturnType<typeof setTimeout> | null = null;
|
|
151
|
+
let textInputPending: string | null = null;
|
|
152
|
+
|
|
153
|
+
function flushTextInput() {
|
|
154
|
+
if (textInputTimer !== null) {
|
|
155
|
+
clearTimeout(textInputTimer);
|
|
156
|
+
textInputTimer = null;
|
|
157
|
+
}
|
|
158
|
+
if (textInputPending !== null && control.type === 'text') {
|
|
159
|
+
const value = textInputPending;
|
|
160
|
+
textInputPending = null;
|
|
161
|
+
void control.onChange(value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function handleTextInput(value: string) {
|
|
166
|
+
if (control.type !== 'text') {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const debounceMs = control.debounceMs ?? 0;
|
|
170
|
+
if (debounceMs <= 0) {
|
|
171
|
+
void control.onChange(value);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
textInputPending = value;
|
|
175
|
+
if (textInputTimer !== null) {
|
|
176
|
+
clearTimeout(textInputTimer);
|
|
177
|
+
}
|
|
178
|
+
textInputTimer = setTimeout(flushTextInput, debounceMs);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function handleTextKeydown(event: KeyboardEvent) {
|
|
182
|
+
if (event.key === 'Enter' && control.type === 'text') {
|
|
183
|
+
event.preventDefault();
|
|
184
|
+
flushTextInput();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
$: textInputStyle = control.type === 'text'
|
|
189
|
+
? [
|
|
190
|
+
control.width ? `width: ${control.width}` : '',
|
|
191
|
+
control.minWidth ? `min-width: ${control.minWidth}` : '',
|
|
192
|
+
control.maxWidth ? `max-width: ${control.maxWidth}` : ''
|
|
193
|
+
]
|
|
194
|
+
.filter(Boolean)
|
|
195
|
+
.join('; ')
|
|
196
|
+
: '';
|
|
197
|
+
|
|
198
|
+
onDestroy(() => {
|
|
199
|
+
if (textInputTimer !== null) {
|
|
200
|
+
clearTimeout(textInputTimer);
|
|
201
|
+
textInputTimer = null;
|
|
202
|
+
}
|
|
203
|
+
textInputPending = null;
|
|
204
|
+
});
|
|
205
|
+
|
|
35
206
|
</script>
|
|
36
207
|
|
|
37
208
|
{#if control.type === 'container'}
|
|
@@ -110,31 +281,29 @@
|
|
|
110
281
|
{/each}
|
|
111
282
|
</div>
|
|
112
283
|
{:else if control.type === 'dropdownSearch'}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
onChange={(detail) => control.type === 'dropdownSearch' && void control.onChange(detail)}
|
|
137
|
-
/>
|
|
284
|
+
{#key dropdownSearchKey}
|
|
285
|
+
<Dropdown
|
|
286
|
+
value={dropdownSearchValue}
|
|
287
|
+
search
|
|
288
|
+
inputStyle="input"
|
|
289
|
+
portal
|
|
290
|
+
selectedOptions={dropdownSearchSelectedOptions}
|
|
291
|
+
loadOptions={loadDropdownSearchOptions}
|
|
292
|
+
searchDebounceMs={control.debounceMs ?? 500}
|
|
293
|
+
searchLimit={control.limit ?? 10}
|
|
294
|
+
placeholder={control.placeholder ?? ''}
|
|
295
|
+
ariaLabel={control.ariaLabel}
|
|
296
|
+
{language}
|
|
297
|
+
noResultsText={control.noResultsText}
|
|
298
|
+
loadingText={control.loadingText}
|
|
299
|
+
width={control.width}
|
|
300
|
+
minWidth={control.minWidth}
|
|
301
|
+
maxWidth={control.maxWidth}
|
|
302
|
+
getItemLabel={dropdownSearchOptionLabel}
|
|
303
|
+
onChange={handleDropdownSearchChange}
|
|
304
|
+
onSearchChange={handleDropdownSearchQueryChange}
|
|
305
|
+
/>
|
|
306
|
+
{/key}
|
|
138
307
|
{:else if control.type === 'dateRange'}
|
|
139
308
|
<DateRangeFilter
|
|
140
309
|
value={control.value}
|
|
@@ -264,4 +433,16 @@
|
|
|
264
433
|
onChange={control.onChange}
|
|
265
434
|
onTriggerClick={control.onTriggerClick}
|
|
266
435
|
/>
|
|
436
|
+
{:else if control.type === 'text'}
|
|
437
|
+
<input
|
|
438
|
+
class="suu-filter-table__text-input"
|
|
439
|
+
type="search"
|
|
440
|
+
value={control.value}
|
|
441
|
+
placeholder={control.placeholder ?? ''}
|
|
442
|
+
aria-label={control.ariaLabel}
|
|
443
|
+
disabled={control.disabled}
|
|
444
|
+
style={textInputStyle}
|
|
445
|
+
on:input={(event) => handleTextInput((event.currentTarget as HTMLInputElement).value)}
|
|
446
|
+
on:keydown={handleTextKeydown}
|
|
447
|
+
/>
|
|
267
448
|
{/if}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterControl.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/FilterControl.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FilterControl.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/FilterControl.svelte.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAkD,aAAa,EAAE,MAAM,YAAY,CAAC;AAuUhG,QAAA,MAAM,aAAa,KAA+E,CAAC;AACjF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CheckboxFilterControl, DateRangeFilterControl, DropdownFilterControl, DropdownMultiSelectFilterControl, DropdownSearchFilterControl, FilterButtonControl, FilterContainerControl, FilterControl, FilterLinkControl, FilterSelectControl, NumberRangeFilterControl, RadioFilterControl } from './types.js';
|
|
1
|
+
import type { CheckboxFilterControl, DateRangeFilterControl, DropdownFilterControl, DropdownMultiSelectFilterControl, DropdownSearchFilterControl, FilterButtonControl, FilterContainerControl, FilterControl, FilterLinkControl, FilterSelectControl, NumberRangeFilterControl, RadioFilterControl, TextInputFilterControl } from './types.js';
|
|
2
2
|
declare function checkbox(options: Omit<CheckboxFilterControl, 'type'>): CheckboxFilterControl;
|
|
3
3
|
declare function radio(options: Omit<RadioFilterControl, 'type'>): RadioFilterControl;
|
|
4
4
|
declare function dropdownSearch(options: Omit<DropdownSearchFilterControl, 'type'>): DropdownSearchFilterControl;
|
|
@@ -10,6 +10,7 @@ declare function select(options: Omit<FilterSelectControl, 'type'>): FilterSelec
|
|
|
10
10
|
declare function dropdown(options: Omit<DropdownFilterControl, 'type'>): DropdownFilterControl;
|
|
11
11
|
declare function dropdownMultiSelect(options: Omit<DropdownMultiSelectFilterControl, 'type'>): DropdownMultiSelectFilterControl;
|
|
12
12
|
declare function container(controls: FilterControl[]): FilterContainerControl;
|
|
13
|
+
declare function text(options: Omit<TextInputFilterControl, 'type'>): TextInputFilterControl;
|
|
13
14
|
export declare const filter: {
|
|
14
15
|
checkbox: typeof checkbox;
|
|
15
16
|
radio: typeof radio;
|
|
@@ -22,6 +23,7 @@ export declare const filter: {
|
|
|
22
23
|
dropdown: typeof dropdown;
|
|
23
24
|
dropdownMultiSelect: typeof dropdownMultiSelect;
|
|
24
25
|
container: typeof container;
|
|
26
|
+
text: typeof text;
|
|
25
27
|
};
|
|
26
28
|
export {};
|
|
27
29
|
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gCAAgC,EAChC,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,gCAAgC,EAChC,2BAA2B,EAC3B,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAEpB,iBAAS,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,qBAAqB,CAErF;AAED,iBAAS,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,GAAG,kBAAkB,CAE5E;AAED,iBAAS,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,2BAA2B,EAAE,MAAM,CAAC,GAAG,2BAA2B,CAEvG;AAED,iBAAS,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,GAAG,sBAAsB,CAExF;AAED,iBAAS,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,CAAC,GAAG,wBAAwB,CAE9F;AAED,iBAAS,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAAG,mBAAmB,CAE/E;AAED,iBAAS,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC,GAAG,iBAAiB,CAEzE;AAED,iBAAS,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAAG,mBAAmB,CAE/E;AAED,iBAAS,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAAG,qBAAqB,CAErF;AAED,iBAAS,mBAAmB,CAC1B,OAAO,EAAE,IAAI,CAAC,gCAAgC,EAAE,MAAM,CAAC,GACtD,gCAAgC,CAElC;AAED,iBAAS,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,sBAAsB,CAEpE;AAED,iBAAS,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,GAAG,sBAAsB,CAEnF;AAED,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAalB,CAAC"}
|
|
@@ -31,6 +31,9 @@ function dropdownMultiSelect(options) {
|
|
|
31
31
|
function container(controls) {
|
|
32
32
|
return { type: 'container', controls };
|
|
33
33
|
}
|
|
34
|
+
function text(options) {
|
|
35
|
+
return { type: 'text', ...options };
|
|
36
|
+
}
|
|
34
37
|
export const filter = {
|
|
35
38
|
checkbox,
|
|
36
39
|
radio,
|
|
@@ -42,5 +45,6 @@ export const filter = {
|
|
|
42
45
|
select,
|
|
43
46
|
dropdown,
|
|
44
47
|
dropdownMultiSelect,
|
|
45
|
-
container
|
|
48
|
+
container,
|
|
49
|
+
text
|
|
46
50
|
};
|
|
@@ -8,5 +8,5 @@ export { isDateRangePreset, resolveDateRangePreset } from './date-range.js';
|
|
|
8
8
|
export { getUiMessages, resolveUiLanguage, uiLanguages } from '../i18n.js';
|
|
9
9
|
export { getAriaSort, getCellValue, getPageCount, normalizePagination, setDataTableFilters, setDataTablePageSize, setDataTablePagination, setDataTableSort, toggleSort } from './state.js';
|
|
10
10
|
export type { UiLanguage, UiMessages } from '../i18n.js';
|
|
11
|
-
export type { CheckboxFilterDefinition, CheckboxFilterControl, CustomDateRangePreset, DataTableColumn, DataTableCellValue, DataTableClassValue, DataTableHorizontalAlign, DataTableLayout, DataTablePaginationQueryKey, DataTableServerPagination, DataTableVerticalAlign, DateRangeFilterDefinition, DateRangeFilterControl, DateRangeFilterValue, DateRangePreset, DateRangePresetContext, DateRangePresetEntry, DateRangePresetSelect, DataTableRowAttributes, DataTableRowKey, DataTableSortChangeHandler, DataTableState, DataTableStateChangeHandler, DropdownSearchFilterDefinition, DropdownSearchFilterControl, DropdownFilterDefinition, DropdownFilterControl, DropdownMultiSelectFilterDefinition, DropdownMultiSelectFilterControl, FilterDefinition, FilterButtonControl, FilterContainerControl, FilterControl, FilterLinkControl, FilterOption, FilterSelectControl, FilterState, FilterTableRow, FilterValue, NumberRangeFilterDefinition, NumberRangeFilterControl, NumberRangeFilterValue, PaginationState, PaginationChangeHandler, PaginationDropdownPlacement, RadioFilterDefinition, RadioFilterControl, SortDirection, SortState } from './types.js';
|
|
11
|
+
export type { CheckboxFilterDefinition, CheckboxFilterControl, CustomDateRangePreset, DataTableColumn, DataTableCellValue, DataTableClassValue, DataTableHorizontalAlign, DataTableLayout, DataTablePaginationQueryKey, DataTableServerPagination, DataTableVerticalAlign, DateRangeFilterDefinition, DateRangeFilterControl, DateRangeFilterValue, DateRangePreset, DateRangePresetContext, DateRangePresetEntry, DateRangePresetSelect, DataTableRowAttributes, DataTableRowKey, DataTableSortChangeHandler, DataTableState, DataTableStateChangeHandler, DropdownSearchFilterDefinition, DropdownSearchFilterControl, DropdownFilterDefinition, DropdownFilterControl, DropdownMultiSelectFilterDefinition, DropdownMultiSelectFilterControl, FilterDefinition, FilterButtonControl, FilterContainerControl, FilterControl, FilterLinkControl, FilterOption, FilterSelectControl, FilterState, FilterTableRow, FilterValue, NumberRangeFilterDefinition, NumberRangeFilterControl, NumberRangeFilterValue, PaginationState, PaginationChangeHandler, PaginationDropdownPlacement, RadioFilterDefinition, RadioFilterControl, SortDirection, SortState, TextInputFilterDefinition, TextInputFilterControl } from './types.js';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,0BAA0B,EAC1B,cAAc,EACd,2BAA2B,EAC3B,8BAA8B,EAC9B,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,mCAAmC,EACnC,gCAAgC,EAChC,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,WAAW,EACX,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,EACtB,eAAe,EACf,uBAAuB,EACvB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/data-table/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,EACtB,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,0BAA0B,EAC1B,cAAc,EACd,2BAA2B,EAC3B,8BAA8B,EAC9B,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,mCAAmC,EACnC,gCAAgC,EAChC,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,WAAW,EACX,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,EACtB,eAAe,EACf,uBAAuB,EACvB,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,SAAS,EACT,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,YAAY,CAAC"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { DropdownSearchChangeDetail, DropdownSearchItem, DropdownSearchItemLabelGetter, DropdownSearchLoadOptions, DropdownSearchStatus } from '../dropdown-search/types.js';
|
|
2
1
|
import type { DropdownLoadOptions, DropdownMenuAlign, DropdownMultiChangeHandler, DropdownMultiValue, DropdownOption, DropdownOptionGroup, DropdownPlacement, DropdownSelection, DropdownSelectionChangeHandler, DropdownTriggerClickHandler } from '../dropdown/types.js';
|
|
3
2
|
export type SortDirection = 'asc' | 'desc';
|
|
4
3
|
export type DataTableLayout = 'auto' | 'fixed';
|
|
@@ -187,6 +186,42 @@ export interface RadioFilterControl {
|
|
|
187
186
|
options: FilterOption[];
|
|
188
187
|
onChange: (value: string) => void | Promise<void>;
|
|
189
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Data-table-local copy of the structural types that the removed free-text
|
|
191
|
+
* search component family used to host. The `dropdownSearch` filter control
|
|
192
|
+
* contract is unchanged; only that module is gone.
|
|
193
|
+
*/
|
|
194
|
+
export type DropdownSearchStatus = 'empty' | 'loading' | 'valid' | 'invalid' | 'error';
|
|
195
|
+
/**
|
|
196
|
+
* Search options and selected chips use the unified label/value contract:
|
|
197
|
+
* `label` is the display text, `value` is the submitted string identifier.
|
|
198
|
+
* Extra business fields (e.g. `param_dict`) are preserved as metadata.
|
|
199
|
+
*/
|
|
200
|
+
export interface DropdownSearchItem {
|
|
201
|
+
label: string;
|
|
202
|
+
value: string;
|
|
203
|
+
param_dict?: Record<string, string | number | null>;
|
|
204
|
+
disabled?: boolean;
|
|
205
|
+
[key: string]: unknown;
|
|
206
|
+
}
|
|
207
|
+
export interface DropdownSearchLoadContext {
|
|
208
|
+
limit: number;
|
|
209
|
+
signal: AbortSignal;
|
|
210
|
+
}
|
|
211
|
+
export interface DropdownSearchResult {
|
|
212
|
+
options: DropdownSearchItem[];
|
|
213
|
+
exactMatch?: DropdownSearchItem | null;
|
|
214
|
+
}
|
|
215
|
+
export type DropdownSearchLoadOptions = (query: string, context: DropdownSearchLoadContext) => Promise<DropdownSearchResult> | DropdownSearchResult;
|
|
216
|
+
export interface DropdownSearchChangeDetail {
|
|
217
|
+
/** Free-text input content; distinct from the submitted `DropdownSearchItem.value`. */
|
|
218
|
+
value: string;
|
|
219
|
+
selectedItem: DropdownSearchItem | null;
|
|
220
|
+
selectedItems: DropdownSearchItem[];
|
|
221
|
+
status: DropdownSearchStatus;
|
|
222
|
+
}
|
|
223
|
+
/** Returns the input text shown for a selected item; defaults to the item label. */
|
|
224
|
+
export type DropdownSearchItemLabelGetter = (item: DropdownSearchItem) => string;
|
|
190
225
|
export interface DropdownSearchFilterControl {
|
|
191
226
|
type: 'dropdownSearch';
|
|
192
227
|
value: string;
|
|
@@ -241,7 +276,25 @@ export interface FilterContainerControl {
|
|
|
241
276
|
type: 'container';
|
|
242
277
|
controls: FilterControl[];
|
|
243
278
|
}
|
|
244
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Free-text filter input for `keyword contains`-style filtering. Unlike
|
|
281
|
+
* `dropdownSearch` it has no selection semantics: every (debounced) change is
|
|
282
|
+
* the raw input text, so it pairs with consumer-side row matching.
|
|
283
|
+
*/
|
|
284
|
+
export interface TextInputFilterControl {
|
|
285
|
+
type: 'text';
|
|
286
|
+
value: string;
|
|
287
|
+
placeholder?: string;
|
|
288
|
+
ariaLabel?: string;
|
|
289
|
+
/** Milliseconds to batch changes before `onChange` fires; 0 (default) reports every keystroke. */
|
|
290
|
+
debounceMs?: number;
|
|
291
|
+
width?: string;
|
|
292
|
+
minWidth?: string;
|
|
293
|
+
maxWidth?: string;
|
|
294
|
+
disabled?: boolean;
|
|
295
|
+
onChange: (value: string) => void | Promise<void>;
|
|
296
|
+
}
|
|
297
|
+
export type FilterControl = CheckboxFilterControl | RadioFilterControl | DropdownSearchFilterControl | DateRangeFilterControl | NumberRangeFilterControl | FilterButtonControl | FilterLinkControl | FilterSelectControl | DropdownFilterControl | DropdownMultiSelectFilterControl | FilterContainerControl | TextInputFilterControl;
|
|
245
298
|
export interface FilterTableRow {
|
|
246
299
|
key: string;
|
|
247
300
|
title: string;
|
|
@@ -275,5 +328,9 @@ export type NumberRangeFilterDefinition = NumberRangeFilterControl & {
|
|
|
275
328
|
key: string;
|
|
276
329
|
label: string;
|
|
277
330
|
};
|
|
278
|
-
export type
|
|
331
|
+
export type TextInputFilterDefinition = TextInputFilterControl & {
|
|
332
|
+
key: string;
|
|
333
|
+
label: string;
|
|
334
|
+
};
|
|
335
|
+
export type FilterDefinition = CheckboxFilterDefinition | RadioFilterDefinition | DropdownSearchFilterDefinition | DropdownFilterDefinition | DropdownMultiSelectFilterDefinition | DateRangeFilterDefinition | NumberRangeFilterDefinition | TextInputFilterDefinition;
|
|
279
336
|
//# sourceMappingURL=types.d.ts.map
|