bits-ui 1.4.8 → 1.5.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.
@@ -19,4 +19,5 @@ export { default as NextButton } from "../calendar/components/calendar-next-butt
19
19
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
20
20
  export { default as Cell } from "../calendar/components/calendar-cell.svelte";
21
21
  export { default as Day } from "../calendar/components/calendar-day.svelte";
22
- export type { DatePickerRootProps as RootProps, DatePickerLabelProps as LabelProps, DatePickerInputProps as InputProps, DatePickerSegmentProps as SegmentProps, DatePickerArrowProps as ArrowProps, DatePickerCloseProps as CloseProps, DatePickerContentProps as ContentProps, DatePickerContentStaticProps as ContentStaticProps, DatePickerTriggerProps as TriggerProps, DatePickerCalendarProps as CalendarProps, DatePickerCellProps as CellProps, DatePickerDayProps as DayProps, DatePickerGridBodyProps as GridBodyProps, DatePickerGridHeadProps as GridHeadProps, DatePickerGridProps as GridProps, DatePickerGridRowProps as GridRowProps, DatePickerHeadCellProps as HeadCellProps, DatePickerHeaderProps as HeaderProps, DatePickerHeadingProps as HeadingProps, DatePickerNextButtonProps as NextButtonProps, DatePickerPrevButtonProps as PrevButtonProps, } from "./types.js";
22
+ export { default as Portal } from "../utilities/portal/portal.svelte";
23
+ export type { DatePickerRootProps as RootProps, DatePickerLabelProps as LabelProps, DatePickerInputProps as InputProps, DatePickerSegmentProps as SegmentProps, DatePickerArrowProps as ArrowProps, DatePickerCloseProps as CloseProps, DatePickerContentProps as ContentProps, DatePickerContentStaticProps as ContentStaticProps, DatePickerTriggerProps as TriggerProps, DatePickerCalendarProps as CalendarProps, DatePickerCellProps as CellProps, DatePickerDayProps as DayProps, DatePickerGridBodyProps as GridBodyProps, DatePickerGridHeadProps as GridHeadProps, DatePickerGridProps as GridProps, DatePickerGridRowProps as GridRowProps, DatePickerHeadCellProps as HeadCellProps, DatePickerHeaderProps as HeaderProps, DatePickerHeadingProps as HeadingProps, DatePickerNextButtonProps as NextButtonProps, DatePickerPrevButtonProps as PrevButtonProps, DatePickerPortalProps as PortalProps, } from "./types.js";
@@ -19,3 +19,4 @@ export { default as NextButton } from "../calendar/components/calendar-next-butt
19
19
  export { default as PrevButton } from "../calendar/components/calendar-prev-button.svelte";
20
20
  export { default as Cell } from "../calendar/components/calendar-cell.svelte";
21
21
  export { default as Day } from "../calendar/components/calendar-day.svelte";
22
+ export { default as Portal } from "../utilities/portal/portal.svelte";
@@ -4,6 +4,7 @@ import type { BitsPrimitiveDivAttributes } from "../../shared/attributes.js";
4
4
  import type { CalendarRootSnippetProps } from "../../types.js";
5
5
  import type { DateMatcher, DateOnInvalid, DateValidator, EditableSegmentPart } from "../../shared/index.js";
6
6
  import type { Granularity, WeekStartsOn } from "../../shared/date/types.js";
7
+ import type { PortalProps } from "../utilities/portal/index.js";
7
8
  export type DatePickerRootPropsWithoutHTML = WithChildren<{
8
9
  /**
9
10
  * The value of the date picker.
@@ -231,4 +232,6 @@ export type { PopoverTriggerPropsWithoutHTML as DatePickerTriggerPropsWithoutHTM
231
232
  export type { DateFieldInputPropsWithoutHTML as DatePickerInputPropsWithoutHTML, DateFieldInputProps as DatePickerInputProps, DateFieldLabelPropsWithoutHTML as DatePickerLabelPropsWithoutHTML, DateFieldLabelProps as DatePickerLabelProps, DateFieldSegmentPropsWithoutHTML as DatePickerSegmentPropsWithoutHTML, DateFieldSegmentProps as DatePickerSegmentProps, } from "../date-field/types.js";
232
233
  export type DatePickerCalendarPropsWithoutHTML = WithChild<{}, CalendarRootSnippetProps>;
233
234
  export type DatePickerCalendarProps = DatePickerCalendarPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, DatePickerCalendarPropsWithoutHTML>;
235
+ export type DatePickerPortalPropsWithoutHTML = PortalProps;
236
+ export type DatePickerPortalProps = DatePickerPortalPropsWithoutHTML;
234
237
  export type { CalendarCellPropsWithoutHTML as DatePickerCellPropsWithoutHTML, CalendarCellProps as DatePickerCellProps, CalendarDayPropsWithoutHTML as DatePickerDayPropsWithoutHTML, CalendarDayProps as DatePickerDayProps, CalendarGridPropsWithoutHTML as DatePickerGridPropsWithoutHTML, CalendarGridProps as DatePickerGridProps, CalendarGridBodyPropsWithoutHTML as DatePickerGridBodyPropsWithoutHTML, CalendarGridBodyProps as DatePickerGridBodyProps, CalendarGridHeadPropsWithoutHTML as DatePickerGridHeadPropsWithoutHTML, CalendarGridHeadProps as DatePickerGridHeadProps, CalendarGridRowPropsWithoutHTML as DatePickerGridRowPropsWithoutHTML, CalendarGridRowProps as DatePickerGridRowProps, CalendarHeadCellPropsWithoutHTML as DatePickerHeadCellPropsWithoutHTML, CalendarHeadCellProps as DatePickerHeadCellProps, CalendarHeaderPropsWithoutHTML as DatePickerHeaderPropsWithoutHTML, CalendarHeaderProps as DatePickerHeaderProps, CalendarHeadingPropsWithoutHTML as DatePickerHeadingPropsWithoutHTML, CalendarHeadingProps as DatePickerHeadingProps, CalendarNextButtonPropsWithoutHTML as DatePickerNextButtonPropsWithoutHTML, CalendarNextButtonProps as DatePickerNextButtonProps, CalendarPrevButtonPropsWithoutHTML as DatePickerPrevButtonPropsWithoutHTML, CalendarPrevButtonProps as DatePickerPrevButtonProps, } from "../calendar/types.js";
@@ -1,20 +1,23 @@
1
1
  <script lang="ts">
2
2
  import { box, mergeProps } from "svelte-toolbelt";
3
- import type { MenuItemProps } from "../types.js";
3
+ import type { MenuSubTriggerProps } from "../types.js";
4
4
  import { useMenuSubTrigger } from "../menu.svelte.js";
5
5
  import { useId } from "../../../internal/use-id.js";
6
6
  import FloatingLayerAnchor from "../../utilities/floating-layer/components/floating-layer-anchor.svelte";
7
+ import { noop } from "../../../internal/noop.js";
7
8
  let {
8
9
  id = useId(),
9
10
  disabled = false,
10
11
  ref = $bindable(null),
11
12
  children,
12
13
  child,
14
+ onSelect = noop,
13
15
  ...restProps
14
- }: MenuItemProps = $props();
16
+ }: MenuSubTriggerProps = $props();
15
17
 
16
18
  const subTriggerState = useMenuSubTrigger({
17
19
  disabled: box.with(() => disabled),
20
+ onSelect: box.with(() => onSelect),
18
21
  id: box.with(() => id),
19
22
  ref: box.with(
20
23
  () => ref,
@@ -1,4 +1,4 @@
1
- import type { MenuItemProps } from "../types.js";
2
- declare const MenuSubTrigger: import("svelte").Component<MenuItemProps, {}, "ref">;
1
+ import type { MenuSubTriggerProps } from "../types.js";
2
+ declare const MenuSubTrigger: import("svelte").Component<MenuSubTriggerProps, {}, "ref">;
3
3
  type MenuSubTrigger = ReturnType<typeof MenuSubTrigger>;
4
4
  export default MenuSubTrigger;
@@ -146,10 +146,11 @@ declare class MenuItemState {
146
146
  }
147
147
  declare class MenuSubTriggerState {
148
148
  #private;
149
+ readonly opts: MenuItemSharedStateProps & Pick<MenuItemStateProps, "onSelect">;
149
150
  readonly item: MenuItemSharedState;
150
151
  readonly content: MenuContentState;
151
152
  readonly submenu: MenuMenuState;
152
- constructor(item: MenuItemSharedState, content: MenuContentState, submenu: MenuMenuState);
153
+ constructor(opts: MenuItemSharedStateProps & Pick<MenuItemStateProps, "onSelect">, item: MenuItemSharedState, content: MenuContentState, submenu: MenuMenuState);
153
154
  onpointermove(e: BitsPointerEvent): void;
154
155
  onpointerleave(e: BitsPointerEvent): void;
155
156
  onkeydown(e: BitsKeyboardEvent): void;
@@ -363,7 +364,7 @@ type MenuItemCombinedProps = MenuItemSharedStateProps & MenuItemStateProps;
363
364
  export declare function useMenuRoot(props: MenuRootStateProps): MenuRootState;
364
365
  export declare function useMenuMenu(root: MenuRootState, props: MenuMenuStateProps): MenuMenuState;
365
366
  export declare function useMenuSubmenu(props: MenuMenuStateProps): MenuMenuState;
366
- export declare function useMenuSubTrigger(props: MenuItemSharedStateProps): MenuSubTriggerState;
367
+ export declare function useMenuSubTrigger(props: MenuItemSharedStateProps & Pick<MenuItemStateProps, "onSelect">): MenuSubTriggerState;
367
368
  export declare function useMenuDropdownTrigger(props: DropdownMenuTriggerStateProps): DropdownMenuTriggerState;
368
369
  export declare function useMenuContextTrigger(props: ContextMenuTriggerStateProps): ContextMenuTriggerState;
369
370
  export declare function useMenuContent(props: MenuContentStateProps): MenuContentState;
@@ -434,11 +434,13 @@ class MenuItemState {
434
434
  }));
435
435
  }
436
436
  class MenuSubTriggerState {
437
+ opts;
437
438
  item;
438
439
  content;
439
440
  submenu;
440
441
  #openTimer = null;
441
- constructor(item, content, submenu) {
442
+ constructor(opts, item, content, submenu) {
443
+ this.opts = opts;
442
444
  this.item = item;
443
445
  this.content = content;
444
446
  this.submenu = submenu;
@@ -485,13 +487,7 @@ class MenuSubTriggerState {
485
487
  if (this.item.opts.disabled.current || (isTypingAhead && e.key === kbd.SPACE))
486
488
  return;
487
489
  if (SUB_OPEN_KEYS[this.submenu.root.opts.dir.current].includes(e.key)) {
488
- this.submenu.onOpen();
489
- afterTick(() => {
490
- const contentNode = this.submenu.contentNode;
491
- if (!contentNode)
492
- return;
493
- MenuOpenEvent.dispatch(contentNode);
494
- });
490
+ e.currentTarget.click();
495
491
  e.preventDefault();
496
492
  }
497
493
  }
@@ -506,8 +502,19 @@ class MenuSubTriggerState {
506
502
  if (!isHTMLElement(e.currentTarget))
507
503
  return;
508
504
  e.currentTarget.focus();
505
+ const selectEvent = new CustomEvent("menusubtriggerselect", {
506
+ bubbles: true,
507
+ cancelable: true,
508
+ });
509
+ this.opts.onSelect.current(selectEvent);
509
510
  if (!this.submenu.opts.open.current) {
510
511
  this.submenu.onOpen();
512
+ afterTick(() => {
513
+ const contentNode = this.submenu.contentNode;
514
+ if (!contentNode)
515
+ return;
516
+ MenuOpenEvent.dispatch(contentNode);
517
+ });
511
518
  }
512
519
  }
513
520
  props = $derived.by(() => mergeProps({
@@ -832,7 +839,7 @@ export function useMenuSubTrigger(props) {
832
839
  const content = MenuContentContext.get();
833
840
  const item = new MenuItemSharedState(props, content);
834
841
  const submenu = MenuMenuContext.get();
835
- return new MenuSubTriggerState(item, content, submenu);
842
+ return new MenuSubTriggerState(props, item, content, submenu);
836
843
  }
837
844
  export function useMenuDropdownTrigger(props) {
838
845
  return new DropdownMenuTriggerState(props, MenuMenuContext.get());
@@ -124,8 +124,8 @@ export type MenuSubContentPropsWithoutHTML = Expand<WithChildNoChildrenSnippetPr
124
124
  export type MenuSubContentProps = MenuSubContentPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, MenuSubContentPropsWithoutHTML>;
125
125
  export type MenuSubContentStaticPropsWithoutHTML = Expand<WithChildNoChildrenSnippetProps<Omit<PopperLayerStaticProps, "content" | "preventScroll"> & _SharedMenuContentProps, StaticContentSnippetProps>>;
126
126
  export type MenuSubContentStaticProps = MenuSubContentStaticPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, MenuSubContentStaticPropsWithoutHTML>;
127
- export type MenuSubTriggerPropsWithoutHTML = MenuItemPropsWithoutHTML;
128
- export type MenuSubTriggerProps = MenuItemProps;
127
+ export type MenuSubTriggerPropsWithoutHTML = Omit<MenuItemPropsWithoutHTML, "closeOnSelect">;
128
+ export type MenuSubTriggerProps = Omit<MenuItemProps, "closeOnSelect">;
129
129
  export type MenuSeparatorPropsWithoutHTML = WithChild;
130
130
  export type MenuSeparatorProps = MenuSeparatorPropsWithoutHTML & Without<BitsPrimitiveDivAttributes, MenuSeparatorPropsWithoutHTML>;
131
131
  export type MenuArrowPropsWithoutHTML = ArrowPropsWithoutHTML;
@@ -251,7 +251,10 @@ class ScrollAreaScrollbarVisibleState {
251
251
  });
252
252
  thumbRatio = $derived.by(() => getThumbRatio(this.sizes.viewport, this.sizes.content));
253
253
  hasThumb = $derived.by(() => Boolean(this.thumbRatio > 0 && this.thumbRatio < 1));
254
- prevTransformStyle = "";
254
+ // this needs to be a $state to properly restore the transform style when the scrollbar
255
+ // goes from a hidden to visible state, otherwise it will start at the beginning of the
256
+ // scrollbar and flicker to the correct position after
257
+ prevTransformStyle = $state("");
255
258
  constructor(scrollbar) {
256
259
  this.scrollbar = scrollbar;
257
260
  this.root = scrollbar.root;
@@ -292,6 +295,7 @@ class ScrollAreaScrollbarVisibleState {
292
295
  });
293
296
  const transformStyle = `translate3d(${offset}px, 0, 0)`;
294
297
  this.thumbNode.style.transform = transformStyle;
298
+ this.prevTransformStyle = transformStyle;
295
299
  }
296
300
  xOnWheelScroll(scrollPos) {
297
301
  if (!this.root.viewportNode)
@@ -310,6 +314,7 @@ class ScrollAreaScrollbarVisibleState {
310
314
  const offset = getThumbOffsetFromScroll({ scrollPos, sizes: this.sizes });
311
315
  const transformStyle = `translate3d(0, ${offset}px, 0)`;
312
316
  this.thumbNode.style.transform = transformStyle;
317
+ this.prevTransformStyle = transformStyle;
313
318
  }
314
319
  yOnWheelScroll(scrollPos) {
315
320
  if (!this.root.viewportNode)
@@ -533,12 +538,12 @@ class ScrollAreaScrollbarSharedState {
533
538
  });
534
539
  return unsubListener;
535
540
  });
536
- $effect(() => {
541
+ $effect.pre(() => {
537
542
  // react to changes to this:
538
543
  this.scrollbarVis.sizes;
539
544
  untrack(() => this.handleThumbPositionChange());
540
545
  });
541
- $effect(() => {
546
+ $effect.pre(() => {
542
547
  this.handleThumbPositionChange();
543
548
  });
544
549
  useResizeObserver(() => this.scrollbar.opts.ref.current, this.handleResize);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bits-ui",
3
- "version": "1.4.8",
3
+ "version": "1.5.0",
4
4
  "license": "MIT",
5
5
  "repository": "github:huntabyte/bits-ui",
6
6
  "funding": "https://github.com/sponsors/huntabyte",