bits-ui 1.3.19 → 1.4.0

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.
@@ -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;
@@ -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));
@@ -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,7 +55,7 @@ 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() {
@@ -921,7 +921,7 @@ class SelectScrollButtonImplState {
921
921
  opts;
922
922
  content;
923
923
  root;
924
- autoScrollInterval = null;
924
+ autoScrollTimer = null;
925
925
  userScrollTimer = -1;
926
926
  isUserScrolling = false;
927
927
  onAutoScroll = noop;
@@ -959,24 +959,22 @@ class SelectScrollButtonImplState {
959
959
  }, 200);
960
960
  }
961
961
  clearAutoScrollInterval() {
962
- if (this.autoScrollInterval === null)
962
+ if (this.autoScrollTimer === null)
963
963
  return;
964
- window.clearInterval(this.autoScrollInterval);
965
- this.autoScrollInterval = null;
964
+ window.clearTimeout(this.autoScrollTimer);
965
+ this.autoScrollTimer = null;
966
966
  }
967
967
  onpointerdown(_) {
968
- if (this.autoScrollInterval !== null)
968
+ if (this.autoScrollTimer !== null)
969
969
  return;
970
- this.autoScrollInterval = window.setInterval(() => {
970
+ const autoScroll = (tick) => {
971
971
  this.onAutoScroll();
972
- }, 50);
972
+ this.autoScrollTimer = window.setTimeout(() => autoScroll(tick + 1), this.opts.delay.current(tick));
973
+ };
974
+ this.autoScrollTimer = window.setTimeout(() => autoScroll(1), this.opts.delay.current(0));
973
975
  }
974
- onpointermove(_) {
975
- if (this.autoScrollInterval !== null)
976
- return;
977
- this.autoScrollInterval = window.setInterval(() => {
978
- this.onAutoScroll();
979
- }, 50);
976
+ onpointermove(e) {
977
+ this.onpointerdown(e);
980
978
  }
981
979
  onpointerleave(_) {
982
980
  this.clearAutoScrollInterval();
@@ -1018,7 +1016,7 @@ class SelectScrollDownButtonState {
1018
1016
  }
1019
1017
  this.scrollIntoViewTimer = afterSleep(5, () => {
1020
1018
  const activeItem = this.root.highlightedNode;
1021
- activeItem?.scrollIntoView({ block: "nearest" });
1019
+ activeItem?.scrollIntoView({ block: this.root.opts.scrollAlignment.current });
1022
1020
  });
1023
1021
  });
1024
1022
  }
@@ -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>;
@@ -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]
@@ -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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.3.19",
3
+ "version": "1.4.0",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",