mertani-web-toolkit 0.1.58 → 0.1.60

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.
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { onMount, onDestroy, tick, getContext } from 'svelte';
3
3
  import type { IFieldOption } from './SelectInput.js';
4
- import Icon from '../../Icon/Icon.svelte';
4
+ import { Icon } from 'mertani-web-toolkit';
5
5
  import './SelectInput.css';
6
6
 
7
7
  interface Props {
@@ -32,9 +32,15 @@
32
32
  searchPlaceholder?: string;
33
33
  emptyMessage?: string;
34
34
  searchable?: boolean;
35
+ /** Jika true: opsi tidak difilter di klien (hasil dari server); ketikan di search memicu onSearchQueryChange (debounced). */
36
+ remoteSearch?: boolean;
35
37
 
36
38
  // Events
37
39
  onSelect?: (val: string) => void;
40
+ /** Dipanggil saat dropdown baru dibuka (klik trigger). */
41
+ onOpen?: () => void;
42
+ /** Dipanggil saat teks search berubah (debounce 300ms), hanya jika remoteSearch. */
43
+ onSearchQueryChange?: (query: string) => void;
38
44
 
39
45
  // Validation
40
46
  isMandatory?: boolean;
@@ -79,9 +85,12 @@
79
85
  searchPlaceholder = 'Cari',
80
86
  emptyMessage = 'Tidak ada hasil',
81
87
  searchable = true,
88
+ remoteSearch = false,
82
89
 
83
90
  // Events
84
91
  onSelect,
92
+ onOpen,
93
+ onSearchQueryChange,
85
94
 
86
95
  // Validation
87
96
  isMandatory = false,
@@ -116,8 +125,19 @@
116
125
  let menuEl: HTMLDivElement | null = $state(null);
117
126
  let resizeObs: ResizeObserver | null = $state(null);
118
127
  let unregisterDropdown: (() => void) | null = $state(null);
128
+ // eslint-disable-next-line svelte/prefer-writable-derived
119
129
  let error = $state('');
120
130
  let isFocused = $state(false);
131
+ let searchNotifyTimer: ReturnType<typeof setTimeout> | null = null;
132
+
133
+ function scheduleSearchQueryNotify() {
134
+ if (!remoteSearch || !onSearchQueryChange) return;
135
+ if (searchNotifyTimer) clearTimeout(searchNotifyTimer);
136
+ searchNotifyTimer = setTimeout(() => {
137
+ searchNotifyTimer = null;
138
+ onSearchQueryChange?.(search);
139
+ }, 500);
140
+ }
121
141
 
122
142
  // Validate on value changes
123
143
  $effect(() => {
@@ -203,6 +223,7 @@
203
223
 
204
224
  // ===== Derived Values =====
205
225
  const filteredOptions = $derived(() => {
226
+ if (remoteSearch) return options;
206
227
  if (!search) return options;
207
228
  const query = normalize(search);
208
229
  return options.filter((o) => normalize(getLabel(o)).includes(query));
@@ -237,6 +258,7 @@
237
258
  }
238
259
  open = !open;
239
260
  if (open) {
261
+ onOpen?.();
240
262
  void afterOpen();
241
263
  }
242
264
  }
@@ -251,6 +273,10 @@
251
273
  }
252
274
 
253
275
  function close() {
276
+ if (searchNotifyTimer) {
277
+ clearTimeout(searchNotifyTimer);
278
+ searchNotifyTimer = null;
279
+ }
254
280
  open = false;
255
281
  search = ''; // Reset search when closing
256
282
  }
@@ -346,6 +372,7 @@
346
372
  });
347
373
 
348
374
  onDestroy(() => {
375
+ if (searchNotifyTimer) clearTimeout(searchNotifyTimer);
349
376
  window.removeEventListener('resize', onWindowChange);
350
377
  window.removeEventListener('scroll', onWindowChange, true);
351
378
  resizeObs?.disconnect();
@@ -409,6 +436,7 @@
409
436
  placeholder={searchPlaceholder}
410
437
  bind:value={search}
411
438
  class="search-input"
439
+ oninput={scheduleSearchQueryNotify}
412
440
  />
413
441
  <span class="search-icon">
414
442
  <Icon name="bs-search" />
@@ -444,6 +472,7 @@
444
472
  placeholder={searchPlaceholder}
445
473
  bind:value={search}
446
474
  class="search-input"
475
+ oninput={scheduleSearchQueryNotify}
447
476
  />
448
477
  <span class="search-icon">
449
478
  <Icon name="bs-search" />
@@ -21,7 +21,13 @@ interface Props {
21
21
  searchPlaceholder?: string;
22
22
  emptyMessage?: string;
23
23
  searchable?: boolean;
24
+ /** Jika true: opsi tidak difilter di klien (hasil dari server); ketikan di search memicu onSearchQueryChange (debounced). */
25
+ remoteSearch?: boolean;
24
26
  onSelect?: (val: string) => void;
27
+ /** Dipanggil saat dropdown baru dibuka (klik trigger). */
28
+ onOpen?: () => void;
29
+ /** Dipanggil saat teks search berubah (debounce 300ms), hanya jika remoteSearch. */
30
+ onSearchQueryChange?: (query: string) => void;
25
31
  isMandatory?: boolean;
26
32
  customValidation?: (value: string) => string | null;
27
33
  isLoading?: boolean;
@@ -114,7 +114,7 @@
114
114
  isShow = true,
115
115
  disabled = false,
116
116
  readOnly = false,
117
- clearable = true,
117
+ clearable = false,
118
118
  tooltip = '',
119
119
 
120
120
  class: className = '',
@@ -1,16 +1,16 @@
1
- <svg
2
- width="16"
3
- height="16"
4
- viewBox="0 0 16 16"
5
- fill="currentColor"
6
- xmlns="http://www.w3.org/2000/svg"
7
- >
8
- <path
9
- d="M5.884 6.68C5.84256 6.62777 5.79109 6.58436 5.73263 6.55232C5.67416 6.52027 5.60988 6.50025 5.54356 6.49341C5.47724 6.48658 5.41022 6.49308 5.34645 6.51253C5.28268 6.53198 5.22344 6.56399 5.17223 6.60667C5.12101 6.64935 5.07884 6.70185 5.04821 6.76106C5.01758 6.82028 4.9991 6.88503 4.99386 6.95149C4.98863 7.01796 4.99673 7.0848 5.01771 7.14808C5.03868 7.21137 5.0721 7.26982 5.116 7.32L7.349 10L5.116 12.68C5.03487 12.7823 4.99694 12.9122 5.01032 13.042C5.02369 13.1719 5.08731 13.2913 5.18759 13.3749C5.28787 13.4585 5.41684 13.4995 5.54697 13.4892C5.6771 13.479 5.79805 13.4182 5.884 13.32L8 10.781L10.116 13.321C10.201 13.4228 10.323 13.4867 10.4551 13.4987C10.5205 13.5046 10.5865 13.4975 10.6492 13.4779C10.7118 13.4583 10.7701 13.4266 10.8205 13.3845C10.8709 13.3424 10.9126 13.2908 10.9431 13.2326C10.9735 13.1744 10.9923 13.1108 10.9982 13.0454C11.0041 12.98 10.997 12.914 10.9774 12.8513C10.9578 12.7887 10.9261 12.7304 10.884 12.68L8.651 10L10.884 7.32C10.9651 7.21775 11.0031 7.08782 10.9897 6.95798C10.9763 6.82814 10.9127 6.70867 10.8124 6.62511C10.7121 6.54154 10.5832 6.50051 10.453 6.51076C10.3229 6.52102 10.2019 6.58176 10.116 6.68L8 9.219L5.884 6.68Z"
10
- fill="currentColor"
11
- />
12
- <path
13
- d="M14 14V4.5L9.5 0H4C3.46957 0 2.96086 0.210714 2.58579 0.585786C2.21071 0.960859 2 1.46957 2 2V14C2 14.5304 2.21071 15.0391 2.58579 15.4142C2.96086 15.7893 3.46957 16 4 16H12C12.5304 16 13.0391 15.7893 13.4142 15.4142C13.7893 15.0391 14 14.5304 14 14ZM9.5 3C9.5 3.39782 9.65804 3.77936 9.93934 4.06066C10.2206 4.34196 10.6022 4.5 11 4.5H13V14C13 14.2652 12.8946 14.5196 12.7071 14.7071C12.5196 14.8946 12.2652 15 12 15H4C3.73478 15 3.48043 14.8946 3.29289 14.7071C3.10536 14.5196 3 14.2652 3 14V2C3 1.73478 3.10536 1.48043 3.29289 1.29289C3.48043 1.10536 3.73478 1 4 1H9.5V3Z"
14
- fill="currentColor"
15
- />
16
- </svg>
1
+ <svg
2
+ width="16"
3
+ height="16"
4
+ viewBox="0 0 16 16"
5
+ fill="currentColor"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ >
8
+ <path
9
+ d="M5.884 6.68C5.84256 6.62777 5.79109 6.58436 5.73263 6.55232C5.67416 6.52027 5.60988 6.50025 5.54356 6.49341C5.47724 6.48658 5.41022 6.49308 5.34645 6.51253C5.28268 6.53198 5.22344 6.56399 5.17223 6.60667C5.12101 6.64935 5.07884 6.70185 5.04821 6.76106C5.01758 6.82028 4.9991 6.88503 4.99386 6.95149C4.98863 7.01796 4.99673 7.0848 5.01771 7.14808C5.03868 7.21137 5.0721 7.26982 5.116 7.32L7.349 10L5.116 12.68C5.03487 12.7823 4.99694 12.9122 5.01032 13.042C5.02369 13.1719 5.08731 13.2913 5.18759 13.3749C5.28787 13.4585 5.41684 13.4995 5.54697 13.4892C5.6771 13.479 5.79805 13.4182 5.884 13.32L8 10.781L10.116 13.321C10.201 13.4228 10.323 13.4867 10.4551 13.4987C10.5205 13.5046 10.5865 13.4975 10.6492 13.4779C10.7118 13.4583 10.7701 13.4266 10.8205 13.3845C10.8709 13.3424 10.9126 13.2908 10.9431 13.2326C10.9735 13.1744 10.9923 13.1108 10.9982 13.0454C11.0041 12.98 10.997 12.914 10.9774 12.8513C10.9578 12.7887 10.9261 12.7304 10.884 12.68L8.651 10L10.884 7.32C10.9651 7.21775 11.0031 7.08782 10.9897 6.95798C10.9763 6.82814 10.9127 6.70867 10.8124 6.62511C10.7121 6.54154 10.5832 6.50051 10.453 6.51076C10.3229 6.52102 10.2019 6.58176 10.116 6.68L8 9.219L5.884 6.68Z"
10
+ fill="currentColor"
11
+ />
12
+ <path
13
+ d="M14 14V4.5L9.5 0H4C3.46957 0 2.96086 0.210714 2.58579 0.585786C2.21071 0.960859 2 1.46957 2 2V14C2 14.5304 2.21071 15.0391 2.58579 15.4142C2.96086 15.7893 3.46957 16 4 16H12C12.5304 16 13.0391 15.7893 13.4142 15.4142C13.7893 15.0391 14 14.5304 14 14ZM9.5 3C9.5 3.39782 9.65804 3.77936 9.93934 4.06066C10.2206 4.34196 10.6022 4.5 11 4.5H13V14C13 14.2652 12.8946 14.5196 12.7071 14.7071C12.5196 14.8946 12.2652 15 12 15H4C3.73478 15 3.48043 14.8946 3.29289 14.7071C3.10536 14.5196 3 14.2652 3 14V2C3 1.73478 3.10536 1.48043 3.29289 1.29289C3.48043 1.10536 3.73478 1 4 1H9.5V3Z"
14
+ fill="currentColor"
15
+ />
16
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mertani-web-toolkit",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "homepage": "https://storybook.mertani.com/",
5
5
  "scripts": {
6
6
  "dev": "vite dev",