mertani-web-toolkit 0.1.64 → 0.1.65

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.
@@ -59,35 +59,56 @@
59
59
  box-shadow 0.2s;
60
60
  }
61
61
 
62
- .select-trigger:not(:disabled) {
62
+ .select-trigger:not(.disabled) {
63
63
  background: var(--color-bg-surface);
64
64
  cursor: pointer;
65
65
  }
66
66
 
67
- .select-trigger:not(:disabled):hover {
67
+ .select-trigger:not(.disabled):hover {
68
68
  border-color: var(--color-border-form);
69
69
  }
70
70
 
71
- .select-trigger:not(:disabled):focus {
71
+ .select-trigger:not(.disabled):focus {
72
72
  outline: none;
73
73
  border-color: var(--color-bg-act-primary);
74
74
  box-shadow: 0 0 0 2px var(--color-bg-act-primary) 40;
75
75
  }
76
76
 
77
- .select-trigger:disabled {
77
+ .select-trigger.disabled {
78
78
  cursor: not-allowed;
79
79
  background: var(--color-bg-disabled);
80
80
  }
81
81
 
82
- .select-trigger.error:not(:disabled) {
82
+ .select-trigger.error:not(.disabled) {
83
83
  border-color: var(--color-text-error-ti);
84
84
  }
85
85
 
86
- .select-trigger.error:not(:disabled):focus {
86
+ .select-trigger.error:not(.disabled):focus {
87
87
  border-color: var(--color-text-error-ti);
88
88
  box-shadow: 0 0 0 2px var(--color-text-error-ti) 40;
89
89
  }
90
90
 
91
+ .select-clear-button {
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ padding: 4px;
96
+ border-radius: 4px;
97
+ color: var(--color-text-tertiary);
98
+ background: transparent;
99
+ border: none;
100
+ cursor: pointer;
101
+ transition:
102
+ color 0.2s,
103
+ background-color 0.2s;
104
+ line-height: 0;
105
+ }
106
+
107
+ .select-clear-button:hover {
108
+ color: var(--color-text-primary);
109
+ background: var(--color-bg-disabled);
110
+ }
111
+
91
112
  .select-menu {
92
113
  position: absolute;
93
114
  right: 0;
@@ -41,6 +41,7 @@
41
41
  onOpen?: () => void;
42
42
  /** Dipanggil saat teks search berubah (debounce 300ms), hanya jika remoteSearch. */
43
43
  onSearchQueryChange?: (query: string) => void;
44
+ onClear?: () => void;
44
45
 
45
46
  // Validation
46
47
  isMandatory?: boolean;
@@ -56,6 +57,7 @@
56
57
  class?: string;
57
58
  style?: string;
58
59
  isShowChevron?: boolean;
60
+ isClearable?: boolean;
59
61
  }
60
62
 
61
63
  const {
@@ -92,6 +94,7 @@
92
94
  onSelect,
93
95
  onOpen,
94
96
  onSearchQueryChange,
97
+ onClear,
95
98
 
96
99
  // Validation
97
100
  isMandatory = false,
@@ -105,7 +108,8 @@
105
108
 
106
109
  class: className = '',
107
110
  style: customStyle = '',
108
- isShowChevron = true
111
+ isShowChevron = true,
112
+ isClearable = false
109
113
  }: Props = $props();
110
114
 
111
115
  // ===== Constants =====
@@ -123,7 +127,7 @@
123
127
  let open = $state(false);
124
128
  let search = $state('');
125
129
  let placement: 'bottom' | 'top' = $state('bottom');
126
- let triggerEl: HTMLButtonElement | null = $state(null);
130
+ let triggerEl: HTMLDivElement | null = $state(null);
127
131
  let menuEl: HTMLDivElement | null = $state(null);
128
132
  let resizeObs: ResizeObserver | null = $state(null);
129
133
  let unregisterDropdown: (() => void) | null = $state(null);
@@ -306,6 +310,13 @@
306
310
  close();
307
311
  }
308
312
 
313
+ function handleClear(e: MouseEvent) {
314
+ e.stopPropagation();
315
+ onSelect?.('');
316
+ onClear?.();
317
+ error = validateInput('');
318
+ }
319
+
309
320
  function validateInput(val: string): string {
310
321
  if (customValidation) {
311
322
  const customError = customValidation(val);
@@ -403,28 +414,42 @@
403
414
  </label>
404
415
  {/if}
405
416
  <div class="relative flex-1">
406
- <button
417
+ <div
407
418
  bind:this={triggerEl}
408
- type="button"
409
- class="select-trigger {className} {error ? 'error' : ''}"
410
- style={triggerStyles()}
419
+ role="combobox"
420
+ tabindex="0"
411
421
  aria-haspopup="listbox"
412
422
  aria-expanded={open}
423
+ aria-controls={open ? 'select-menu' : undefined}
424
+ class="select-trigger {className} {error ? 'error' : ''}"
425
+ style={triggerStyles()}
413
426
  onclick={toggle}
414
427
  onkeydown={handleKeydown}
415
428
  onfocus={handleFocus}
416
429
  onblur={handleBlur}
417
- disabled={disabled || isLoading}
418
430
  title={tooltip || ''}
431
+ class:disabled={disabled || isLoading}
419
432
  >
420
433
  <span class="truncate">{labelOf(value) || placeholder}</span>
421
- {#if isShowChevron}
422
- <Icon
423
- name="bs-chevron-down"
424
- style="transform-origin: center; transition: transform 0.25s; transform: rotate({chevronRotation});"
425
- />
426
- {/if}
427
- </button>
434
+ <div class="flex items-center gap-1">
435
+ {#if isClearable && value && !disabled && !isLoading}
436
+ <button
437
+ type="button"
438
+ class="select-clear-button"
439
+ onclick={handleClear}
440
+ aria-label="Clear selection"
441
+ >
442
+ <Icon name="bs-x-lg" />
443
+ </button>
444
+ {/if}
445
+ {#if isShowChevron}
446
+ <Icon
447
+ name="bs-chevron-down"
448
+ style="transform-origin: center; transition: transform 0.25s; transform: rotate({chevronRotation});"
449
+ />
450
+ {/if}
451
+ </div>
452
+ </div>
428
453
 
429
454
  {#if open}
430
455
  <div
@@ -28,6 +28,7 @@ interface Props {
28
28
  onOpen?: () => void;
29
29
  /** Dipanggil saat teks search berubah (debounce 300ms), hanya jika remoteSearch. */
30
30
  onSearchQueryChange?: (query: string) => void;
31
+ onClear?: () => void;
31
32
  isMandatory?: boolean;
32
33
  customValidation?: (value: string) => string | null;
33
34
  isLoading?: boolean;
@@ -37,6 +38,7 @@ interface Props {
37
38
  class?: string;
38
39
  style?: string;
39
40
  isShowChevron?: boolean;
41
+ isClearable?: boolean;
40
42
  }
41
43
  declare const SelectInput: import("svelte").Component<Props, {}, "">;
42
44
  type SelectInput = ReturnType<typeof SelectInput>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mertani-web-toolkit",
3
- "version": "0.1.64",
3
+ "version": "0.1.65",
4
4
  "homepage": "https://storybook.mertani.com/",
5
5
  "scripts": {
6
6
  "dev": "vite dev",