@ibobbyts/svelte-ui-utils 0.1.2

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +379 -0
  3. package/dist/data-table/BaseDataTable.svelte +322 -0
  4. package/dist/data-table/BaseDataTable.svelte.d.ts +49 -0
  5. package/dist/data-table/BaseDataTable.svelte.d.ts.map +1 -0
  6. package/dist/data-table/DataTable.svelte +104 -0
  7. package/dist/data-table/DataTable.svelte.d.ts +59 -0
  8. package/dist/data-table/DataTable.svelte.d.ts.map +1 -0
  9. package/dist/data-table/DateRangeFilter.svelte +174 -0
  10. package/dist/data-table/DateRangeFilter.svelte.d.ts +30 -0
  11. package/dist/data-table/DateRangeFilter.svelte.d.ts.map +1 -0
  12. package/dist/data-table/FilterControl.svelte +184 -0
  13. package/dist/data-table/FilterControl.svelte.d.ts +5 -0
  14. package/dist/data-table/FilterControl.svelte.d.ts.map +1 -0
  15. package/dist/data-table/FilterTable.svelte +25 -0
  16. package/dist/data-table/FilterTable.svelte.d.ts +24 -0
  17. package/dist/data-table/FilterTable.svelte.d.ts.map +1 -0
  18. package/dist/data-table/NumberRangeFilter.svelte +80 -0
  19. package/dist/data-table/NumberRangeFilter.svelte.d.ts +32 -0
  20. package/dist/data-table/NumberRangeFilter.svelte.d.ts.map +1 -0
  21. package/dist/data-table/filter.d.ts +23 -0
  22. package/dist/data-table/filter.d.ts.map +1 -0
  23. package/dist/data-table/filter.js +38 -0
  24. package/dist/data-table/index.d.ts +11 -0
  25. package/dist/data-table/index.d.ts.map +1 -0
  26. package/dist/data-table/index.js +8 -0
  27. package/dist/data-table/state.d.ts +11 -0
  28. package/dist/data-table/state.d.ts.map +1 -0
  29. package/dist/data-table/state.js +58 -0
  30. package/dist/data-table/types.d.ts +167 -0
  31. package/dist/data-table/types.d.ts.map +1 -0
  32. package/dist/data-table/types.js +1 -0
  33. package/dist/dropdown/Dropdown.svelte +159 -0
  34. package/dist/dropdown/Dropdown.svelte.d.ts +28 -0
  35. package/dist/dropdown/Dropdown.svelte.d.ts.map +1 -0
  36. package/dist/dropdown/index.d.ts +3 -0
  37. package/dist/dropdown/index.d.ts.map +1 -0
  38. package/dist/dropdown/index.js +1 -0
  39. package/dist/dropdown/types.d.ts +9 -0
  40. package/dist/dropdown/types.d.ts.map +1 -0
  41. package/dist/dropdown/types.js +1 -0
  42. package/dist/dropdown-search/DropdownSearch.svelte +312 -0
  43. package/dist/dropdown-search/DropdownSearch.svelte.d.ts +51 -0
  44. package/dist/dropdown-search/DropdownSearch.svelte.d.ts.map +1 -0
  45. package/dist/dropdown-search/index.d.ts +6 -0
  46. package/dist/dropdown-search/index.d.ts.map +1 -0
  47. package/dist/dropdown-search/index.js +3 -0
  48. package/dist/dropdown-search/state.d.ts +15 -0
  49. package/dist/dropdown-search/state.d.ts.map +1 -0
  50. package/dist/dropdown-search/state.js +44 -0
  51. package/dist/dropdown-search/types.d.ts +24 -0
  52. package/dist/dropdown-search/types.d.ts.map +1 -0
  53. package/dist/dropdown-search/types.js +1 -0
  54. package/dist/i18n.d.ts +31 -0
  55. package/dist/i18n.d.ts.map +1 -0
  56. package/dist/i18n.js +118 -0
  57. package/dist/index.d.ts +7 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +5 -0
  60. package/dist/pagination/Pagination.svelte +112 -0
  61. package/dist/pagination/Pagination.svelte.d.ts +30 -0
  62. package/dist/pagination/Pagination.svelte.d.ts.map +1 -0
  63. package/dist/pagination/index.d.ts +6 -0
  64. package/dist/pagination/index.d.ts.map +1 -0
  65. package/dist/pagination/index.js +3 -0
  66. package/dist/style.css +1110 -0
  67. package/dist/toast/Toast.svelte +37 -0
  68. package/dist/toast/Toast.svelte.d.ts +26 -0
  69. package/dist/toast/Toast.svelte.d.ts.map +1 -0
  70. package/dist/toast/ToastManager.svelte +29 -0
  71. package/dist/toast/ToastManager.svelte.d.ts +26 -0
  72. package/dist/toast/ToastManager.svelte.d.ts.map +1 -0
  73. package/dist/toast/index.d.ts +7 -0
  74. package/dist/toast/index.d.ts.map +1 -0
  75. package/dist/toast/index.js +4 -0
  76. package/dist/toast/store.d.ts +7 -0
  77. package/dist/toast/store.d.ts.map +1 -0
  78. package/dist/toast/store.js +114 -0
  79. package/dist/toast/types.d.ts +36 -0
  80. package/dist/toast/types.d.ts.map +1 -0
  81. package/dist/toast/types.js +1 -0
  82. package/package.json +83 -0
@@ -0,0 +1,312 @@
1
+ <script lang="ts">
2
+ import { onDestroy, onMount } from 'svelte';
3
+ import { getUiMessages, type UiLanguage } from '../i18n.js';
4
+ import { formatParamDict, normalizeDropdownSearchValue, resolveDropdownSearchStatus } from './state.js';
5
+ import type {
6
+ DropdownSearchChangeDetail,
7
+ DropdownSearchItem,
8
+ DropdownSearchItemValueGetter,
9
+ DropdownSearchLoadOptions,
10
+ DropdownSearchStatus
11
+ } from './types.js';
12
+
13
+ export let value = '';
14
+ export let selectedItem: DropdownSearchItem | null = null;
15
+ export let status: DropdownSearchStatus = 'empty';
16
+ export let placeholder = '';
17
+ export let debounceMs = 500;
18
+ export let limit = 10;
19
+ export let minLength = 1;
20
+ export let validate = true;
21
+ export let loadOptions: DropdownSearchLoadOptions;
22
+ export let id: string | undefined = undefined;
23
+ export let name: string | undefined = undefined;
24
+ export let ariaLabel: string | undefined = undefined;
25
+ export let listboxId: string | undefined = undefined;
26
+ export let disabled = false;
27
+ export let language: UiLanguage = 'en_us';
28
+ export let noResultsText: string | undefined = undefined;
29
+ export let loadingText: string | undefined = undefined;
30
+ export let clearLabel: string | undefined = undefined;
31
+ export let searchOnExternalValueChange = false;
32
+ export let width: string | undefined = undefined;
33
+ export let minWidth: string | undefined = undefined;
34
+ export let maxWidth: string | undefined = undefined;
35
+ export let getItemValue: DropdownSearchItemValueGetter = (item) => item.title;
36
+ export let onChange: ((detail: DropdownSearchChangeDetail) => void) | undefined = undefined;
37
+ export let onSelect: ((item: DropdownSearchItem) => void) | undefined = undefined;
38
+ export let onStatusChange: ((status: DropdownSearchStatus) => void) | undefined = undefined;
39
+ export let onInputBlur: ((event: FocusEvent) => void) | undefined = undefined;
40
+
41
+ let options: DropdownSearchItem[] = [];
42
+ let exactMatch: DropdownSearchItem | null = null;
43
+ let focused = false;
44
+ let inputElement: HTMLInputElement | undefined;
45
+ let searchTimer: ReturnType<typeof setTimeout> | undefined;
46
+ let activeController: AbortController | undefined;
47
+ let requestId = 0;
48
+ let lastHandledValue = value;
49
+
50
+ $: messages = getUiMessages(language);
51
+ $: resolvedNoResultsText = noResultsText?.trim() ? noResultsText : messages.dropdownSearch.noResultsText;
52
+ $: resolvedLoadingText = loadingText?.trim() ? loadingText : messages.dropdownSearch.loadingText;
53
+ $: resolvedClearLabel = clearLabel?.trim() ? clearLabel : messages.dropdownSearch.clearLabel;
54
+ $: resolvedListboxId = listboxId ?? (id ? `${id}-options` : undefined);
55
+ $: hasQuery = normalizeDropdownSearchValue(value).length > 0;
56
+ $: showOptions = focused && !disabled && (options.length > 0 || status === 'loading' || (hasQuery && status === 'invalid'));
57
+ $: if (!validate && status !== 'empty' && status !== 'loading') {
58
+ setStatus('empty');
59
+ }
60
+ $: if (searchOnExternalValueChange && value !== lastHandledValue) {
61
+ handleExternalValue(value);
62
+ }
63
+
64
+ function emitChange() {
65
+ const detail = { value, selectedItem, status };
66
+ onChange?.(detail);
67
+ }
68
+
69
+ function setStatus(nextStatus: DropdownSearchStatus) {
70
+ if (status !== nextStatus) {
71
+ status = nextStatus;
72
+ onStatusChange?.(status);
73
+ }
74
+ }
75
+
76
+ function resetSearchState(nextValue: string) {
77
+ lastHandledValue = nextValue;
78
+ value = nextValue;
79
+ selectedItem = null;
80
+ exactMatch = null;
81
+ options = [];
82
+ const trimmed = normalizeDropdownSearchValue(nextValue);
83
+ if (trimmed && trimmed.length >= minLength) {
84
+ abortActiveSearch();
85
+ setStatus('loading');
86
+ } else {
87
+ abortActiveSearch();
88
+ setStatus(resolveDropdownSearchStatus({ value, selectedItem, exactMatch, minLength, validate }));
89
+ }
90
+ emitChange();
91
+ }
92
+
93
+ function clearSearchTimer() {
94
+ if (searchTimer) {
95
+ clearTimeout(searchTimer);
96
+ searchTimer = undefined;
97
+ }
98
+ }
99
+
100
+ function abortActiveSearch() {
101
+ if (activeController) {
102
+ activeController.abort();
103
+ activeController = undefined;
104
+ }
105
+ }
106
+
107
+ async function runSearch(query: string) {
108
+ const trimmed = normalizeDropdownSearchValue(query);
109
+
110
+ if (!trimmed || trimmed.length < minLength) {
111
+ abortActiveSearch();
112
+ options = [];
113
+ exactMatch = null;
114
+ setStatus(resolveDropdownSearchStatus({ value: query, minLength, validate }));
115
+ emitChange();
116
+ return;
117
+ }
118
+
119
+ abortActiveSearch();
120
+ const currentRequestId = ++requestId;
121
+ const controller = new AbortController();
122
+ activeController = controller;
123
+ setStatus('loading');
124
+ emitChange();
125
+
126
+ try {
127
+ const result = await loadOptions(trimmed, { limit, signal: controller.signal });
128
+
129
+ if (controller.signal.aborted || currentRequestId !== requestId) {
130
+ return;
131
+ }
132
+
133
+ options = result.options ?? [];
134
+ exactMatch = validate ? (result.exactMatch ?? null) : null;
135
+ selectedItem = validate && exactMatch && !exactMatch.disabled ? exactMatch : null;
136
+ setStatus(resolveDropdownSearchStatus({ value, selectedItem, exactMatch, minLength, validate }));
137
+ emitChange();
138
+ } catch (error) {
139
+ if (controller.signal.aborted || currentRequestId !== requestId) {
140
+ return;
141
+ }
142
+
143
+ options = [];
144
+ exactMatch = null;
145
+ selectedItem = null;
146
+ setStatus(resolveDropdownSearchStatus({ value: query, errored: true, minLength, validate }));
147
+ emitChange();
148
+ } finally {
149
+ if (activeController === controller) {
150
+ activeController = undefined;
151
+ }
152
+ }
153
+ }
154
+
155
+ function scheduleSearch(query: string) {
156
+ clearSearchTimer();
157
+ searchTimer = setTimeout(() => {
158
+ void runSearch(query);
159
+ }, debounceMs);
160
+ }
161
+
162
+ function handleInput(event: Event) {
163
+ const input = event.currentTarget as HTMLInputElement;
164
+ resetSearchState(input.value);
165
+ scheduleSearch(input.value);
166
+ }
167
+
168
+ function selectItem(item: DropdownSearchItem) {
169
+ if (item.disabled) {
170
+ return;
171
+ }
172
+
173
+ clearSearchTimer();
174
+ abortActiveSearch();
175
+ selectedItem = item;
176
+ exactMatch = validate ? item : null;
177
+ value = getItemValue(item);
178
+ lastHandledValue = value;
179
+ setStatus(validate ? 'valid' : 'empty');
180
+ focused = false;
181
+ emitChange();
182
+ onSelect?.(item);
183
+ }
184
+
185
+ function clearSearch() {
186
+ if (!hasQuery || disabled) {
187
+ return;
188
+ }
189
+
190
+ clearSearchTimer();
191
+ abortActiveSearch();
192
+ value = '';
193
+ lastHandledValue = value;
194
+ selectedItem = null;
195
+ exactMatch = null;
196
+ options = [];
197
+ setStatus(resolveDropdownSearchStatus({ value, selectedItem, exactMatch, minLength, validate }));
198
+ focused = true;
199
+ emitChange();
200
+ inputElement?.focus();
201
+ }
202
+
203
+ function handleExternalValue(nextValue: string) {
204
+ lastHandledValue = nextValue;
205
+ selectedItem = null;
206
+ exactMatch = null;
207
+ options = [];
208
+
209
+ clearSearchTimer();
210
+ if (!normalizeDropdownSearchValue(nextValue) || normalizeDropdownSearchValue(nextValue).length < minLength) {
211
+ setStatus(resolveDropdownSearchStatus({ value: nextValue, selectedItem, exactMatch, minLength, validate }));
212
+ emitChange();
213
+ return;
214
+ }
215
+
216
+ void runSearch(nextValue);
217
+ }
218
+
219
+ onDestroy(() => {
220
+ clearSearchTimer();
221
+ abortActiveSearch();
222
+ });
223
+
224
+ onMount(() => {
225
+ if (searchOnExternalValueChange && normalizeDropdownSearchValue(value)) {
226
+ handleExternalValue(value);
227
+ }
228
+ });
229
+ </script>
230
+
231
+ <div
232
+ class={`suu-dropdown-search suu-dropdown-search--${status}`}
233
+ class:suu-dropdown-search--has-clear={hasQuery && !disabled}
234
+ data-status={status}
235
+ style:width
236
+ style:min-width={minWidth}
237
+ style:max-width={maxWidth}
238
+ >
239
+ <div class="suu-dropdown-search__field">
240
+ <svg class="suu-dropdown-search__icon" viewBox="0 0 24 24" aria-hidden="true">
241
+ <circle cx="11" cy="11" r="7"></circle>
242
+ <path d="m16 16 4 4"></path>
243
+ </svg>
244
+ <input
245
+ bind:this={inputElement}
246
+ class="suu-dropdown-search__input"
247
+ {id}
248
+ {name}
249
+ {value}
250
+ {placeholder}
251
+ aria-label={ariaLabel}
252
+ {disabled}
253
+ autocomplete="off"
254
+ aria-autocomplete="list"
255
+ aria-controls={resolvedListboxId}
256
+ aria-expanded={showOptions}
257
+ aria-invalid={status === 'invalid' || status === 'error'}
258
+ on:input={handleInput}
259
+ on:focus={() => (focused = true)}
260
+ on:blur={(event) => {
261
+ onInputBlur?.(event);
262
+ setTimeout(() => (focused = false), 120);
263
+ }}
264
+ />
265
+ {#if hasQuery && !disabled}
266
+ <button
267
+ type="button"
268
+ class="suu-dropdown-search__clear"
269
+ aria-label={resolvedClearLabel}
270
+ title={resolvedClearLabel}
271
+ on:mousedown|preventDefault
272
+ on:click={clearSearch}
273
+ >
274
+ <svg viewBox="0 0 20 20" aria-hidden="true">
275
+ <path d="m6 6 8 8M14 6l-8 8"></path>
276
+ </svg>
277
+ </button>
278
+ {/if}
279
+ </div>
280
+
281
+ {#if showOptions}
282
+ <div class="suu-dropdown-search__menu">
283
+ <div class="suu-dropdown-search__menu-panel" id={resolvedListboxId} role="listbox">
284
+ {#if status === 'loading'}
285
+ <div class="suu-dropdown-search__empty suu-dropdown-search__empty--loading" aria-live="polite">
286
+ <span class="suu-dropdown-search__spinner" aria-hidden="true"></span>
287
+ <span>{resolvedLoadingText}</span>
288
+ </div>
289
+ {:else if options.length > 0}
290
+ {#each options as option (option.id)}
291
+ <button
292
+ type="button"
293
+ class="suu-dropdown-search__option"
294
+ class:suu-dropdown-search__option--disabled={option.disabled}
295
+ role="option"
296
+ aria-selected={selectedItem?.id === option.id}
297
+ disabled={option.disabled}
298
+ on:mousedown|preventDefault={() => selectItem(option)}
299
+ >
300
+ <span class="suu-dropdown-search__title">{option.title}</span>
301
+ {#if formatParamDict(option.param_dict).length > 0}
302
+ <span class="suu-dropdown-search__meta">{formatParamDict(option.param_dict).join(' · ')}</span>
303
+ {/if}
304
+ </button>
305
+ {/each}
306
+ {:else}
307
+ <div class="suu-dropdown-search__empty">{resolvedNoResultsText}</div>
308
+ {/if}
309
+ </div>
310
+ </div>
311
+ {/if}
312
+ </div>
@@ -0,0 +1,51 @@
1
+ import { type UiLanguage } from '../i18n.js';
2
+ import type { DropdownSearchChangeDetail, DropdownSearchItem, DropdownSearchItemValueGetter, DropdownSearchLoadOptions, DropdownSearchStatus } from './types.js';
3
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
+ $$bindings?: Bindings;
6
+ } & Exports;
7
+ (internal: unknown, props: Props & {
8
+ $$events?: Events;
9
+ $$slots?: Slots;
10
+ }): Exports & {
11
+ $set?: any;
12
+ $on?: any;
13
+ };
14
+ z_$$bindings?: Bindings;
15
+ }
16
+ declare const DropdownSearch: $$__sveltets_2_IsomorphicComponent<{
17
+ value?: string;
18
+ selectedItem?: DropdownSearchItem | null;
19
+ status?: DropdownSearchStatus;
20
+ placeholder?: string;
21
+ debounceMs?: number;
22
+ limit?: number;
23
+ minLength?: number;
24
+ validate?: boolean;
25
+ loadOptions: DropdownSearchLoadOptions;
26
+ id?: string | undefined;
27
+ name?: string | undefined;
28
+ ariaLabel?: string | undefined;
29
+ listboxId?: string | undefined;
30
+ disabled?: boolean;
31
+ language?: UiLanguage;
32
+ noResultsText?: string | undefined;
33
+ loadingText?: string | undefined;
34
+ clearLabel?: string | undefined;
35
+ searchOnExternalValueChange?: boolean;
36
+ width?: string | undefined;
37
+ minWidth?: string | undefined;
38
+ maxWidth?: string | undefined;
39
+ getItemValue?: DropdownSearchItemValueGetter;
40
+ onChange?: ((detail: DropdownSearchChangeDetail) => void) | undefined;
41
+ onSelect?: ((item: DropdownSearchItem) => void) | undefined;
42
+ onStatusChange?: ((status: DropdownSearchStatus) => void) | undefined;
43
+ onInputBlur?: ((event: FocusEvent) => void) | undefined;
44
+ }, {
45
+ mousedown: MouseEvent;
46
+ } & {
47
+ [evt: string]: CustomEvent<any>;
48
+ }, {}, {}, string>;
49
+ type DropdownSearch = InstanceType<typeof DropdownSearch>;
50
+ export default DropdownSearch;
51
+ //# sourceMappingURL=DropdownSearch.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropdownSearch.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown-search/DropdownSearch.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EACR,0BAA0B,EAC1B,kBAAkB,EAClB,6BAA6B,EAC7B,yBAAyB,EACzB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAgRtB,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,cAAc;;mBAVoqB,kBAAkB,GAAG,IAAI;aAAW,oBAAoB;;;;;;iBAAiK,yBAAyB;SAAO,MAAM,GAAG,SAAS;WAAS,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;gBAAc,MAAM,GAAG,SAAS;;eAAyC,UAAU;oBAAkB,MAAM,GAAG,SAAS;kBAAgB,MAAM,GAAG,SAAS;iBAAe,MAAM,GAAG,SAAS;;YAA4E,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;eAAa,MAAM,GAAG,SAAS;mBAAiB,6BAA6B;eAAa,CAAC,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,CAAC,GAAG,SAAS;eAAa,CAAC,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAAG,SAAS;qBAAmB,CAAC,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,SAAS;kBAAgB,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS;;;;;kBAUniD,CAAC;AAClF,KAAK,cAAc,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC;AAC5D,eAAe,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { default as DropdownSearch } from './DropdownSearch.svelte';
2
+ export { getUiMessages, resolveUiLanguage, uiLanguages } from '../i18n.js';
3
+ export { clampDropdownSearchLimit, formatParamDict, isUsableExactMatch, normalizeDropdownSearchValue, resolveDropdownSearchStatus } from './state.js';
4
+ export type { UiLanguage, UiMessages } from '../i18n.js';
5
+ export type { DropdownSearchChangeDetail, DropdownSearchItem, DropdownSearchItemValueGetter, DropdownSearchLoadContext, DropdownSearchLoadOptions, DropdownSearchResult, DropdownSearchStatus } from './types.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,kBAAkB,EAClB,4BAA4B,EAC5B,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as DropdownSearch } from './DropdownSearch.svelte';
2
+ export { getUiMessages, resolveUiLanguage, uiLanguages } from '../i18n.js';
3
+ export { clampDropdownSearchLimit, formatParamDict, isUsableExactMatch, normalizeDropdownSearchValue, resolveDropdownSearchStatus } from './state.js';
@@ -0,0 +1,15 @@
1
+ import type { DropdownSearchItem, DropdownSearchStatus } from './types.js';
2
+ export declare function normalizeDropdownSearchValue(value: string): string;
3
+ export declare function clampDropdownSearchLimit(limit: number): number;
4
+ export declare function isUsableExactMatch(item: DropdownSearchItem | null | undefined): item is DropdownSearchItem;
5
+ export declare function resolveDropdownSearchStatus(params: {
6
+ value: string;
7
+ selectedItem?: DropdownSearchItem | null;
8
+ exactMatch?: DropdownSearchItem | null;
9
+ loading?: boolean;
10
+ errored?: boolean;
11
+ minLength?: number;
12
+ validate?: boolean;
13
+ }): DropdownSearchStatus;
14
+ export declare function formatParamDict(paramDict: DropdownSearchItem['param_dict']): string[];
15
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown-search/state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE3E,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,IAAI,kBAAkB,CAE1G;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,oBAAoB,CA8BvB;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,kBAAkB,CAAC,YAAY,CAAC,GAAG,MAAM,EAAE,CAQrF"}
@@ -0,0 +1,44 @@
1
+ export function normalizeDropdownSearchValue(value) {
2
+ return value.trim();
3
+ }
4
+ export function clampDropdownSearchLimit(limit) {
5
+ if (!Number.isFinite(limit)) {
6
+ return 10;
7
+ }
8
+ return Math.min(50, Math.max(1, Math.floor(limit)));
9
+ }
10
+ export function isUsableExactMatch(item) {
11
+ return Boolean(item && !item.disabled);
12
+ }
13
+ export function resolveDropdownSearchStatus(params) {
14
+ const trimmed = normalizeDropdownSearchValue(params.value);
15
+ const minLength = params.minLength ?? 1;
16
+ const validate = params.validate ?? true;
17
+ if (!trimmed) {
18
+ return 'empty';
19
+ }
20
+ if (params.loading) {
21
+ return 'loading';
22
+ }
23
+ if (!validate) {
24
+ return 'empty';
25
+ }
26
+ if (params.errored) {
27
+ return 'error';
28
+ }
29
+ if (trimmed.length < minLength) {
30
+ return 'invalid';
31
+ }
32
+ if (isUsableExactMatch(params.selectedItem) || isUsableExactMatch(params.exactMatch)) {
33
+ return 'valid';
34
+ }
35
+ return 'invalid';
36
+ }
37
+ export function formatParamDict(paramDict) {
38
+ if (!paramDict) {
39
+ return [];
40
+ }
41
+ return Object.entries(paramDict)
42
+ .filter(([, value]) => value !== null && value !== undefined && value !== '')
43
+ .map(([key, value]) => `${key}: ${value}`);
44
+ }
@@ -0,0 +1,24 @@
1
+ export type DropdownSearchStatus = 'empty' | 'loading' | 'valid' | 'invalid' | 'error';
2
+ export interface DropdownSearchItem {
3
+ id: string | number;
4
+ title: string;
5
+ param_dict?: Record<string, string | number | null>;
6
+ disabled?: boolean;
7
+ [key: string]: unknown;
8
+ }
9
+ export interface DropdownSearchLoadContext {
10
+ limit: number;
11
+ signal: AbortSignal;
12
+ }
13
+ export interface DropdownSearchResult {
14
+ options: DropdownSearchItem[];
15
+ exactMatch?: DropdownSearchItem | null;
16
+ }
17
+ export type DropdownSearchLoadOptions = (query: string, context: DropdownSearchLoadContext) => Promise<DropdownSearchResult> | DropdownSearchResult;
18
+ export interface DropdownSearchChangeDetail {
19
+ value: string;
20
+ selectedItem: DropdownSearchItem | null;
21
+ status: DropdownSearchStatus;
22
+ }
23
+ export type DropdownSearchItemValueGetter = (item: DropdownSearchItem) => string;
24
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/dropdown-search/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAEvF,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACxC;AAED,MAAM,MAAM,yBAAyB,GAAG,CACtC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,yBAAyB,KAC/B,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;AAE1D,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACxC,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,MAAM,6BAA6B,GAAG,CAAC,IAAI,EAAE,kBAAkB,KAAK,MAAM,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ export declare const uiLanguages: readonly ["en_us", "zh_cn", "zh_tw"];
2
+ export type UiLanguage = (typeof uiLanguages)[number];
3
+ type DateRangePresetKey = 'last24Hours' | 'last7Days' | 'last30Days' | 'today' | 'thisWeek' | 'thisMonth' | 'thisYear';
4
+ export interface UiMessages {
5
+ toast: {
6
+ closeLabel: string;
7
+ };
8
+ dropdownSearch: {
9
+ noResultsText: string;
10
+ loadingText: string;
11
+ clearLabel: string;
12
+ };
13
+ table: {
14
+ emptyText: string;
15
+ pageSizeLabel: string;
16
+ paginationLabel: string;
17
+ };
18
+ dateRange: {
19
+ startLabel: string;
20
+ endLabel: string;
21
+ presetLabels: Record<DateRangePresetKey, string>;
22
+ };
23
+ numberRange: {
24
+ minLabel: string;
25
+ maxLabel: string;
26
+ };
27
+ }
28
+ export declare function resolveUiLanguage(language: UiLanguage | string | null | undefined): UiLanguage;
29
+ export declare function getUiMessages(language: UiLanguage | string | null | undefined): UiMessages;
30
+ export {};
31
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/lib/i18n.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,sCAAuC,CAAC;AAEhE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,KAAK,kBAAkB,GACnB,aAAa,GACb,WAAW,GACX,YAAY,GACZ,OAAO,GACP,UAAU,GACV,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,cAAc,EAAE;QACd,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,SAAS,EAAE;QACT,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;KAClD,CAAC;IACF,WAAW,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAqGD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAiB9F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,CAE1F"}
package/dist/i18n.js ADDED
@@ -0,0 +1,118 @@
1
+ export const uiLanguages = ['en_us', 'zh_cn', 'zh_tw'];
2
+ const messages = {
3
+ en_us: {
4
+ toast: {
5
+ closeLabel: 'Close notification'
6
+ },
7
+ dropdownSearch: {
8
+ noResultsText: 'Empty',
9
+ loadingText: 'Loading...',
10
+ clearLabel: 'Clear'
11
+ },
12
+ table: {
13
+ emptyText: 'No records',
14
+ pageSizeLabel: 'Rows',
15
+ paginationLabel: 'Pagination'
16
+ },
17
+ dateRange: {
18
+ startLabel: 'Start date',
19
+ endLabel: 'End date',
20
+ presetLabels: {
21
+ last24Hours: 'Last 24 Hours',
22
+ last7Days: 'Last 7 Days',
23
+ last30Days: 'Last 30 Days',
24
+ today: 'Today',
25
+ thisWeek: 'This Week',
26
+ thisMonth: 'This Month',
27
+ thisYear: 'This Year'
28
+ }
29
+ },
30
+ numberRange: {
31
+ minLabel: 'Min',
32
+ maxLabel: 'Max'
33
+ }
34
+ },
35
+ zh_cn: {
36
+ toast: {
37
+ closeLabel: '关闭通知'
38
+ },
39
+ dropdownSearch: {
40
+ noResultsText: '空',
41
+ loadingText: '搜索中...',
42
+ clearLabel: '清除'
43
+ },
44
+ table: {
45
+ emptyText: '暂无记录',
46
+ pageSizeLabel: '每页',
47
+ paginationLabel: '分页'
48
+ },
49
+ dateRange: {
50
+ startLabel: '开始日期',
51
+ endLabel: '结束日期',
52
+ presetLabels: {
53
+ last24Hours: '过去 24 小时',
54
+ last7Days: '过去 7 天',
55
+ last30Days: '过去 30 天',
56
+ today: '今天',
57
+ thisWeek: '本周',
58
+ thisMonth: '本月',
59
+ thisYear: '今年'
60
+ }
61
+ },
62
+ numberRange: {
63
+ minLabel: '最小值',
64
+ maxLabel: '最大值'
65
+ }
66
+ },
67
+ zh_tw: {
68
+ toast: {
69
+ closeLabel: '關閉通知'
70
+ },
71
+ dropdownSearch: {
72
+ noResultsText: '空',
73
+ loadingText: '搜尋中...',
74
+ clearLabel: '清除'
75
+ },
76
+ table: {
77
+ emptyText: '暫無記錄',
78
+ pageSizeLabel: '每頁',
79
+ paginationLabel: '分頁'
80
+ },
81
+ dateRange: {
82
+ startLabel: '開始日期',
83
+ endLabel: '結束日期',
84
+ presetLabels: {
85
+ last24Hours: '過去 24 小時',
86
+ last7Days: '過去 7 天',
87
+ last30Days: '過去 30 天',
88
+ today: '今天',
89
+ thisWeek: '本週',
90
+ thisMonth: '本月',
91
+ thisYear: '今年'
92
+ }
93
+ },
94
+ numberRange: {
95
+ minLabel: '最小值',
96
+ maxLabel: '最大值'
97
+ }
98
+ }
99
+ };
100
+ export function resolveUiLanguage(language) {
101
+ if (!language) {
102
+ return 'en_us';
103
+ }
104
+ const normalized = language.trim().toLowerCase().replaceAll('-', '_');
105
+ if (normalized === 'zh' || normalized === 'zh_cn' || normalized === 'zh_hans') {
106
+ return 'zh_cn';
107
+ }
108
+ if (normalized === 'zh_tw' || normalized === 'zh_hant' || normalized === 'zh_hk') {
109
+ return 'zh_tw';
110
+ }
111
+ if (normalized === 'en' || normalized === 'en_us') {
112
+ return 'en_us';
113
+ }
114
+ return 'en_us';
115
+ }
116
+ export function getUiMessages(language) {
117
+ return messages[resolveUiLanguage(language)];
118
+ }
@@ -0,0 +1,7 @@
1
+ export * from './toast/index.js';
2
+ export * from './dropdown/index.js';
3
+ export * from './dropdown-search/index.js';
4
+ export * from './data-table/index.js';
5
+ export { getUiMessages, resolveUiLanguage, uiLanguages } from './i18n.js';
6
+ export type { UiLanguage, UiMessages } from './i18n.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC1E,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './toast/index.js';
2
+ export * from './dropdown/index.js';
3
+ export * from './dropdown-search/index.js';
4
+ export * from './data-table/index.js';
5
+ export { getUiMessages, resolveUiLanguage, uiLanguages } from './i18n.js';