bits-ui 2.8.9 → 2.8.11

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.
@@ -41,6 +41,12 @@
41
41
  function handleInteractOutside(e: PointerEvent) {
42
42
  onInteractOutside(e);
43
43
  if (e.defaultPrevented) return;
44
+
45
+ // don't close if the interaction is with a submenu content or items
46
+ if (e.target && e.target instanceof Element) {
47
+ const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr("sub-content")}]`;
48
+ if (e.target.closest(subContentSelector)) return;
49
+ }
44
50
  contentState.parentMenu.onClose();
45
51
  }
46
52
 
@@ -41,6 +41,12 @@
41
41
  if (e.defaultPrevented) return;
42
42
  onInteractOutside(e);
43
43
  if (e.defaultPrevented) return;
44
+
45
+ // don't close if the interaction is with a submenu content or items
46
+ if (e.target && e.target instanceof Element) {
47
+ const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr("sub-content")}]`;
48
+ if (e.target.closest(subContentSelector)) return;
49
+ }
44
50
  contentState.parentMenu.onClose();
45
51
  }
46
52
  function handleEscapeKeydown(e: KeyboardEvent) {
@@ -42,6 +42,11 @@
42
42
  function handleInteractOutside(e: PointerEvent) {
43
43
  onInteractOutside(e);
44
44
  if (e.defaultPrevented) return;
45
+ // don't close if the interaction is with a submenu content or items
46
+ if (e.target && e.target instanceof Element) {
47
+ const subContentSelector = `[${contentState.parentMenu.root.getBitsAttr("sub-content")}]`;
48
+ if (e.target.closest(subContentSelector)) return;
49
+ }
45
50
  contentState.parentMenu.onClose();
46
51
  }
47
52
 
@@ -423,15 +423,13 @@ export class MenuItemState {
423
423
  return;
424
424
  const selectEvent = new CustomEvent("menuitemselect", { bubbles: true, cancelable: true });
425
425
  this.opts.onSelect.current(selectEvent);
426
- afterTick(() => {
427
- if (selectEvent.defaultPrevented) {
428
- this.item.content.parentMenu.root.isUsingKeyboard.current = false;
429
- return;
430
- }
431
- if (this.opts.closeOnSelect.current) {
432
- this.item.content.parentMenu.root.opts.onClose();
433
- }
434
- });
426
+ if (selectEvent.defaultPrevented) {
427
+ this.item.content.parentMenu.root.isUsingKeyboard.current = false;
428
+ return;
429
+ }
430
+ if (this.opts.closeOnSelect.current) {
431
+ this.item.content.parentMenu.root.opts.onClose();
432
+ }
435
433
  }
436
434
  onkeydown(e) {
437
435
  const isTypingAhead = this.item.content.search !== "";
@@ -868,7 +866,7 @@ export class ContextMenuTriggerState {
868
866
  this.parentMenu.onOpen();
869
867
  }
870
868
  oncontextmenu(e) {
871
- if (this.opts.disabled.current)
869
+ if (e.defaultPrevented || this.opts.disabled.current)
872
870
  return;
873
871
  this.#clearLongPressTimer();
874
872
  this.#handleOpen(e);
@@ -28,6 +28,7 @@ interface SelectBaseRootStateOpts extends ReadableBoxedValues<{
28
28
  isCombobox: boolean;
29
29
  }
30
30
  declare abstract class SelectBaseRootState {
31
+ #private;
31
32
  readonly opts: SelectBaseRootStateOpts;
32
33
  touchedInput: boolean;
33
34
  inputNode: HTMLElement | null;
@@ -44,7 +45,9 @@ declare abstract class SelectBaseRootState {
44
45
  constructor(opts: SelectBaseRootStateOpts);
45
46
  setHighlightedNode(node: HTMLElement | null, initial?: boolean): void;
46
47
  getCandidateNodes(): HTMLElement[];
47
- setHighlightedToFirstCandidate(): void;
48
+ setHighlightedToFirstCandidate(options?: {
49
+ debounced: boolean;
50
+ }): void;
48
51
  getNodeByValue(value: string): HTMLElement | null;
49
52
  setOpen(open: boolean): void;
50
53
  toggleOpen(): void;
@@ -1,5 +1,5 @@
1
1
  import { Context, Previous, watch } from "runed";
2
- import { afterSleep, afterTick, onDestroyEffect, attachRef, DOMContext, box, } from "svelte-toolbelt";
2
+ import { afterSleep, afterTick, onDestroyEffect, onMountEffect, attachRef, DOMContext, box, } from "svelte-toolbelt";
3
3
  import { on } from "svelte/events";
4
4
  import { backward, forward, next, prev } from "../../internal/arrays.js";
5
5
  import { getAriaExpanded, getAriaHidden, getDataDisabled, getDataOpenClosed, getDisabled, getRequired, } from "../../internal/attrs.js";
@@ -11,6 +11,7 @@ import { getFloatingContentCSSVars } from "../../internal/floating-svelte/floati
11
11
  import { DataTypeahead } from "../../internal/data-typeahead.svelte.js";
12
12
  import { DOMTypeahead } from "../../internal/dom-typeahead.svelte.js";
13
13
  import { OpenChangeComplete } from "../../internal/open-change-complete.js";
14
+ import { debounce } from "../../internal/debounce.js";
14
15
  // prettier-ignore
15
16
  export const INTERACTION_KEYS = [kbd.ARROW_LEFT, kbd.ESCAPE, kbd.ARROW_RIGHT, kbd.SHIFT, kbd.CAPS_LOCK, kbd.CONTROL, kbd.ALT, kbd.META, kbd.ENTER, kbd.F1, kbd.F2, kbd.F3, kbd.F4, kbd.F5, kbd.F6, kbd.F7, kbd.F8, kbd.F9, kbd.F10, kbd.F11, kbd.F12];
16
17
  export const FIRST_KEYS = [kbd.ARROW_DOWN, kbd.PAGE_UP, kbd.HOME];
@@ -82,6 +83,7 @@ class SelectBaseRootState {
82
83
  }
83
84
  });
84
85
  }
86
+ #debouncedSetHighlightedToFirstCandidate = debounce(this.setHighlightedToFirstCandidate.bind(this), 20);
85
87
  setHighlightedNode(node, initial = false) {
86
88
  this.highlightedNode = node;
87
89
  if (node && (this.isUsingKeyboard || initial)) {
@@ -94,7 +96,11 @@ class SelectBaseRootState {
94
96
  return [];
95
97
  return Array.from(node.querySelectorAll(`[${this.getBitsAttr("item")}]:not([data-disabled])`));
96
98
  }
97
- setHighlightedToFirstCandidate() {
99
+ setHighlightedToFirstCandidate(options = { debounced: false }) {
100
+ if (options.debounced) {
101
+ this.#debouncedSetHighlightedToFirstCandidate();
102
+ return;
103
+ }
98
104
  this.setHighlightedNode(null);
99
105
  const candidateNodes = this.getCandidateNodes();
100
106
  if (!candidateNodes.length)
@@ -372,7 +378,6 @@ export class SelectInputState {
372
378
  }
373
379
  oninput(e) {
374
380
  this.root.opts.inputValue.current = e.currentTarget.value;
375
- this.root.setHighlightedToFirstCandidate();
376
381
  }
377
382
  props = $derived.by(() => ({
378
383
  id: this.opts.id.current,
@@ -785,6 +790,12 @@ export class SelectItemState {
785
790
  this.opts = opts;
786
791
  this.root = root;
787
792
  this.attachment = attachRef(opts.ref);
793
+ onMountEffect(() => {
794
+ this.root.setHighlightedToFirstCandidate({ debounced: true });
795
+ });
796
+ onDestroyEffect(() => {
797
+ this.root.setHighlightedToFirstCandidate({ debounced: true });
798
+ });
788
799
  watch([() => this.isHighlighted, () => this.prevHighlighted.current], () => {
789
800
  if (this.isHighlighted) {
790
801
  this.opts.onHighlight.current();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "2.8.9",
3
+ "version": "2.8.11",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",