bits-ui 2.3.0 → 2.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.
Files changed (110) hide show
  1. package/dist/bits/accordion/accordion.svelte.d.ts +0 -5
  2. package/dist/bits/accordion/accordion.svelte.js +11 -14
  3. package/dist/bits/aspect-ratio/aspect-ratio.svelte.d.ts +0 -1
  4. package/dist/bits/aspect-ratio/aspect-ratio.svelte.js +6 -2
  5. package/dist/bits/avatar/avatar.svelte.d.ts +0 -3
  6. package/dist/bits/avatar/avatar.svelte.js +8 -6
  7. package/dist/bits/calendar/calendar.svelte.d.ts +2 -2
  8. package/dist/bits/calendar/calendar.svelte.js +4 -4
  9. package/dist/bits/calendar/components/calendar.svelte +4 -3
  10. package/dist/bits/checkbox/checkbox.svelte.d.ts +0 -3
  11. package/dist/bits/checkbox/checkbox.svelte.js +14 -14
  12. package/dist/bits/collapsible/collapsible.svelte.d.ts +0 -3
  13. package/dist/bits/collapsible/collapsible.svelte.js +8 -7
  14. package/dist/bits/command/command.svelte.d.ts +0 -12
  15. package/dist/bits/command/command.svelte.js +35 -31
  16. package/dist/bits/date-field/components/date-field.svelte +4 -3
  17. package/dist/bits/date-field/date-field.svelte.d.ts +2 -4
  18. package/dist/bits/date-field/date-field.svelte.js +8 -6
  19. package/dist/bits/date-picker/components/date-picker-trigger.svelte +2 -2
  20. package/dist/bits/date-picker/components/date-picker.svelte +4 -3
  21. package/dist/bits/date-range-field/components/date-range-field.svelte +4 -3
  22. package/dist/bits/date-range-field/date-range-field.svelte.d.ts +1 -3
  23. package/dist/bits/date-range-field/date-range-field.svelte.js +7 -5
  24. package/dist/bits/date-range-picker/components/date-range-picker-trigger.svelte +2 -2
  25. package/dist/bits/date-range-picker/components/date-range-picker.svelte +4 -3
  26. package/dist/bits/dialog/dialog.svelte.d.ts +2 -12
  27. package/dist/bits/dialog/dialog.svelte.js +16 -24
  28. package/dist/bits/index.d.ts +1 -0
  29. package/dist/bits/index.js +1 -0
  30. package/dist/bits/label/label.svelte.d.ts +0 -1
  31. package/dist/bits/label/label.svelte.js +6 -2
  32. package/dist/bits/link-preview/link-preview.svelte.d.ts +0 -2
  33. package/dist/bits/link-preview/link-preview.svelte.js +7 -5
  34. package/dist/bits/menu/components/menu-sub-content-static.svelte +1 -1
  35. package/dist/bits/menu/components/menu-sub-content.svelte +1 -1
  36. package/dist/bits/menu/menu.svelte.d.ts +2 -1
  37. package/dist/bits/menu/menu.svelte.js +39 -21
  38. package/dist/bits/menubar/menubar.svelte.d.ts +1 -7
  39. package/dist/bits/menubar/menubar.svelte.js +12 -14
  40. package/dist/bits/meter/meter.svelte.d.ts +0 -1
  41. package/dist/bits/meter/meter.svelte.js +6 -2
  42. package/dist/bits/navigation-menu/navigation-menu.svelte.d.ts +2 -11
  43. package/dist/bits/navigation-menu/navigation-menu.svelte.js +30 -25
  44. package/dist/bits/pagination/pagination.svelte.d.ts +0 -4
  45. package/dist/bits/pagination/pagination.svelte.js +9 -10
  46. package/dist/bits/pin-input/pin-input.svelte.d.ts +0 -2
  47. package/dist/bits/pin-input/pin-input.svelte.js +7 -5
  48. package/dist/bits/popover/popover.svelte.d.ts +0 -3
  49. package/dist/bits/popover/popover.svelte.js +9 -5
  50. package/dist/bits/progress/progress.svelte.d.ts +0 -1
  51. package/dist/bits/progress/progress.svelte.js +6 -2
  52. package/dist/bits/radio-group/radio-group.svelte.d.ts +7 -9
  53. package/dist/bits/radio-group/radio-group.svelte.js +9 -10
  54. package/dist/bits/range-calendar/components/range-calendar.svelte +4 -3
  55. package/dist/bits/range-calendar/range-calendar.svelte.d.ts +38 -38
  56. package/dist/bits/range-calendar/range-calendar.svelte.js +79 -79
  57. package/dist/bits/rating-group/rating-group.svelte.d.ts +0 -2
  58. package/dist/bits/rating-group/rating-group.svelte.js +33 -11
  59. package/dist/bits/scroll-area/scroll-area.svelte.d.ts +15 -19
  60. package/dist/bits/scroll-area/scroll-area.svelte.js +10 -10
  61. package/dist/bits/select/select.svelte.d.ts +28 -30
  62. package/dist/bits/select/select.svelte.js +37 -49
  63. package/dist/bits/separator/separator.svelte.d.ts +1 -2
  64. package/dist/bits/separator/separator.svelte.js +6 -3
  65. package/dist/bits/slider/slider.svelte.d.ts +17 -24
  66. package/dist/bits/slider/slider.svelte.js +15 -17
  67. package/dist/bits/switch/switch.svelte.d.ts +6 -8
  68. package/dist/bits/switch/switch.svelte.js +7 -5
  69. package/dist/bits/tabs/tabs.svelte.d.ts +5 -9
  70. package/dist/bits/tabs/tabs.svelte.js +11 -11
  71. package/dist/bits/time-field/components/time-field.svelte +4 -3
  72. package/dist/bits/time-field/time-field.svelte.d.ts +1 -3
  73. package/dist/bits/time-field/time-field.svelte.js +7 -5
  74. package/dist/bits/time-range-field/components/time-range-field.svelte +4 -3
  75. package/dist/bits/time-range-field/time-range-field.svelte.d.ts +1 -3
  76. package/dist/bits/time-range-field/time-range-field.svelte.js +7 -5
  77. package/dist/bits/toggle/toggle.svelte.d.ts +3 -3
  78. package/dist/bits/toggle/toggle.svelte.js +6 -3
  79. package/dist/bits/toggle-group/toggle-group.svelte.d.ts +1 -2
  80. package/dist/bits/toggle-group/toggle-group.svelte.js +8 -6
  81. package/dist/bits/toolbar/toolbar.svelte.d.ts +11 -18
  82. package/dist/bits/toolbar/toolbar.svelte.js +14 -17
  83. package/dist/bits/tooltip/tooltip.svelte.d.ts +13 -14
  84. package/dist/bits/tooltip/tooltip.svelte.js +7 -5
  85. package/dist/bits/utilities/config/bits-config.d.ts +44 -0
  86. package/dist/bits/utilities/config/bits-config.js +92 -0
  87. package/dist/bits/utilities/config/components/bits-config.svelte +14 -0
  88. package/dist/bits/utilities/config/components/bits-config.svelte.d.ts +4 -0
  89. package/dist/bits/utilities/config/exports.d.ts +2 -0
  90. package/dist/bits/utilities/config/exports.js +2 -0
  91. package/dist/bits/utilities/config/index.d.ts +1 -0
  92. package/dist/bits/utilities/config/index.js +1 -0
  93. package/dist/bits/utilities/config/prop-resolvers.d.ts +13 -0
  94. package/dist/bits/utilities/config/prop-resolvers.js +37 -0
  95. package/dist/bits/utilities/config/types.d.ts +13 -0
  96. package/dist/bits/utilities/config/types.js +1 -0
  97. package/dist/bits/utilities/portal/portal.svelte +21 -21
  98. package/dist/bits/utilities/portal/types.d.ts +2 -1
  99. package/dist/index.d.ts +1 -1
  100. package/dist/index.js +1 -1
  101. package/dist/internal/attrs.d.ts +14 -0
  102. package/dist/internal/attrs.js +18 -0
  103. package/dist/internal/date-time/calendar-helpers.svelte.d.ts +1 -0
  104. package/dist/internal/date-time/calendar-helpers.svelte.js +18 -1
  105. package/dist/internal/use-arrow-navigation.d.ts +2 -2
  106. package/dist/internal/use-arrow-navigation.js +1 -1
  107. package/dist/internal/use-data-typeahead.svelte.d.ts +1 -1
  108. package/dist/internal/use-data-typeahead.svelte.js +1 -1
  109. package/dist/types.d.ts +1 -0
  110. package/package.json +1 -1
@@ -3,6 +3,7 @@ import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/bo
3
3
  import { type UseRovingFocusReturn } from "../../internal/use-roving-focus.svelte.js";
4
4
  import type { Orientation } from "../../shared/index.js";
5
5
  import type { BitsKeyboardEvent, BitsMouseEvent, WithRefProps } from "../../internal/types.js";
6
+ export declare const toolbarAttrs: import("../../internal/attrs.js").BitsAttrs<readonly ["root", "item", "group", "group-item", "link", "button"]>;
6
7
  type ToolbarRootStateProps = WithRefProps<ReadableBoxedValues<{
7
8
  orientation: Orientation;
8
9
  loop: boolean;
@@ -11,11 +12,10 @@ declare class ToolbarRootState {
11
12
  readonly opts: ToolbarRootStateProps;
12
13
  rovingFocusGroup: UseRovingFocusReturn;
13
14
  constructor(opts: ToolbarRootStateProps);
14
- props: {
15
+ readonly props: {
15
16
  readonly id: string;
16
17
  readonly role: "toolbar";
17
18
  readonly "data-orientation": Orientation;
18
- readonly "data-toolbar-root": "";
19
19
  };
20
20
  }
21
21
  type ToolbarGroupBaseStateProps = WithRefProps<ReadableBoxedValues<{
@@ -25,9 +25,8 @@ declare class ToolbarGroupBaseState {
25
25
  readonly opts: ToolbarGroupBaseStateProps;
26
26
  readonly root: ToolbarRootState;
27
27
  constructor(opts: ToolbarGroupBaseStateProps, root: ToolbarRootState);
28
- props: {
28
+ readonly props: {
29
29
  readonly id: string;
30
- readonly "data-toolbar-group": "";
31
30
  readonly role: "group";
32
31
  readonly "data-orientation": "horizontal" | "vertical";
33
32
  readonly "data-disabled": "" | undefined;
@@ -39,8 +38,8 @@ type ToolbarGroupSingleStateProps = ToolbarGroupBaseStateProps & WritableBoxedVa
39
38
  declare class ToolbarGroupSingleState extends ToolbarGroupBaseState {
40
39
  readonly opts: ToolbarGroupSingleStateProps;
41
40
  readonly root: ToolbarRootState;
42
- isMulti: boolean;
43
- anyPressed: boolean;
41
+ readonly isMulti: false;
42
+ readonly anyPressed: boolean;
44
43
  constructor(opts: ToolbarGroupSingleStateProps, root: ToolbarRootState);
45
44
  includesItem(item: string): boolean;
46
45
  toggleItem(item: string): void;
@@ -51,8 +50,8 @@ type ToolbarGroupMultipleStateProps = ToolbarGroupBaseStateProps & WritableBoxed
51
50
  declare class ToolbarGroupMultipleState extends ToolbarGroupBaseState {
52
51
  readonly opts: ToolbarGroupMultipleStateProps;
53
52
  readonly root: ToolbarRootState;
54
- isMulti: boolean;
55
- anyPressed: boolean;
53
+ readonly isMulti: true;
54
+ readonly anyPressed: boolean;
56
55
  constructor(opts: ToolbarGroupMultipleStateProps, root: ToolbarRootState);
57
56
  includesItem(item: string): boolean;
58
57
  toggleItem(item: string): void;
@@ -70,8 +69,8 @@ declare class ToolbarGroupItemState {
70
69
  constructor(opts: ToolbarGroupItemStateProps, group: ToolbarGroupState, root: ToolbarRootState);
71
70
  onclick(_: BitsMouseEvent): void;
72
71
  onkeydown(e: BitsKeyboardEvent): void;
73
- isPressed: boolean;
74
- props: {
72
+ readonly isPressed: boolean;
73
+ readonly props: {
75
74
  readonly id: string;
76
75
  readonly role: "radio" | undefined;
77
76
  readonly tabindex: number;
@@ -81,8 +80,6 @@ declare class ToolbarGroupItemState {
81
80
  readonly "data-value": string;
82
81
  readonly "aria-pressed": "true" | "false" | undefined;
83
82
  readonly "aria-checked": "true" | "false" | "mixed" | undefined;
84
- readonly "data-toolbar-item": "";
85
- readonly "data-toolbar-group-item": "";
86
83
  readonly disabled: true | undefined;
87
84
  readonly onclick: (_: BitsMouseEvent) => void;
88
85
  readonly onkeydown: (e: BitsKeyboardEvent) => void;
@@ -95,10 +92,8 @@ declare class ToolbarLinkState {
95
92
  readonly root: ToolbarRootState;
96
93
  constructor(opts: ToolbarLinkStateProps, root: ToolbarRootState);
97
94
  onkeydown(e: BitsKeyboardEvent): void;
98
- props: {
95
+ readonly props: {
99
96
  readonly id: string;
100
- readonly "data-toolbar-link": "";
101
- readonly "data-toolbar-item": "";
102
97
  readonly role: "link" | undefined;
103
98
  readonly tabindex: number;
104
99
  readonly "data-orientation": "horizontal" | "vertical";
@@ -114,10 +109,8 @@ declare class ToolbarButtonState {
114
109
  readonly root: ToolbarRootState;
115
110
  constructor(opts: ToolbarButtonStateProps, root: ToolbarRootState);
116
111
  onkeydown(e: BitsKeyboardEvent): void;
117
- props: {
112
+ readonly props: {
118
113
  readonly id: string;
119
- readonly "data-toolbar-item": "";
120
- readonly "data-toolbar-button": "";
121
114
  readonly role: "button" | undefined;
122
115
  readonly tabindex: number;
123
116
  readonly "data-disabled": "" | undefined;
@@ -1,15 +1,12 @@
1
1
  import { attachRef } from "svelte-toolbelt";
2
2
  import { Context } from "runed";
3
- import { getAriaChecked, getAriaPressed, getDataDisabled, getDataOrientation, getDisabled, } from "../../internal/attrs.js";
3
+ import { createBitsAttrs, getAriaChecked, getAriaPressed, getDataDisabled, getDataOrientation, getDisabled, } from "../../internal/attrs.js";
4
4
  import { kbd } from "../../internal/kbd.js";
5
5
  import { useRovingFocus, } from "../../internal/use-roving-focus.svelte.js";
6
- const TOOLBAR_ROOT_ATTR = "data-toolbar-root";
7
- // all links, buttons, and items must have the ITEM_ATTR for roving focus
8
- const TOOLBAR_ITEM_ATTR = "data-toolbar-item";
9
- const TOOLBAR_GROUP_ATTR = "data-toolbar-group";
10
- const TOOLBAR_GROUP_ITEM_ATTR = "data-toolbar-group-item";
11
- const TOOLBAR_LINK_ATTR = "data-toolbar-link";
12
- const TOOLBAR_BUTTON_ATTR = "data-toolbar-button";
6
+ export const toolbarAttrs = createBitsAttrs({
7
+ component: "toolbar",
8
+ parts: ["root", "item", "group", "group-item", "link", "button"],
9
+ });
13
10
  class ToolbarRootState {
14
11
  opts;
15
12
  rovingFocusGroup;
@@ -19,14 +16,14 @@ class ToolbarRootState {
19
16
  orientation: this.opts.orientation,
20
17
  loop: this.opts.loop,
21
18
  rootNode: this.opts.ref,
22
- candidateAttr: TOOLBAR_ITEM_ATTR,
19
+ candidateAttr: toolbarAttrs.item,
23
20
  });
24
21
  }
25
22
  props = $derived.by(() => ({
26
23
  id: this.opts.id.current,
27
24
  role: "toolbar",
28
25
  "data-orientation": this.opts.orientation.current,
29
- [TOOLBAR_ROOT_ATTR]: "",
26
+ [toolbarAttrs.root]: "",
30
27
  ...attachRef(this.opts.ref),
31
28
  }));
32
29
  }
@@ -39,7 +36,7 @@ class ToolbarGroupBaseState {
39
36
  }
40
37
  props = $derived.by(() => ({
41
38
  id: this.opts.id.current,
42
- [TOOLBAR_GROUP_ATTR]: "",
39
+ [toolbarAttrs.group]: "",
43
40
  role: "group",
44
41
  "data-orientation": getDataOrientation(this.root.opts.orientation.current),
45
42
  "data-disabled": getDataDisabled(this.opts.disabled.current),
@@ -143,8 +140,8 @@ class ToolbarGroupItemState {
143
140
  "data-value": this.opts.value.current,
144
141
  "aria-pressed": this.#ariaPressed,
145
142
  "aria-checked": this.#ariaChecked,
146
- [TOOLBAR_ITEM_ATTR]: "",
147
- [TOOLBAR_GROUP_ITEM_ATTR]: "",
143
+ [toolbarAttrs.item]: "",
144
+ [toolbarAttrs["group-item"]]: "",
148
145
  disabled: getDisabled(this.#isDisabled),
149
146
  //
150
147
  onclick: this.onclick,
@@ -177,8 +174,8 @@ class ToolbarLinkState {
177
174
  #tabIndex = $state(0);
178
175
  props = $derived.by(() => ({
179
176
  id: this.opts.id.current,
180
- [TOOLBAR_LINK_ATTR]: "",
181
- [TOOLBAR_ITEM_ATTR]: "",
177
+ [toolbarAttrs.link]: "",
178
+ [toolbarAttrs.item]: "",
182
179
  role: this.#role,
183
180
  tabindex: this.#tabIndex,
184
181
  "data-orientation": getDataOrientation(this.root.opts.orientation.current),
@@ -212,8 +209,8 @@ class ToolbarButtonState {
212
209
  });
213
210
  props = $derived.by(() => ({
214
211
  id: this.opts.id.current,
215
- [TOOLBAR_ITEM_ATTR]: "",
216
- [TOOLBAR_BUTTON_ATTR]: "",
212
+ [toolbarAttrs.item]: "",
213
+ [toolbarAttrs.button]: "",
217
214
  role: this.#role,
218
215
  tabindex: this.#tabIndex,
219
216
  "data-disabled": getDataDisabled(this.opts.disabled.current),
@@ -2,6 +2,7 @@ import { DOMContext } from "svelte-toolbelt";
2
2
  import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
3
3
  import type { WithRefProps } from "../../internal/types.js";
4
4
  import type { FocusEventHandler, MouseEventHandler, PointerEventHandler } from "svelte/elements";
5
+ export declare const tooltipAttrs: import("../../internal/attrs.js").BitsAttrs<readonly ["content", "trigger"]>;
5
6
  type TooltipProviderStateProps = ReadableBoxedValues<{
6
7
  delayDuration: number;
7
8
  disableHoverableContent: boolean;
@@ -33,14 +34,14 @@ declare class TooltipRootState {
33
34
  #private;
34
35
  readonly opts: TooltipRootStateProps;
35
36
  readonly provider: TooltipProviderState;
36
- delayDuration: number;
37
- disableHoverableContent: boolean;
38
- disableCloseOnTriggerClick: boolean;
39
- disabled: boolean;
40
- ignoreNonKeyboardFocus: boolean;
37
+ readonly delayDuration: number;
38
+ readonly disableHoverableContent: boolean;
39
+ readonly disableCloseOnTriggerClick: boolean;
40
+ readonly disabled: boolean;
41
+ readonly ignoreNonKeyboardFocus: boolean;
41
42
  contentNode: HTMLElement | null;
42
43
  triggerNode: HTMLElement | null;
43
- stateAttr: string;
44
+ readonly stateAttr: string;
44
45
  constructor(opts: TooltipRootStateProps, provider: TooltipProviderState);
45
46
  handleOpen: () => void;
46
47
  handleClose: () => void;
@@ -57,13 +58,12 @@ declare class TooltipTriggerState {
57
58
  domContext: DOMContext;
58
59
  constructor(opts: TooltipTriggerStateProps, root: TooltipRootState);
59
60
  handlePointerUp: () => void;
60
- props: {
61
+ readonly props: {
61
62
  readonly id: string;
62
63
  readonly "aria-describedby": string | undefined;
63
- readonly "data-state": string;
64
+ readonly "data-state": "closed" | "delayed-open" | "instant-open";
64
65
  readonly "data-disabled": "" | undefined;
65
66
  readonly "data-delay-duration": `${number}`;
66
- readonly "data-tooltip-trigger": "";
67
67
  readonly tabindex: 0 | undefined;
68
68
  readonly disabled: boolean;
69
69
  readonly onpointerup: PointerEventHandler<HTMLElement>;
@@ -87,20 +87,19 @@ declare class TooltipContentState {
87
87
  onEscapeKeydown: (e: KeyboardEvent) => void;
88
88
  onOpenAutoFocus: (e: Event) => void;
89
89
  onCloseAutoFocus: (e: Event) => void;
90
- snippetProps: {
90
+ readonly snippetProps: {
91
91
  open: boolean;
92
92
  };
93
- props: {
93
+ readonly props: {
94
94
  readonly id: string;
95
- readonly "data-state": string;
95
+ readonly "data-state": "closed" | "delayed-open" | "instant-open";
96
96
  readonly "data-disabled": "" | undefined;
97
97
  readonly style: {
98
98
  readonly pointerEvents: "auto";
99
99
  readonly outline: "none";
100
100
  };
101
- readonly "data-tooltip-content": "";
102
101
  };
103
- popperProps: {
102
+ readonly popperProps: {
104
103
  onInteractOutside: (e: PointerEvent) => void;
105
104
  onEscapeKeydown: (e: KeyboardEvent) => void;
106
105
  onOpenAutoFocus: (e: Event) => void;
@@ -4,9 +4,11 @@ import { Context, watch } from "runed";
4
4
  import { useTimeoutFn } from "../../internal/use-timeout-fn.svelte.js";
5
5
  import { isElement, isFocusVisible } from "../../internal/is.js";
6
6
  import { useGraceArea } from "../../internal/use-grace-area.svelte.js";
7
- import { getDataDisabled } from "../../internal/attrs.js";
8
- const TOOLTIP_CONTENT_ATTR = "data-tooltip-content";
9
- const TOOLTIP_TRIGGER_ATTR = "data-tooltip-trigger";
7
+ import { createBitsAttrs, getDataDisabled } from "../../internal/attrs.js";
8
+ export const tooltipAttrs = createBitsAttrs({
9
+ component: "tooltip",
10
+ parts: ["content", "trigger"],
11
+ });
10
12
  class TooltipProviderState {
11
13
  opts;
12
14
  isOpenDelayed = $state(true);
@@ -200,7 +202,7 @@ class TooltipTriggerState {
200
202
  "data-state": this.root.stateAttr,
201
203
  "data-disabled": getDataDisabled(this.#isDisabled),
202
204
  "data-delay-duration": `${this.root.delayDuration}`,
203
- [TOOLTIP_TRIGGER_ATTR]: "",
205
+ [tooltipAttrs.trigger]: "",
204
206
  tabindex: this.#isDisabled ? undefined : 0,
205
207
  disabled: this.opts.disabled.current,
206
208
  onpointerup: this.#onpointerup,
@@ -275,7 +277,7 @@ class TooltipContentState {
275
277
  pointerEvents: "auto",
276
278
  outline: "none",
277
279
  },
278
- [TOOLTIP_CONTENT_ATTR]: "",
280
+ [tooltipAttrs.content]: "",
279
281
  ...attachRef(this.opts.ref, (v) => (this.root.contentNode = v)),
280
282
  }));
281
283
  popperProps = {
@@ -0,0 +1,44 @@
1
+ import { Context } from "runed";
2
+ import type { ReadableBoxedValues } from "../../../internal/box.svelte.js";
3
+ import type { BitsConfigPropsWithoutChildren } from "./types.js";
4
+ type BitsConfigStateProps = ReadableBoxedValues<BitsConfigPropsWithoutChildren>;
5
+ export declare const BitsConfigContext: Context<BitsConfigState>;
6
+ /**
7
+ * Gets the current Bits UI configuration state from the context.
8
+ *
9
+ * Returns a default configuration (where all values are `undefined`) if no configuration is found.
10
+ */
11
+ export declare function getBitsConfig(): Required<ReadableBoxedValues<BitsConfigPropsWithoutChildren>>;
12
+ /**
13
+ * Creates and sets a new Bits UI configuration state that inherits from parent configs.
14
+ *
15
+ * @param opts - Configuration options for this level
16
+ * @returns The configuration state instance
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * // In a component that wants to set a default portal target
21
+ * const config = useBitsConfig({ defaultPortalTo: box("#some-element") });
22
+ *
23
+ * // Child components will inherit this config and can override specific values
24
+ * const childConfig = useBitsConfig({ someOtherProp: box("value") });
25
+ * // childConfig still has defaultPortalTo="#some-element" from parent
26
+ * ```
27
+ */
28
+ export declare function useBitsConfig(opts: BitsConfigStateProps): BitsConfigState;
29
+ /**
30
+ * Configuration state that inherits from parent configurations.
31
+ *
32
+ * @example
33
+ * Config resolution:
34
+ * ```
35
+ * Level 1: { defaultPortalTo: "#some-element", theme: "dark" }
36
+ * Level 2: { spacing: "large" } // inherits defaultPortalTo="#some-element", theme="dark"
37
+ * Level 3: { theme: "light" } // inherits defaultPortalTo="#some-element", spacing="large", overrides theme="light"
38
+ * ```
39
+ */
40
+ export declare class BitsConfigState {
41
+ readonly opts: Required<BitsConfigStateProps>;
42
+ constructor(parent: BitsConfigState | null, opts: BitsConfigStateProps);
43
+ }
44
+ export {};
@@ -0,0 +1,92 @@
1
+ import { Context } from "runed";
2
+ import { box } from "svelte-toolbelt";
3
+ export const BitsConfigContext = new Context("BitsConfig");
4
+ /**
5
+ * Gets the current Bits UI configuration state from the context.
6
+ *
7
+ * Returns a default configuration (where all values are `undefined`) if no configuration is found.
8
+ */
9
+ export function getBitsConfig() {
10
+ const fallback = new BitsConfigState(null, {});
11
+ return BitsConfigContext.getOr(fallback).opts;
12
+ }
13
+ /**
14
+ * Creates and sets a new Bits UI configuration state that inherits from parent configs.
15
+ *
16
+ * @param opts - Configuration options for this level
17
+ * @returns The configuration state instance
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // In a component that wants to set a default portal target
22
+ * const config = useBitsConfig({ defaultPortalTo: box("#some-element") });
23
+ *
24
+ * // Child components will inherit this config and can override specific values
25
+ * const childConfig = useBitsConfig({ someOtherProp: box("value") });
26
+ * // childConfig still has defaultPortalTo="#some-element" from parent
27
+ * ```
28
+ */
29
+ export function useBitsConfig(opts) {
30
+ return BitsConfigContext.set(new BitsConfigState(BitsConfigContext.getOr(null), opts));
31
+ }
32
+ /**
33
+ * Configuration state that inherits from parent configurations.
34
+ *
35
+ * @example
36
+ * Config resolution:
37
+ * ```
38
+ * Level 1: { defaultPortalTo: "#some-element", theme: "dark" }
39
+ * Level 2: { spacing: "large" } // inherits defaultPortalTo="#some-element", theme="dark"
40
+ * Level 3: { theme: "light" } // inherits defaultPortalTo="#some-element", spacing="large", overrides theme="light"
41
+ * ```
42
+ */
43
+ export class BitsConfigState {
44
+ opts;
45
+ constructor(parent, opts) {
46
+ const resolveConfigOption = createConfigResolver(parent, opts);
47
+ this.opts = {
48
+ defaultPortalTo: resolveConfigOption((config) => config.defaultPortalTo),
49
+ defaultLocale: resolveConfigOption((config) => config.defaultLocale),
50
+ };
51
+ }
52
+ }
53
+ /**
54
+ * Returns a config resolver that resolves a given config option's value.
55
+ *
56
+ * The resolver creates reactive boxes that resolve config option values using this priority:
57
+ * 1. Current level's value (if defined)
58
+ * 2. Parent level's value (if defined and current is undefined)
59
+ * 3. `undefined` (if no value is found in either parent or child)
60
+ *
61
+ * @param parent - Parent configuration state (null if this is root level)
62
+ * @param currentOpts - Current level's configuration options
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * // Given this hierarchy:
67
+ * // Root: { defaultPortalTo: "#some-element" }
68
+ * // Child: { someOtherProp: "value" } // no defaultPortalTo specified
69
+ *
70
+ * const resolveConfigOption = createConfigResolver(parent, opts);
71
+ * const portalTo = resolveConfigOption(config => config.defaultPortalTo);
72
+ *
73
+ * // portalTo.current === "#some-element" (inherited from parent)
74
+ * // even when child didn't specify `defaultPortalTo`
75
+ * ```
76
+ */
77
+ function createConfigResolver(parent, currentOpts) {
78
+ return (getter) => {
79
+ const configOption = box.with(() => {
80
+ // try current opts first
81
+ const value = getter(currentOpts)?.current;
82
+ if (value !== undefined)
83
+ return value;
84
+ // if no parent, return undefined
85
+ if (parent === null)
86
+ return undefined;
87
+ // get value from parent (which already has its own chain resolved)
88
+ return getter(parent.opts)?.current;
89
+ });
90
+ return configOption;
91
+ };
92
+ }
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import type { BitsConfigProps } from "../types.js";
3
+ import { useBitsConfig } from "../bits-config.js";
4
+ import { box } from "svelte-toolbelt";
5
+
6
+ let { children, defaultPortalTo, defaultLocale }: BitsConfigProps = $props();
7
+
8
+ useBitsConfig({
9
+ defaultPortalTo: box.with(() => defaultPortalTo),
10
+ defaultLocale: box.with(() => defaultLocale),
11
+ });
12
+ </script>
13
+
14
+ {@render children?.()}
@@ -0,0 +1,4 @@
1
+ import type { BitsConfigProps } from "../types.js";
2
+ declare const BitsConfig: import("svelte").Component<BitsConfigProps, {}, "">;
3
+ type BitsConfig = ReturnType<typeof BitsConfig>;
4
+ export default BitsConfig;
@@ -0,0 +1,2 @@
1
+ export { default as BitsConfig } from "./components/bits-config.svelte";
2
+ export { getBitsConfig, BitsConfigState } from "./bits-config.js";
@@ -0,0 +1,2 @@
1
+ export { default as BitsConfig } from "./components/bits-config.svelte";
2
+ export { getBitsConfig, BitsConfigState } from "./bits-config.js";
@@ -0,0 +1 @@
1
+ export * from "./exports.js";
@@ -0,0 +1 @@
1
+ export * from "./exports.js";
@@ -0,0 +1,13 @@
1
+ import { type Getter, type ReadableBox } from "svelte-toolbelt";
2
+ /**
3
+ * Resolves a locale value using the prop, the config default, or a fallback.
4
+ *
5
+ * Default value: `"en"`
6
+ */
7
+ export declare const resolveLocaleProp: (getProp: Getter<string | undefined>) => ReadableBox<string>;
8
+ /**
9
+ * Resolves a portal's `to` value using the prop, the config default, or a fallback.
10
+ *
11
+ * Default value: `"body"`
12
+ */
13
+ export declare const resolvePortalToProp: (getProp: Getter<string | Element | undefined>) => ReadableBox<string | Element>;
@@ -0,0 +1,37 @@
1
+ import { box } from "svelte-toolbelt";
2
+ import { getBitsConfig } from "./bits-config.js";
3
+ /**
4
+ * Creates a generic prop resolver that follows a standard priority chain:
5
+ * 1. The getter's prop value (if defined)
6
+ * 2. The config default value (if no getter prop value is defined)
7
+ * 3. The fallback value (if no config value found)
8
+ */
9
+ function createPropResolver(configOption, fallback) {
10
+ return (getProp) => {
11
+ const config = getBitsConfig();
12
+ return box.with(() => {
13
+ // 1. return the prop's value, if provided
14
+ const propValue = getProp();
15
+ if (propValue !== undefined)
16
+ return propValue;
17
+ // 2. return the resolved config option value, if available
18
+ const option = configOption(config).current;
19
+ if (option !== undefined)
20
+ return option;
21
+ // 3. return the fallback if no other value is found
22
+ return fallback;
23
+ });
24
+ };
25
+ }
26
+ /**
27
+ * Resolves a locale value using the prop, the config default, or a fallback.
28
+ *
29
+ * Default value: `"en"`
30
+ */
31
+ export const resolveLocaleProp = createPropResolver((config) => config.defaultLocale, "en");
32
+ /**
33
+ * Resolves a portal's `to` value using the prop, the config default, or a fallback.
34
+ *
35
+ * Default value: `"body"`
36
+ */
37
+ export const resolvePortalToProp = createPropResolver((config) => config.defaultPortalTo, "body");
@@ -0,0 +1,13 @@
1
+ import type { WithChildren } from "../../../internal/types.js";
2
+ import type { PortalTarget } from "../portal/types.js";
3
+ export type BitsConfigPropsWithoutChildren = {
4
+ /**
5
+ * The default portal `to`/target to use for the `Portal` components throughout the app.
6
+ */
7
+ defaultPortalTo?: PortalTarget;
8
+ /**
9
+ * The default locale to use for the components that support localization.
10
+ */
11
+ defaultLocale?: string;
12
+ };
13
+ export type BitsConfigProps = WithChildren<BitsConfigPropsWithoutChildren>;
@@ -0,0 +1 @@
1
+ export {};
@@ -5,40 +5,41 @@
5
5
  import PortalConsumer from "./portal-consumer.svelte";
6
6
  import type { PortalProps } from "./types.js";
7
7
  import { isBrowser } from "../../../internal/is.js";
8
+ import { resolvePortalToProp } from "../config/prop-resolvers.js";
8
9
 
9
- let { to = "body", children, disabled }: PortalProps = $props();
10
+ let { to: toProp, children, disabled }: PortalProps = $props();
10
11
 
12
+ const to = resolvePortalToProp(() => toProp);
11
13
  const context = getAllContexts();
12
14
 
13
15
  let target = $derived(getTarget());
14
16
 
15
17
  function getTarget() {
16
18
  if (!isBrowser || disabled) return null;
17
- let localTarget: HTMLElement | null | DocumentFragment | Element = null;
18
- if (typeof to === "string") {
19
- localTarget = document.querySelector(to);
20
- if (localTarget === null) {
21
- if (DEV) {
22
- throw new Error(`Target element "${to}" not found.`);
23
- }
19
+
20
+ let localTarget: Element | null = null;
21
+
22
+ if (typeof to.current === "string") {
23
+ const target = document.querySelector(to.current);
24
+ if (DEV && target === null) {
25
+ throw new Error(`Target element "${to.current}" not found.`);
24
26
  }
25
- } else if (to instanceof HTMLElement || to instanceof DocumentFragment) {
26
- localTarget = to;
27
+ localTarget = target;
27
28
  } else {
28
- if (DEV) {
29
- throw new TypeError(
30
- `Unknown portal target type: ${
31
- to === null ? "null" : typeof to
32
- }. Allowed types: string (query selector), HTMLElement, or DocumentFragment.`
33
- );
34
- }
29
+ localTarget = to.current;
30
+ }
31
+
32
+ if (DEV && !(localTarget instanceof Element)) {
33
+ const type = localTarget === null ? "null" : typeof localTarget;
34
+ throw new TypeError(
35
+ `Unknown portal target type: ${type}. Allowed types: string (query selector) or Element.`
36
+ );
35
37
  }
36
38
 
37
39
  return localTarget;
38
40
  }
39
41
 
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- let instance: any;
42
+ let instance: ReturnType<typeof mount> | null;
42
43
 
43
44
  function unmountInstance() {
44
45
  if (instance) {
@@ -53,8 +54,7 @@
53
54
  return;
54
55
  }
55
56
  instance = mount(PortalConsumer, {
56
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
- target: target as any,
57
+ target: target,
58
58
  props: { children },
59
59
  context,
60
60
  });
@@ -1,11 +1,12 @@
1
1
  import type { Snippet } from "svelte";
2
+ export type PortalTarget = Element | string;
2
3
  export type PortalProps = {
3
4
  /**
4
5
  * Where to portal the content to.
5
6
  *
6
7
  * @default document.body
7
8
  */
8
- to?: HTMLElement | string | DocumentFragment;
9
+ to?: PortalTarget;
9
10
  /**
10
11
  * Disable portalling and render the component inline
11
12
  *
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Accordion, AlertDialog, AspectRatio, Avatar, Button, Calendar, Checkbox, Collapsible, Combobox, Command, ContextMenu, DateField, DatePicker, DateRangeField, DateRangePicker, Dialog, DropdownMenu, Label, LinkPreview, Menubar, Meter, NavigationMenu, Pagination, PinInput, Popover, Progress, RadioGroup, RangeCalendar, RatingGroup as unstable_RatingGroup, ScrollArea, Select, Separator, Slider, Switch, Tabs, TimeField, TimeRangeField, Toggle, ToggleGroup, Toolbar, Tooltip, Portal, IsUsingKeyboard, computeCommandScore, } from "./bits/index.js";
1
+ export { Accordion, AlertDialog, AspectRatio, Avatar, BitsConfig, Button, Calendar, Checkbox, Collapsible, Combobox, Command, ContextMenu, DateField, DatePicker, DateRangeField, DateRangePicker, Dialog, DropdownMenu, Label, LinkPreview, Menubar, Meter, NavigationMenu, Pagination, PinInput, Popover, Progress, RadioGroup, RangeCalendar, RatingGroup as unstable_RatingGroup, ScrollArea, Select, Separator, Slider, Switch, Tabs, TimeField, TimeRangeField, Toggle, ToggleGroup, Toolbar, Tooltip, Portal, IsUsingKeyboard, computeCommandScore, getBitsConfig, } from "./bits/index.js";
2
2
  export * from "./shared/index.js";
3
3
  export type * from "./shared/index.js";
4
4
  export * from "./types.js";
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { Accordion, AlertDialog, AspectRatio, Avatar, Button, Calendar, Checkbox, Collapsible, Combobox, Command, ContextMenu, DateField, DatePicker, DateRangeField, DateRangePicker, Dialog, DropdownMenu, Label, LinkPreview, Menubar, Meter, NavigationMenu, Pagination, PinInput, Popover, Progress, RadioGroup, RangeCalendar, RatingGroup as unstable_RatingGroup, ScrollArea, Select, Separator, Slider, Switch, Tabs, TimeField, TimeRangeField, Toggle, ToggleGroup, Toolbar, Tooltip, Portal, IsUsingKeyboard, computeCommandScore, } from "./bits/index.js";
1
+ export { Accordion, AlertDialog, AspectRatio, Avatar, BitsConfig, Button, Calendar, Checkbox, Collapsible, Combobox, Command, ContextMenu, DateField, DatePicker, DateRangeField, DateRangePicker, Dialog, DropdownMenu, Label, LinkPreview, Menubar, Meter, NavigationMenu, Pagination, PinInput, Popover, Progress, RadioGroup, RangeCalendar, RatingGroup as unstable_RatingGroup, ScrollArea, Select, Separator, Slider, Switch, Tabs, TimeField, TimeRangeField, Toggle, ToggleGroup, Toolbar, Tooltip, Portal, IsUsingKeyboard, computeCommandScore, getBitsConfig, } from "./bits/index.js";
2
2
  export * from "./shared/index.js";
3
3
  export * from "./types.js";
@@ -20,3 +20,17 @@ export declare function getHidden(condition: boolean): true | undefined;
20
20
  export declare function getDisabled(condition: boolean): true | undefined;
21
21
  export declare function getAriaPressed(condition: boolean): "true" | "false";
22
22
  export declare function getRequired(condition: boolean): true | undefined;
23
+ export type BitsAttrsConfig<T extends readonly string[]> = {
24
+ component: string;
25
+ parts: T;
26
+ getVariant?: () => string | null;
27
+ };
28
+ export type BitsAttrs<T extends readonly string[]> = {
29
+ [K in T[number]]: string;
30
+ } & {
31
+ selector: (part: T[number]) => string;
32
+ getAttr: (part: T[number], variant?: string) => string;
33
+ };
34
+ export declare function createBitsAttrs<const T extends readonly string[]>(config: Omit<BitsAttrsConfig<T>, "parts"> & {
35
+ parts: T;
36
+ }): BitsAttrs<T>;