bits-ui 1.0.0-next.18 → 1.0.0-next.19

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.
@@ -38,7 +38,6 @@
38
38
 
39
39
  <PresenceLayer {...mergedProps} present={contentState.root.open.current || forceMount}>
40
40
  {#snippet presence({ present })}
41
- <ScrollLock {preventScroll} />
42
41
  <FocusScope
43
42
  loop
44
43
  trapFocus={present.current && trapFocus}
@@ -69,6 +68,7 @@
69
68
  }}
70
69
  >
71
70
  <TextSelectionLayer {...mergedProps} enabled={present.current}>
71
+ <ScrollLock {preventScroll} />
72
72
  {#if child}
73
73
  {@render child({
74
74
  props: mergeProps(mergedProps, focusScopeProps),
@@ -12,7 +12,7 @@
12
12
  ref = $bindable(null),
13
13
  value = $bindable([]),
14
14
  onValueChange = noop,
15
- onValueChangeEnd = noop,
15
+ onValueCommit = noop,
16
16
  disabled = false,
17
17
  min = 0,
18
18
  max = 100,
@@ -41,7 +41,7 @@
41
41
  }
42
42
  }
43
43
  ),
44
- onValueChangeEnd: box.with(() => onValueChangeEnd),
44
+ onValueCommit: box.with(() => onValueCommit),
45
45
  disabled: box.with(() => disabled),
46
46
  min: box.with(() => min),
47
47
  max: box.with(() => max),
@@ -13,7 +13,7 @@ type SliderRootStateProps = WithRefProps<ReadableBoxedValues<{
13
13
  step: number;
14
14
  dir: Direction;
15
15
  autoSort: boolean;
16
- onValueChangeEnd: OnChangeFn<number[]>;
16
+ onValueCommit: OnChangeFn<number[]>;
17
17
  }> & WritableBoxedValues<{
18
18
  value: number[];
19
19
  }>>;
@@ -35,7 +35,7 @@ declare class SliderRootState {
35
35
  isActive: boolean;
36
36
  currentThumbIdx: number;
37
37
  direction: "rl" | "lr" | "tb" | "bt";
38
- onValueChangeEnd: SliderRootStateProps["onValueChangeEnd"];
38
+ onValueCommit: SliderRootStateProps["onValueCommit"];
39
39
  constructor(props: SliderRootStateProps);
40
40
  applyPosition: ({ clientXY, activeThumbIdx, start, end, }: {
41
41
  clientXY: number;
@@ -38,7 +38,7 @@ class SliderRootState {
38
38
  return this.dir.current === "rtl" ? "tb" : "bt";
39
39
  }
40
40
  });
41
- onValueChangeEnd;
41
+ onValueCommit;
42
42
  constructor(props) {
43
43
  this.id = props.id;
44
44
  this.ref = props.ref;
@@ -50,7 +50,7 @@ class SliderRootState {
50
50
  this.dir = props.dir;
51
51
  this.autoSort = props.autoSort;
52
52
  this.value = props.value;
53
- this.onValueChangeEnd = props.onValueChangeEnd;
53
+ this.onValueCommit = props.onValueCommit;
54
54
  useRefById({
55
55
  id: this.id,
56
56
  ref: this.ref,
@@ -187,7 +187,7 @@ class SliderRootState {
187
187
  };
188
188
  handlePointerUp = () => {
189
189
  if (this.isActive) {
190
- this.onValueChangeEnd.current(untrack(() => this.value.current));
190
+ this.onValueCommit.current(untrack(() => this.value.current));
191
191
  }
192
192
  this.isActive = false;
193
193
  };
@@ -477,7 +477,7 @@ class SliderThumbState {
477
477
  }
478
478
  break;
479
479
  }
480
- this.#root.onValueChangeEnd.current(this.#root.value.current);
480
+ this.#root.onValueCommit.current(this.#root.value.current);
481
481
  };
482
482
  props = $derived.by(() => ({
483
483
  ...this.#root.thumbsPropsArr[this.#index.current],
@@ -17,9 +17,10 @@ export type SliderRootPropsWithoutHTML = WithChild<{
17
17
  onValueChange?: OnChangeFn<number[]>;
18
18
  /**
19
19
  * A callback function called when the user stops dragging the thumb,
20
- * which is useful for knowing when the user has finished interacting with the slider.
20
+ * which is useful for knowing when the user has finished interacting with the
21
+ * slider and _commits_ the value.
21
22
  */
22
- onValueChangeEnd?: OnChangeFn<number[]>;
23
+ onValueCommit?: OnChangeFn<number[]>;
23
24
  /**
24
25
  * Whether to automatically sort the values in the array when moving thumbs past
25
26
  * one another.
@@ -74,9 +74,7 @@
74
74
  {customAnchor}
75
75
  >
76
76
  {#snippet content({ props: floatingProps })}
77
- {#if preventScroll}
78
- <ScrollLock {preventScroll} />
79
- {/if}
77
+ <ScrollLock {preventScroll} />
80
78
  <FocusScope
81
79
  {id}
82
80
  {onOpenAutoFocus}
@@ -62,7 +62,12 @@ function createMonth(props) {
62
62
  if (!startFrom) {
63
63
  startFrom = dateObj.add({ months: 1 }).set({ day: 1 });
64
64
  }
65
- const extraDaysArray = Array.from({ length: extraDays }, (_, i) => {
65
+ let length = extraDays;
66
+ if (nextMonthDays.length === 0) {
67
+ length = extraDays - 1;
68
+ nextMonthDays.push(startFrom);
69
+ }
70
+ const extraDaysArray = Array.from({ length }, (_, i) => {
66
71
  const incr = i + 1;
67
72
  return startFrom.add({ days: incr });
68
73
  });
@@ -1,10 +1,11 @@
1
1
  import { SvelteMap } from "svelte/reactivity";
2
2
  import { afterTick, box } from "svelte-toolbelt";
3
+ import { Previous, watch } from "runed";
4
+ import { untrack } from "svelte";
3
5
  import { isBrowser, isIOS } from "./is.js";
4
6
  import { addEventListener } from "./events.js";
5
7
  import { useId } from "./use-id.js";
6
8
  import { createSharedHook } from "./create-shared-hook.svelte.js";
7
- import { watch } from "./box.svelte.js";
8
9
  const useBodyLockStackCount = createSharedHook(() => {
9
10
  const map = new SvelteMap();
10
11
  const locked = $derived.by(() => {
@@ -15,6 +16,7 @@ const useBodyLockStackCount = createSharedHook(() => {
15
16
  }
16
17
  return false;
17
18
  });
19
+ const prevLocked = new Previous(() => locked);
18
20
  let initialBodyStyle = $state({});
19
21
  let stopTouchMoveListener = null;
20
22
  function resetBodyStyle() {
@@ -27,43 +29,43 @@ const useBodyLockStackCount = createSharedHook(() => {
27
29
  document.body.style.overflow = initialBodyStyle.overflow ?? "";
28
30
  isIOS && stopTouchMoveListener?.();
29
31
  }
30
- watch(box.with(() => locked), (curr, prev) => {
31
- if (!curr) {
32
- if (prev) {
33
- resetBodyStyle();
32
+ $effect(() => {
33
+ const curr = locked;
34
+ return untrack(() => {
35
+ if (!curr) {
36
+ return;
34
37
  }
35
- return;
36
- }
37
- const bodyStyle = getComputedStyle(document.body);
38
- initialBodyStyle.overflow = bodyStyle.overflow;
39
- initialBodyStyle.paddingRight = bodyStyle.paddingRight;
40
- initialBodyStyle.marginRight = bodyStyle.marginRight;
41
- initialBodyStyle.pointerEvents = bodyStyle.pointerEvents;
42
- // TODO: account for RTL direction, etc.
43
- const verticalScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
44
- const paddingRight = Number.parseInt(initialBodyStyle.paddingRight ?? "0", 10);
45
- const config = {
46
- padding: paddingRight + verticalScrollbarWidth,
47
- margin: Number.parseInt(initialBodyStyle.marginRight ?? "0", 10),
48
- };
49
- if (verticalScrollbarWidth > 0) {
50
- document.body.style.paddingRight = `${config.padding}px`;
51
- document.body.style.marginRight = `${config.margin}px`;
52
- document.body.style.setProperty("--scrollbar-width", `${verticalScrollbarWidth}px`);
53
- document.body.style.overflow = "hidden";
54
- }
55
- if (isIOS) {
56
- stopTouchMoveListener = addEventListener(document, "touchmove", (e) => {
57
- if (e.target !== document.documentElement)
58
- return;
59
- if (e.touches.length > 1)
60
- return;
61
- e.preventDefault();
62
- }, { passive: false });
63
- }
64
- afterTick(() => {
65
- document.body.style.pointerEvents = "none";
66
- document.body.style.overflow = "hidden";
38
+ const bodyStyle = getComputedStyle(document.body);
39
+ initialBodyStyle.overflow = bodyStyle.overflow;
40
+ initialBodyStyle.paddingRight = bodyStyle.paddingRight;
41
+ initialBodyStyle.marginRight = bodyStyle.marginRight;
42
+ initialBodyStyle.pointerEvents = bodyStyle.pointerEvents;
43
+ // TODO: account for RTL direction, etc.
44
+ const verticalScrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
45
+ const paddingRight = Number.parseInt(initialBodyStyle.paddingRight ?? "0", 10);
46
+ const config = {
47
+ padding: paddingRight + verticalScrollbarWidth,
48
+ margin: Number.parseInt(initialBodyStyle.marginRight ?? "0", 10),
49
+ };
50
+ if (verticalScrollbarWidth > 0) {
51
+ document.body.style.paddingRight = `${config.padding}px`;
52
+ document.body.style.marginRight = `${config.margin}px`;
53
+ document.body.style.setProperty("--scrollbar-width", `${verticalScrollbarWidth}px`);
54
+ document.body.style.overflow = "hidden";
55
+ }
56
+ if (isIOS) {
57
+ stopTouchMoveListener = addEventListener(document, "touchmove", (e) => {
58
+ if (e.target !== document.documentElement)
59
+ return;
60
+ if (e.touches.length > 1)
61
+ return;
62
+ e.preventDefault();
63
+ }, { passive: false });
64
+ }
65
+ afterTick(() => {
66
+ document.body.style.pointerEvents = "none";
67
+ document.body.style.overflow = "hidden";
68
+ });
67
69
  });
68
70
  });
69
71
  $effect(() => {
@@ -71,16 +73,25 @@ const useBodyLockStackCount = createSharedHook(() => {
71
73
  stopTouchMoveListener?.();
72
74
  };
73
75
  });
74
- return map;
76
+ return {
77
+ get map() {
78
+ return map;
79
+ },
80
+ resetBodyStyle,
81
+ };
75
82
  });
76
83
  export function useBodyScrollLock(initialState) {
77
84
  const id = useId();
78
- const map = useBodyLockStackCount();
79
- map.set(id, initialState ?? false);
80
- const locked = box.with(() => map.get(id) ?? false, (v) => map.set(id, v));
85
+ const countState = useBodyLockStackCount();
86
+ countState.map.set(id, initialState ?? false);
87
+ const locked = box.with(() => countState.map.get(id) ?? false, (v) => countState.map.set(id, v));
81
88
  $effect(() => {
82
89
  return () => {
83
- map.delete(id);
90
+ countState.map.delete(id);
91
+ const length = Array.from(countState.map.values()).length;
92
+ if (length === 0) {
93
+ countState.resetBodyStyle();
94
+ }
84
95
  };
85
96
  });
86
97
  return locked;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.0.0-next.18",
3
+ "version": "1.0.0-next.19",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",