@r2digisolutions/components 0.14.12 → 0.14.14

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.
@@ -70,6 +70,7 @@
70
70
  let popoverEl = $state<HTMLDivElement | null>(null);
71
71
  let inputEl = $state<HTMLInputElement | null>(null);
72
72
  let highlighted = $state(0);
73
+ let openingGesture = $state(false);
73
74
  let childEntries = $state<{ id: number; value: string; disabled: boolean; label: string }[]>([]);
74
75
  let nextChildId = 0;
75
76
  const uid = $props.id();
@@ -163,8 +164,32 @@
163
164
  }
164
165
  }
165
166
 
167
+ function onDocPointerDown(event: PointerEvent) {
168
+ if (!open || openingGesture) return;
169
+ const target = event.target;
170
+ if (!(target instanceof Node)) return;
171
+ if (rootEl?.contains(target) || popoverEl?.contains(target)) return;
172
+ setOpen(false);
173
+ }
174
+
175
+ function markOpeningGesture() {
176
+ openingGesture = true;
177
+ queueMicrotask(() => {
178
+ openingGesture = false;
179
+ });
180
+ }
181
+
182
+ function commitPendingQuery() {
183
+ const trimmed = query.trim();
184
+ if (!creatable || !trimmed || trimmed === value) return;
185
+ value = trimmed;
186
+ onchange?.(trimmed);
187
+ }
188
+
166
189
  function onPopoverClose() {
190
+ commitPendingQuery();
167
191
  if (selected) query = selected.label;
192
+ else if (value) query = value;
168
193
  else if (!creatable) query = '';
169
194
  }
170
195
 
@@ -194,6 +219,7 @@
194
219
 
195
220
  function setOpen(next: boolean) {
196
221
  if (disabled) return;
222
+ if (next) markOpeningGesture();
197
223
  open = next;
198
224
  if (next) {
199
225
  highlighted = 0;
@@ -283,8 +309,11 @@
283
309
  }
284
310
 
285
311
  $effect(() => {
286
- if (selected && !open && query !== selected.label) {
312
+ if (open) return;
313
+ if (selected && query !== selected.label) {
287
314
  query = selected.label;
315
+ } else if (value && query !== value) {
316
+ query = value;
288
317
  }
289
318
  });
290
319
 
@@ -307,11 +336,17 @@
307
336
 
308
337
  const offScroll = on(window, 'scroll', reposition, { capture: true, passive: true });
309
338
  const offResize = on(window, 'resize', reposition);
339
+ // Defer past the opening click — same gesture must not count as outside.
340
+ const timer = window.setTimeout(() => {
341
+ document.addEventListener('pointerdown', onDocPointerDown, true);
342
+ }, 0);
310
343
 
311
344
  return () => {
312
345
  cancelAnimationFrame(frame);
313
346
  offScroll();
314
347
  offResize();
348
+ window.clearTimeout(timer);
349
+ document.removeEventListener('pointerdown', onDocPointerDown, true);
315
350
  };
316
351
  });
317
352
 
@@ -407,17 +442,16 @@
407
442
  <div
408
443
  bind:this={popoverEl}
409
444
  id={listboxId}
410
- popover="auto"
445
+ popover="manual"
411
446
  role="listbox"
412
447
  onbeforetoggle={handleBeforeToggle}
413
448
  ontoggle={handleToggle}
414
449
  class="combobox-popover inset-auto m-0 overflow-y-auto rounded-xl border border-border bg-surface-elevated p-1.5 shadow-xl outline-none"
415
450
  >
416
- {#if open}
417
- {#if !hasRows}
418
- <div class="px-3 py-2.5 text-xs text-muted text-center">{emptyText}</div>
419
- {:else}
420
- {#each items as item, index (itemKey(item))}
451
+ {#if !hasRows}
452
+ <div class="px-3 py-2.5 text-xs text-muted text-center">{emptyText}</div>
453
+ {:else}
454
+ {#each items as item, index (itemKey(item))}
421
455
  {#if item.kind === 'create'}
422
456
  <ComboboxItem
423
457
  value={COMBOBOX_CREATE_KEY}
@@ -465,7 +499,6 @@
465
499
  {/each}
466
500
  {@render children?.()}
467
501
  {/if}
468
- {/if}
469
502
  </div>
470
503
  </div>
471
504
 
@@ -75,8 +75,9 @@
75
75
  }
76
76
  </script>
77
77
 
78
- <div class={['w-full space-y-1', className]}>
78
+ <div class="w-full space-y-1">
79
79
  <Combobox
80
+ class={className}
80
81
  {label}
81
82
  {placeholder}
82
83
  {options}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/components",
3
- "version": "0.14.12",
3
+ "version": "0.14.14",
4
4
  "private": false,
5
5
  "description": "R2DigiSolutions Svelte 5 component library — Atomic Design, Tailwind 4, Light/Dark mode",
6
6
  "license": "MIT",