bits-ui 1.3.19 → 1.4.1

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.
@@ -4,6 +4,7 @@
4
4
  import type { AccordionRootProps } from "../types.js";
5
5
  import { useId } from "../../../internal/use-id.js";
6
6
  import { noop } from "../../../internal/noop.js";
7
+ import { watch } from "runed";
7
8
 
8
9
  let {
9
10
  disabled = false,
@@ -19,7 +20,20 @@
19
20
  ...restProps
20
21
  }: AccordionRootProps = $props();
21
22
 
22
- value === undefined && (value = type === "single" ? "" : []);
23
+ function handleDefaultValue() {
24
+ if (value !== undefined) return;
25
+ value = type === "single" ? "" : [];
26
+ }
27
+
28
+ // SSR
29
+ handleDefaultValue();
30
+
31
+ watch.pre(
32
+ () => value,
33
+ () => {
34
+ handleDefaultValue();
35
+ }
36
+ );
23
37
 
24
38
  const rootState = useAccordionRoot({
25
39
  type,
@@ -6,6 +6,7 @@
6
6
  import { useId } from "../../../internal/use-id.js";
7
7
  import { noop } from "../../../internal/noop.js";
8
8
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
9
+ import { watch } from "runed";
9
10
 
10
11
  let {
11
12
  child,
@@ -40,16 +41,36 @@
40
41
  defaultValue: value,
41
42
  });
42
43
 
43
- if (placeholder === undefined) {
44
+ function handleDefaultPlaceholder() {
45
+ if (placeholder !== undefined) return;
44
46
  placeholder = defaultPlaceholder;
45
47
  }
46
48
 
47
- if (value === undefined) {
48
- const defaultValue = type === "single" ? undefined : [];
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
- value = defaultValue as any;
49
+ // SSR
50
+ handleDefaultPlaceholder();
51
+
52
+ watch.pre(
53
+ () => placeholder,
54
+ () => {
55
+ handleDefaultPlaceholder();
56
+ }
57
+ );
58
+
59
+ function handleDefaultValue() {
60
+ if (value !== undefined) return;
61
+ value = type === "single" ? undefined : [];
51
62
  }
52
63
 
64
+ // SSR
65
+ handleDefaultValue();
66
+
67
+ watch.pre(
68
+ () => value,
69
+ () => {
70
+ handleDefaultValue();
71
+ }
72
+ );
73
+
53
74
  const rootState = useCalendarRoot({
54
75
  id: box.with(() => id),
55
76
  ref: box.with(
@@ -5,6 +5,7 @@
5
5
  import FloatingLayer from "../../utilities/floating-layer/components/floating-layer.svelte";
6
6
  import { useSelectRoot } from "../../select/select.svelte.js";
7
7
  import ListboxHiddenInput from "../../select/components/select-hidden-input.svelte";
8
+ import { watch } from "runed";
8
9
 
9
10
  let {
10
11
  value = $bindable(),
@@ -27,6 +28,14 @@
27
28
  value = defaultValue;
28
29
  }
29
30
 
31
+ watch.pre(
32
+ () => value,
33
+ () => {
34
+ if (value !== undefined) return;
35
+ value = type === "single" ? "" : [];
36
+ }
37
+ );
38
+
30
39
  const rootState = useSelectRoot({
31
40
  type,
32
41
  value: box.with(
@@ -36,8 +36,10 @@
36
36
  value: box.with(
37
37
  () => value,
38
38
  (v) => {
39
- value = v;
40
- onValueChange(v);
39
+ if (value !== v) {
40
+ value = v;
41
+ onValueChange(v);
42
+ }
41
43
  }
42
44
  ),
43
45
  vimBindings: box.with(() => vimBindings),
@@ -5,6 +5,7 @@
5
5
  import type { DateFieldRootProps } from "../types.js";
6
6
  import { noop } from "../../../internal/noop.js";
7
7
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
8
+ import { watch } from "runed";
8
9
 
9
10
  let {
10
11
  disabled = false,
@@ -27,7 +28,9 @@
27
28
  children,
28
29
  }: DateFieldRootProps = $props();
29
30
 
30
- if (placeholder === undefined) {
31
+ function handleDefaultPlaceholder() {
32
+ if (placeholder !== undefined) return;
33
+
31
34
  const defaultPlaceholder = getDefaultDate({
32
35
  granularity,
33
36
  defaultValue: value,
@@ -36,6 +39,21 @@
36
39
  placeholder = defaultPlaceholder;
37
40
  }
38
41
 
42
+ // SSR
43
+ handleDefaultPlaceholder();
44
+
45
+ /**
46
+ * Covers an edge case where when a spread props object is reassigned,
47
+ * the props are reset to their default values, which would make placeholder
48
+ * undefined which causes errors to be thrown.
49
+ */
50
+ watch.pre(
51
+ () => placeholder,
52
+ () => {
53
+ handleDefaultPlaceholder();
54
+ }
55
+ );
56
+
39
57
  useDateFieldRoot({
40
58
  value: box.with(
41
59
  () => value,
@@ -9,6 +9,7 @@
9
9
  import { useDateFieldRoot } from "../../date-field/date-field.svelte.js";
10
10
  import { FloatingLayer } from "../../utilities/floating-layer/index.js";
11
11
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
12
+ import { watch } from "runed";
12
13
 
13
14
  let {
14
15
  open = $bindable(false),
@@ -50,10 +51,26 @@
50
51
  defaultValue: value,
51
52
  });
52
53
 
53
- if (placeholder === undefined) {
54
+ function handleDefaultPlaceholder() {
55
+ if (placeholder !== undefined) return;
54
56
  placeholder = defaultPlaceholder;
55
57
  }
56
58
 
59
+ // SSR
60
+ handleDefaultPlaceholder();
61
+
62
+ /**
63
+ * Covers an edge case where when a spread props object is reassigned,
64
+ * the props are reset to their default values, which would make placeholder
65
+ * undefined which causes errors to be thrown.
66
+ */
67
+ watch.pre(
68
+ () => placeholder,
69
+ () => {
70
+ handleDefaultPlaceholder();
71
+ }
72
+ );
73
+
57
74
  function onDateSelect() {
58
75
  if (closeOnDateSelect) {
59
76
  open = false;
@@ -7,6 +7,7 @@
7
7
  import { noop } from "../../../internal/noop.js";
8
8
  import type { DateRange } from "../../../shared/index.js";
9
9
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
10
+ import { watch } from "runed";
10
11
 
11
12
  let {
12
13
  id = useId(),
@@ -38,21 +39,43 @@
38
39
  let startValue = $state<DateValue | undefined>(value?.start);
39
40
  let endValue = $state<DateValue | undefined>(value?.end);
40
41
 
41
- if (placeholder === undefined) {
42
- const defaultPlaceholder = getDefaultDate({
43
- granularity,
44
- defaultValue: value?.start,
45
- });
46
-
42
+ function handleDefaultPlaceholder() {
43
+ if (placeholder !== undefined) return;
44
+ const defaultPlaceholder = getDefaultDate({ granularity, defaultValue: value?.start });
47
45
  placeholder = defaultPlaceholder;
48
46
  }
49
47
 
50
- if (value === undefined) {
51
- const defaultValue = { start: undefined, end: undefined };
48
+ // SSR
49
+ handleDefaultPlaceholder();
50
+
51
+ watch.pre(
52
+ () => placeholder,
53
+ () => {
54
+ handleDefaultPlaceholder();
55
+ }
56
+ );
52
57
 
58
+ function handleDefaultValue() {
59
+ if (value !== undefined) return;
60
+ const defaultValue = { start: undefined, end: undefined };
53
61
  value = defaultValue;
54
62
  }
55
63
 
64
+ // SSR
65
+ handleDefaultValue();
66
+
67
+ /**
68
+ * Covers an edge case where when a spread props object is reassigned,
69
+ * the props are reset to their default values, which would make value
70
+ * undefined which causes errors to be thrown.
71
+ */
72
+ watch.pre(
73
+ () => value,
74
+ () => {
75
+ handleDefaultValue();
76
+ }
77
+ );
78
+
56
79
  const rootState = useDateRangeFieldRoot({
57
80
  id: box.with(() => id),
58
81
  ref: box.with(
@@ -10,6 +10,7 @@
10
10
  import { useId } from "../../../internal/use-id.js";
11
11
  import type { DateRange } from "../../../shared/index.js";
12
12
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
13
+ import { watch } from "runed";
13
14
 
14
15
  let {
15
16
  open = $bindable(false),
@@ -54,18 +55,51 @@
54
55
  let startValue = $state<DateValue | undefined>(value?.start);
55
56
  let endValue = $state<DateValue | undefined>(value?.end);
56
57
 
57
- if (value === undefined) {
58
+ function handleDefaultValue() {
59
+ if (value !== undefined) return;
58
60
  value = { start: undefined, end: undefined };
59
61
  }
62
+
63
+ // SSR
64
+ handleDefaultValue();
65
+
66
+ /**
67
+ * Covers an edge case where when a spread props object is reassigned,
68
+ * the props are reset to their default values, which would make value
69
+ * undefined which causes errors to be thrown.
70
+ */
71
+ watch.pre(
72
+ () => value,
73
+ () => {
74
+ handleDefaultValue();
75
+ }
76
+ );
77
+
60
78
  const defaultPlaceholder = getDefaultDate({
61
79
  granularity,
62
80
  defaultValue: value?.start,
63
81
  });
64
82
 
65
- if (placeholder === undefined) {
83
+ function handleDefaultPlaceholder() {
84
+ if (placeholder !== undefined) return;
66
85
  placeholder = defaultPlaceholder;
67
86
  }
68
87
 
88
+ // SSR
89
+ handleDefaultPlaceholder();
90
+
91
+ /**
92
+ * Covers an edge case where when a spread props object is reassigned,
93
+ * the props are reset to their default values, which would make placeholder
94
+ * undefined which causes errors to be thrown.
95
+ */
96
+ watch.pre(
97
+ () => placeholder,
98
+ () => {
99
+ handleDefaultPlaceholder();
100
+ }
101
+ );
102
+
69
103
  function onRangeSelect() {
70
104
  if (closeOnRangeSelect) {
71
105
  open = false;
@@ -5,5 +5,4 @@ export { default as ContentStatic } from "./components/popover-content-static.sv
5
5
  export { default as Trigger } from "./components/popover-trigger.svelte";
6
6
  export { default as Close } from "./components/popover-close.svelte";
7
7
  export { default as Portal } from "../utilities/portal/portal.svelte";
8
- export type { PopoverRootProps as RootProps, PopoverArrowProps as ArrowProps, PopoverContentProps as ContentProps, PopoverContentStaticProps as ContentStaticProps, PopoverTriggerProps as TriggerProps, PopoverCloseProps as CloseProps, } from "./types.js";
9
- export type { PortalProps } from "../utilities/portal/types.js";
8
+ export type { PopoverRootProps as RootProps, PopoverArrowProps as ArrowProps, PopoverContentProps as ContentProps, PopoverContentStaticProps as ContentStaticProps, PopoverTriggerProps as TriggerProps, PopoverCloseProps as CloseProps, PopoverPortalProps as PortalProps, } from "./types.js";
@@ -3,6 +3,7 @@ import type { PopperLayerProps, PopperLayerStaticProps } from "../utilities/popp
3
3
  import type { OnChangeFn, WithChild, WithChildNoChildrenSnippetProps, WithChildren, Without } from "../../internal/types.js";
4
4
  import type { BitsPrimitiveButtonAttributes, BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
5
5
  import type { FloatingContentSnippetProps, StaticContentSnippetProps } from "../../shared/types.js";
6
+ import type { PortalProps } from "../../types.js";
6
7
  export type PopoverRootPropsWithoutHTML = WithChildren<{
7
8
  /**
8
9
  * The open state of the popover.
@@ -24,3 +25,5 @@ export type PopoverClosePropsWithoutHTML = WithChild;
24
25
  export type PopoverCloseProps = PopoverClosePropsWithoutHTML & Without<BitsPrimitiveButtonAttributes, PopoverClosePropsWithoutHTML>;
25
26
  export type PopoverArrowPropsWithoutHTML = ArrowPropsWithoutHTML;
26
27
  export type PopoverArrowProps = ArrowProps;
28
+ export type PopoverPortalPropsWithoutHTML = PortalProps;
29
+ export type PopoverPortalProps = PortalProps;
@@ -6,6 +6,7 @@
6
6
  import { noop } from "../../../internal/noop.js";
7
7
  import { useId } from "../../../internal/use-id.js";
8
8
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
9
+ import { watch } from "runed";
9
10
 
10
11
  let {
11
12
  children,
@@ -43,15 +44,36 @@
43
44
  defaultValue: value?.start,
44
45
  });
45
46
 
46
- if (placeholder === undefined) {
47
+ function handleDefaultPlaceholder() {
48
+ if (placeholder !== undefined) return;
47
49
  placeholder = defaultPlaceholder;
48
50
  }
49
51
 
50
- if (value === undefined) {
51
- const defaultValue = { start: undefined, end: undefined };
52
- value = defaultValue;
52
+ // SSR
53
+ handleDefaultPlaceholder();
54
+
55
+ watch.pre(
56
+ () => placeholder,
57
+ () => {
58
+ handleDefaultPlaceholder();
59
+ }
60
+ );
61
+
62
+ function handleDefaultValue() {
63
+ if (value !== undefined) return;
64
+ value = { start: undefined, end: undefined };
53
65
  }
54
66
 
67
+ // SSR
68
+ handleDefaultValue();
69
+
70
+ watch.pre(
71
+ () => value,
72
+ () => {
73
+ handleDefaultValue();
74
+ }
75
+ );
76
+
55
77
  const rootState = useRangeCalendarRoot({
56
78
  id: box.with(() => id),
57
79
  ref: box.with(
@@ -8,6 +8,7 @@
8
8
  let {
9
9
  id = useId(),
10
10
  ref = $bindable(null),
11
+ delay = () => 50,
11
12
  child,
12
13
  children,
13
14
  ...restProps
@@ -19,6 +20,7 @@
19
20
  () => ref,
20
21
  (v) => (ref = v)
21
22
  ),
23
+ delay: box.with(() => delay),
22
24
  });
23
25
 
24
26
  const mergedProps = $derived(mergeProps(restProps, scrollButtonState.props));
@@ -8,6 +8,7 @@
8
8
  let {
9
9
  id = useId(),
10
10
  ref = $bindable(null),
11
+ delay = () => 50,
11
12
  child,
12
13
  children,
13
14
  ...restProps
@@ -19,6 +20,7 @@
19
20
  () => ref,
20
21
  (v) => (ref = v)
21
22
  ),
23
+ delay: box.with(() => delay),
22
24
  });
23
25
 
24
26
  const mergedProps = $derived(mergeProps(restProps, scrollButtonState.props));
@@ -5,6 +5,7 @@
5
5
  import { useSelectRoot } from "../select.svelte.js";
6
6
  import type { SelectRootProps } from "../types.js";
7
7
  import SelectHiddenInput from "./select-hidden-input.svelte";
8
+ import { watch } from "runed";
8
9
 
9
10
  let {
10
11
  value = $bindable(),
@@ -22,12 +23,21 @@
22
23
  children,
23
24
  }: SelectRootProps = $props();
24
25
 
25
- if (value === undefined) {
26
- const defaultValue = type === "single" ? "" : [];
27
-
28
- value = defaultValue;
26
+ function handleDefaultValue() {
27
+ if (value !== undefined) return;
28
+ value = type === "single" ? "" : [];
29
29
  }
30
30
 
31
+ // SSR
32
+ handleDefaultValue();
33
+
34
+ watch.pre(
35
+ () => value,
36
+ () => {
37
+ handleDefaultValue();
38
+ }
39
+ );
40
+
31
41
  const rootState = useSelectRoot({
32
42
  type,
33
43
  value: box.with(
@@ -304,12 +304,14 @@ declare class SelectViewportState {
304
304
  };
305
305
  };
306
306
  }
307
- type SelectScrollButtonImplStateProps = WithRefProps;
307
+ type SelectScrollButtonImplStateProps = WithRefProps & ReadableBoxedValues<{
308
+ delay: (tick: number) => number;
309
+ }>;
308
310
  declare class SelectScrollButtonImplState {
309
311
  readonly opts: SelectScrollButtonImplStateProps;
310
312
  readonly content: SelectContentState;
311
313
  root: SelectBaseRootState;
312
- autoScrollInterval: number | null;
314
+ autoScrollTimer: number | null;
313
315
  userScrollTimer: number;
314
316
  isUserScrolling: boolean;
315
317
  onAutoScroll: () => void;
@@ -318,7 +320,7 @@ declare class SelectScrollButtonImplState {
318
320
  handleUserScroll(): void;
319
321
  clearAutoScrollInterval(): void;
320
322
  onpointerdown(_: BitsPointerEvent): void;
321
- onpointermove(_: BitsPointerEvent): void;
323
+ onpointermove(e: BitsPointerEvent): void;
322
324
  onpointerleave(_: BitsPointerEvent): void;
323
325
  props: {
324
326
  readonly id: string;
@@ -327,7 +329,7 @@ declare class SelectScrollButtonImplState {
327
329
  readonly flexShrink: 0;
328
330
  };
329
331
  readonly onpointerdown: (_: BitsPointerEvent) => void;
330
- readonly onpointermove: (_: BitsPointerEvent) => void;
332
+ readonly onpointermove: (e: BitsPointerEvent) => void;
331
333
  readonly onpointerleave: (_: BitsPointerEvent) => void;
332
334
  };
333
335
  }
@@ -351,7 +353,7 @@ declare class SelectScrollDownButtonState {
351
353
  readonly flexShrink: 0;
352
354
  };
353
355
  readonly onpointerdown: (_: BitsPointerEvent) => void;
354
- readonly onpointermove: (_: BitsPointerEvent) => void;
356
+ readonly onpointermove: (e: BitsPointerEvent) => void;
355
357
  readonly onpointerleave: (_: BitsPointerEvent) => void;
356
358
  };
357
359
  }
@@ -374,7 +376,7 @@ declare class SelectScrollUpButtonState {
374
376
  readonly flexShrink: 0;
375
377
  };
376
378
  readonly onpointerdown: (_: BitsPointerEvent) => void;
377
- readonly onpointermove: (_: BitsPointerEvent) => void;
379
+ readonly onpointermove: (e: BitsPointerEvent) => void;
378
380
  readonly onpointerleave: (_: BitsPointerEvent) => void;
379
381
  };
380
382
  }
@@ -55,15 +55,14 @@ class SelectBaseRootState {
55
55
  setHighlightedNode(node, initial = false) {
56
56
  this.highlightedNode = node;
57
57
  if (node && (this.isUsingKeyboard || initial)) {
58
- node.scrollIntoView({ block: "nearest" });
58
+ node.scrollIntoView({ block: this.opts.scrollAlignment.current });
59
59
  }
60
60
  }
61
61
  getCandidateNodes() {
62
62
  const node = this.contentNode;
63
63
  if (!node)
64
64
  return [];
65
- const nodes = Array.from(node.querySelectorAll(`[${this.bitsAttrs.item}]:not([data-disabled])`));
66
- return nodes;
65
+ return Array.from(node.querySelectorAll(`[${this.bitsAttrs.item}]:not([data-disabled])`));
67
66
  }
68
67
  setHighlightedToFirstCandidate() {
69
68
  this.setHighlightedNode(null);
@@ -817,7 +816,10 @@ class SelectItemState {
817
816
  : undefined,
818
817
  "data-value": this.opts.value.current,
819
818
  "data-disabled": getDataDisabled(this.opts.disabled.current),
820
- "data-highlighted": this.root.highlightedValue === this.opts.value.current ? "" : undefined,
819
+ "data-highlighted": this.root.highlightedValue === this.opts.value.current &&
820
+ !this.opts.disabled.current
821
+ ? ""
822
+ : undefined,
821
823
  "data-selected": this.root.includesItem(this.opts.value.current) ? "" : undefined,
822
824
  "data-label": this.opts.label.current,
823
825
  [this.root.bitsAttrs.item]: "",
@@ -921,7 +923,7 @@ class SelectScrollButtonImplState {
921
923
  opts;
922
924
  content;
923
925
  root;
924
- autoScrollInterval = null;
926
+ autoScrollTimer = null;
925
927
  userScrollTimer = -1;
926
928
  isUserScrolling = false;
927
929
  onAutoScroll = noop;
@@ -959,24 +961,22 @@ class SelectScrollButtonImplState {
959
961
  }, 200);
960
962
  }
961
963
  clearAutoScrollInterval() {
962
- if (this.autoScrollInterval === null)
964
+ if (this.autoScrollTimer === null)
963
965
  return;
964
- window.clearInterval(this.autoScrollInterval);
965
- this.autoScrollInterval = null;
966
+ window.clearTimeout(this.autoScrollTimer);
967
+ this.autoScrollTimer = null;
966
968
  }
967
969
  onpointerdown(_) {
968
- if (this.autoScrollInterval !== null)
970
+ if (this.autoScrollTimer !== null)
969
971
  return;
970
- this.autoScrollInterval = window.setInterval(() => {
972
+ const autoScroll = (tick) => {
971
973
  this.onAutoScroll();
972
- }, 50);
974
+ this.autoScrollTimer = window.setTimeout(() => autoScroll(tick + 1), this.opts.delay.current(tick));
975
+ };
976
+ this.autoScrollTimer = window.setTimeout(() => autoScroll(1), this.opts.delay.current(0));
973
977
  }
974
- onpointermove(_) {
975
- if (this.autoScrollInterval !== null)
976
- return;
977
- this.autoScrollInterval = window.setInterval(() => {
978
- this.onAutoScroll();
979
- }, 50);
978
+ onpointermove(e) {
979
+ this.onpointerdown(e);
980
980
  }
981
981
  onpointerleave(_) {
982
982
  this.clearAutoScrollInterval();
@@ -1018,7 +1018,7 @@ class SelectScrollDownButtonState {
1018
1018
  }
1019
1019
  this.scrollIntoViewTimer = afterSleep(5, () => {
1020
1020
  const activeItem = this.root.highlightedNode;
1021
- activeItem?.scrollIntoView({ block: "nearest" });
1021
+ activeItem?.scrollIntoView({ block: this.root.opts.scrollAlignment.current });
1022
1022
  });
1023
1023
  });
1024
1024
  }
@@ -177,7 +177,16 @@ export type SelectArrowPropsWithoutHTML = ArrowPropsWithoutHTML;
177
177
  export type SelectArrowProps = ArrowProps;
178
178
  export type SelectViewportPropsWithoutHTML = WithChild;
179
179
  export type SelectViewportProps = SelectViewportPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, SelectViewportPropsWithoutHTML>;
180
- export type SelectScrollUpButtonPropsWithoutHTML = WithChild;
180
+ export type SelectScrollButtonPropsWithoutHTML = WithChild<{
181
+ /**
182
+ * Controls the initial delay (tick 0) and delay between auto-scrolls in milliseconds.
183
+ * The default function always returns 50ms.
184
+ *
185
+ * @param tick current tick number
186
+ */
187
+ delay?: (tick: number) => number;
188
+ }>;
189
+ export type SelectScrollUpButtonPropsWithoutHTML = SelectScrollButtonPropsWithoutHTML;
181
190
  export type SelectScrollUpButtonProps = SelectScrollUpButtonPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, SelectScrollUpButtonPropsWithoutHTML>;
182
- export type SelectScrollDownButtonPropsWithoutHTML = WithChild;
191
+ export type SelectScrollDownButtonPropsWithoutHTML = SelectScrollButtonPropsWithoutHTML;
183
192
  export type SelectScrollDownButtonProps = SelectScrollDownButtonPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, SelectScrollDownButtonPropsWithoutHTML>;
@@ -4,6 +4,7 @@
4
4
  import { useSliderRoot } from "../slider.svelte.js";
5
5
  import { useId } from "../../../internal/use-id.js";
6
6
  import { noop } from "../../../internal/noop.js";
7
+ import { watch } from "runed";
7
8
 
8
9
  let {
9
10
  children,
@@ -24,10 +25,21 @@
24
25
  ...restProps
25
26
  }: SliderRootProps = $props();
26
27
 
27
- if (value === undefined) {
28
+ function handleDefaultValue() {
29
+ if (value !== undefined) return;
28
30
  value = type === "single" ? 0 : [];
29
31
  }
30
32
 
33
+ // SSR
34
+ handleDefaultValue();
35
+
36
+ watch.pre(
37
+ () => value,
38
+ () => {
39
+ handleDefaultValue();
40
+ }
41
+ );
42
+
31
43
  const rootState = useSliderRoot({
32
44
  id: box.with(() => id),
33
45
  ref: box.with(
@@ -229,8 +229,8 @@ class SliderSingleRootState extends SliderBaseRootState {
229
229
  }
230
230
  const currValue = this.opts.value.current;
231
231
  return Array.from({ length: count }, (_, i) => {
232
- const tickPosition = i * (step / difference) * 100;
233
- const scale = linearScale([this.opts.min.current, this.opts.max.current], this.getThumbScale());
232
+ const tickPosition = i * step;
233
+ const scale = linearScale([0, (count - 1) * step], this.getThumbScale());
234
234
  const isFirst = i === 0;
235
235
  const isLast = i === count - 1;
236
236
  const offsetPercentage = isFirst ? 0 : isLast ? -100 : -50;
@@ -484,11 +484,12 @@ class SliderMultiRootState extends SliderBaseRootState {
484
484
  }
485
485
  const currValue = this.opts.value.current;
486
486
  return Array.from({ length: count }, (_, i) => {
487
- const tickPosition = i * (step / difference) * 100;
487
+ const tickPosition = i * step;
488
+ const scale = linearScale([0, (count - 1) * step], this.getThumbScale());
488
489
  const isFirst = i === 0;
489
490
  const isLast = i === count - 1;
490
491
  const offsetPercentage = isFirst ? 0 : isLast ? -100 : -50;
491
- const style = getTickStyles(this.direction, tickPosition, offsetPercentage);
492
+ const style = getTickStyles(this.direction, scale(tickPosition), offsetPercentage);
492
493
  const tickValue = min + i * step;
493
494
  const bounded = currValue.length === 1
494
495
  ? tickValue <= currValue[0]
@@ -5,6 +5,7 @@
5
5
  import { useToggleGroupRoot } from "../toggle-group.svelte.js";
6
6
  import { useId } from "../../../internal/use-id.js";
7
7
  import { noop } from "../../../internal/noop.js";
8
+ import { watch } from "runed";
8
9
 
9
10
  let {
10
11
  id = useId(),
@@ -21,12 +22,21 @@
21
22
  ...restProps
22
23
  }: ToggleGroupRootProps = $props();
23
24
 
24
- if (value === undefined) {
25
- const defaultValue = type === "single" ? "" : [];
26
-
27
- value = defaultValue;
25
+ function handleDefaultValue() {
26
+ if (value !== undefined) return;
27
+ value = type === "single" ? "" : [];
28
28
  }
29
29
 
30
+ // SSR
31
+ handleDefaultValue();
32
+
33
+ watch.pre(
34
+ () => value,
35
+ () => {
36
+ handleDefaultValue();
37
+ }
38
+ );
39
+
30
40
  const rootState = useToggleGroupRoot({
31
41
  id: box.with(() => id),
32
42
  value: box.with(
@@ -5,6 +5,7 @@
5
5
  import { useToolbarGroup } from "../toolbar.svelte.js";
6
6
  import { useId } from "../../../internal/use-id.js";
7
7
  import { noop } from "../../../internal/noop.js";
8
+ import { watch } from "runed";
8
9
 
9
10
  let {
10
11
  id = useId(),
@@ -18,11 +19,21 @@
18
19
  ...restProps
19
20
  }: ToolbarGroupProps = $props();
20
21
 
21
- if (value === undefined) {
22
- const defaultValue = type === "single" ? "" : [];
23
- value = defaultValue;
22
+ function handleDefaultValue() {
23
+ if (value !== undefined) return;
24
+ value = type === "single" ? "" : [];
24
25
  }
25
26
 
27
+ // SSR
28
+ handleDefaultValue();
29
+
30
+ watch.pre(
31
+ () => value,
32
+ () => {
33
+ handleDefaultValue();
34
+ }
35
+ );
36
+
26
37
  const groupState = useToolbarGroup({
27
38
  id: box.with(() => id),
28
39
  disabled: box.with(() => disabled),
@@ -125,7 +125,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
125
125
  }
126
126
  function handleClose(prevFocusedElement) {
127
127
  const destroyEvent = AutoFocusOnDestroyEvent.createEvent();
128
- onCloseAutoFocus.current(destroyEvent);
128
+ onCloseAutoFocus.current?.(destroyEvent);
129
129
  const shouldIgnore = ctx.ignoreCloseAutoFocus;
130
130
  afterSleep(0, () => {
131
131
  if (!destroyEvent.defaultPrevented && prevFocusedElement && !shouldIgnore) {
@@ -10,13 +10,12 @@ export function useDOMTypeahead(opts) {
10
10
  return;
11
11
  search.current = search.current + key;
12
12
  const currentItem = getCurrentItem();
13
- const currentMatch = candidates.find((item) => item === currentItem)?.textContent ?? "";
14
- const values = candidates.map((item) => item.textContent ?? "");
13
+ const currentMatch = candidates.find((item) => item === currentItem)?.textContent?.trim() ?? "";
14
+ const values = candidates.map((item) => item.textContent?.trim() ?? "");
15
15
  const nextMatch = getNextMatch(values, search.current, currentMatch);
16
- const newItem = candidates.find((item) => item.textContent === nextMatch);
17
- if (newItem) {
16
+ const newItem = candidates.find((item) => item.textContent?.trim() === nextMatch);
17
+ if (newItem)
18
18
  onMatch(newItem);
19
- }
20
19
  return newItem;
21
20
  }
22
21
  function resetTypeahead() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.3.19",
3
+ "version": "1.4.1",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",