bits-ui 1.0.0-next.41 → 1.0.0-next.42

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.
@@ -16,6 +16,7 @@
16
16
  onEscapeKeydown = noop,
17
17
  children,
18
18
  child,
19
+ preventScroll = false,
19
20
  ...restProps
20
21
  }: SelectContentProps = $props();
21
22
 
@@ -56,7 +57,7 @@
56
57
  onCloseAutoFocus={(e) => e.preventDefault()}
57
58
  trapFocus={false}
58
59
  loop={false}
59
- preventScroll={false}
60
+ {preventScroll}
60
61
  onPlaced={() => (contentState.isPositioned = true)}
61
62
  forceMount={true}
62
63
  >
@@ -83,7 +84,7 @@
83
84
  onCloseAutoFocus={(e) => e.preventDefault()}
84
85
  trapFocus={false}
85
86
  loop={false}
86
- preventScroll={false}
87
+ {preventScroll}
87
88
  onPlaced={() => (contentState.isPositioned = true)}
88
89
  forceMount={false}
89
90
  >
@@ -48,6 +48,8 @@ export class DismissibleLayerState {
48
48
  $effect(() => {
49
49
  if (this.#enabled.current && this.currNode) {
50
50
  afterSleep(1, () => {
51
+ if (!this.currNode)
52
+ return;
51
53
  globalThis.bitsDismissableLayers.set(this, untrack(() => this.#behaviorType));
52
54
  unsubEvents();
53
55
  unsubEvents = this.#addEventListeners();
@@ -1,11 +1,13 @@
1
1
  import { afterTick } from "svelte-toolbelt";
2
+ import { Previous } from "runed";
3
+ import { untrack } from "svelte";
2
4
  import { useStateMachine } from "../../../internal/use-state-machine.svelte.js";
3
- import { watch } from "../../../internal/box.svelte.js";
4
5
  export function usePresence(present, id) {
5
6
  let styles = $state({});
6
7
  let prevAnimationNameState = $state("none");
7
8
  const initialState = present.current ? "mounted" : "unmounted";
8
9
  let node = $state(null);
10
+ const prevPresent = new Previous(() => present.current);
9
11
  $effect(() => {
10
12
  if (!id.current)
11
13
  return;
@@ -28,40 +30,43 @@ export function usePresence(present, id) {
28
30
  MOUNT: "mounted",
29
31
  },
30
32
  });
31
- watch(present, (currPresent, prevPresent) => {
32
- if (!node) {
33
- node = document.getElementById(id.current);
34
- }
35
- if (!node)
36
- return;
37
- const hasPresentChanged = currPresent !== prevPresent;
38
- if (!hasPresentChanged)
39
- return;
40
- const prevAnimationName = prevAnimationNameState;
41
- const currAnimationName = getAnimationName(node);
42
- if (currPresent) {
43
- dispatch("MOUNT");
44
- }
45
- else if (currAnimationName === "none" || styles.display === "none") {
46
- // If there is no exit animation or the element is hidden, animations won't run
47
- // so we unmount instantly
48
- dispatch("UNMOUNT");
49
- }
50
- else {
51
- /**
52
- * When `present` changes to `false`, we check changes to animation-name to
53
- * determine whether an animation has started. We chose this approach (reading
54
- * computed styles) because there is no `animationrun` event and `animationstart`
55
- * fires after `animation-delay` has expired which would be too late.
56
- */
57
- const isAnimating = prevAnimationName !== currAnimationName;
58
- if (prevPresent && isAnimating) {
59
- dispatch("ANIMATION_OUT");
33
+ $effect(() => {
34
+ const currPresent = present.current;
35
+ untrack(() => {
36
+ if (!node) {
37
+ node = document.getElementById(id.current);
60
38
  }
61
- else {
39
+ if (!node)
40
+ return;
41
+ const hasPresentChanged = currPresent !== prevPresent.current;
42
+ if (!hasPresentChanged)
43
+ return;
44
+ const prevAnimationName = prevAnimationNameState;
45
+ const currAnimationName = getAnimationName(node);
46
+ if (currPresent) {
47
+ dispatch("MOUNT");
48
+ }
49
+ else if (currAnimationName === "none" || styles.display === "none") {
50
+ // If there is no exit animation or the element is hidden, animations won't run
51
+ // so we unmount instantly
62
52
  dispatch("UNMOUNT");
63
53
  }
64
- }
54
+ else {
55
+ /**
56
+ * When `present` changes to `false`, we check changes to animation-name to
57
+ * determine whether an animation has started. We chose this approach (reading
58
+ * computed styles) because there is no `animationrun` event and `animationstart`
59
+ * fires after `animation-delay` has expired which would be too late.
60
+ */
61
+ const isAnimating = prevAnimationName !== currAnimationName;
62
+ if (prevPresent && isAnimating) {
63
+ dispatch("ANIMATION_OUT");
64
+ }
65
+ else {
66
+ dispatch("UNMOUNT");
67
+ }
68
+ }
69
+ });
65
70
  });
66
71
  /**
67
72
  * Triggering an ANIMATION_OUT during an ANIMATION_IN will fire an `animationcancel`
@@ -90,14 +95,17 @@ export function usePresence(present, id) {
90
95
  prevAnimationNameState = getAnimationName(node);
91
96
  }
92
97
  }
93
- watch(state, () => {
94
- if (!node) {
95
- node = document.getElementById(id.current);
96
- }
97
- if (!node)
98
- return;
99
- const currAnimationName = getAnimationName(node);
100
- prevAnimationNameState = state.current === "mounted" ? currAnimationName : "none";
98
+ $effect(() => {
99
+ state.current;
100
+ untrack(() => {
101
+ if (!node) {
102
+ node = document.getElementById(id.current);
103
+ }
104
+ if (!node)
105
+ return;
106
+ const currAnimationName = getAnimationName(node);
107
+ prevAnimationNameState = state.current === "mounted" ? currAnimationName : "none";
108
+ });
101
109
  });
102
110
  $effect(() => {
103
111
  if (!node)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.0.0-next.41",
3
+ "version": "1.0.0-next.42",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",