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
@@ -2,30 +2,34 @@ import { afterSleep, afterTick, srOnlyStyles, attachRef } from "svelte-toolbelt"
2
2
  import { Context, watch } from "runed";
3
3
  import { findNextSibling, findPreviousSibling } from "./utils.js";
4
4
  import { kbd } from "../../internal/kbd.js";
5
- import { getAriaDisabled, getAriaExpanded, getAriaSelected, getDataDisabled, getDataSelected, } from "../../internal/attrs.js";
5
+ import { createBitsAttrs, getAriaDisabled, getAriaExpanded, getAriaSelected, getDataDisabled, getDataSelected, } from "../../internal/attrs.js";
6
6
  import { getFirstNonCommentChild } from "../../internal/dom.js";
7
7
  import { computeCommandScore } from "./index.js";
8
8
  import cssesc from "css.escape";
9
- // attributes
10
- const COMMAND_ROOT_ATTR = "data-command-root";
11
- const COMMAND_LIST_ATTR = "data-command-list";
12
- const COMMAND_INPUT_ATTR = "data-command-input";
13
- const COMMAND_SEPARATOR_ATTR = "data-command-separator";
14
- const COMMAND_LOADING_ATTR = "data-command-loading";
15
- const COMMAND_EMPTY_ATTR = "data-command-empty";
16
- const COMMAND_GROUP_ATTR = "data-command-group";
17
- const COMMAND_GROUP_ITEMS_ATTR = "data-command-group-items";
18
- const COMMAND_GROUP_HEADING_ATTR = "data-command-group-heading";
19
- const COMMAND_ITEM_ATTR = "data-command-item";
20
- const COMMAND_VIEWPORT_ATTR = "data-command-viewport";
21
- const COMMAND_INPUT_LABEL_ATTR = "data-command-input-label";
22
9
  const COMMAND_VALUE_ATTR = "data-value";
10
+ const commandAttrs = createBitsAttrs({
11
+ component: "command",
12
+ parts: [
13
+ "root",
14
+ "list",
15
+ "input",
16
+ "separator",
17
+ "loading",
18
+ "empty",
19
+ "group",
20
+ "group-items",
21
+ "group-heading",
22
+ "item",
23
+ "viewport",
24
+ "input-label",
25
+ ],
26
+ });
23
27
  // selectors
24
- const COMMAND_GROUP_SELECTOR = `[${COMMAND_GROUP_ATTR}]`;
25
- const COMMAND_GROUP_ITEMS_SELECTOR = `[${COMMAND_GROUP_ITEMS_ATTR}]`;
26
- const COMMAND_GROUP_HEADING_SELECTOR = `[${COMMAND_GROUP_HEADING_ATTR}]`;
27
- const COMMAND_ITEM_SELECTOR = `[${COMMAND_ITEM_ATTR}]`;
28
- const COMMAND_VALID_ITEM_SELECTOR = `${COMMAND_ITEM_SELECTOR}:not([aria-disabled="true"])`;
28
+ const COMMAND_GROUP_SELECTOR = commandAttrs.selector("group");
29
+ const COMMAND_GROUP_ITEMS_SELECTOR = commandAttrs.selector("group-items");
30
+ const COMMAND_GROUP_HEADING_SELECTOR = commandAttrs.selector("group-heading");
31
+ const COMMAND_ITEM_SELECTOR = commandAttrs.selector("item");
32
+ const COMMAND_VALID_ITEM_SELECTOR = `${commandAttrs.selector("item")}:not([aria-disabled="true"])`;
29
33
  const CommandRootContext = new Context("Command.Root");
30
34
  const CommandListContext = new Context("Command.List");
31
35
  const CommandGroupContainerContext = new Context("Command.Group");
@@ -568,7 +572,7 @@ class CommandRootState {
568
572
  props = $derived.by(() => ({
569
573
  id: this.opts.id.current,
570
574
  role: "application",
571
- [COMMAND_ROOT_ATTR]: "",
575
+ [commandAttrs.root]: "",
572
576
  tabindex: -1,
573
577
  onkeydown: this.onkeydown,
574
578
  ...attachRef(this.opts.ref),
@@ -592,7 +596,7 @@ class CommandEmptyState {
592
596
  props = $derived.by(() => ({
593
597
  id: this.opts.id.current,
594
598
  role: "presentation",
595
- [COMMAND_EMPTY_ATTR]: "",
599
+ [commandAttrs.empty]: "",
596
600
  ...attachRef(this.opts.ref),
597
601
  }));
598
602
  }
@@ -637,7 +641,7 @@ class CommandGroupContainerState {
637
641
  role: "presentation",
638
642
  hidden: this.shouldRender ? undefined : true,
639
643
  "data-value": this.trueValue,
640
- [COMMAND_GROUP_ATTR]: "",
644
+ [commandAttrs.group]: "",
641
645
  ...attachRef(this.opts.ref),
642
646
  }));
643
647
  }
@@ -650,7 +654,7 @@ class CommandGroupHeadingState {
650
654
  }
651
655
  props = $derived.by(() => ({
652
656
  id: this.opts.id.current,
653
- [COMMAND_GROUP_HEADING_ATTR]: "",
657
+ [commandAttrs["group-heading"]]: "",
654
658
  ...attachRef(this.opts.ref, (v) => (this.group.headingNode = v)),
655
659
  }));
656
660
  }
@@ -664,7 +668,7 @@ class CommandGroupItemsState {
664
668
  props = $derived.by(() => ({
665
669
  id: this.opts.id.current,
666
670
  role: "group",
667
- [COMMAND_GROUP_ITEMS_ATTR]: "",
671
+ [commandAttrs["group-items"]]: "",
668
672
  "aria-labelledby": this.group.headingNode?.id ?? undefined,
669
673
  ...attachRef(this.opts.ref),
670
674
  }));
@@ -696,7 +700,7 @@ class CommandInputState {
696
700
  props = $derived.by(() => ({
697
701
  id: this.opts.id.current,
698
702
  type: "text",
699
- [COMMAND_INPUT_ATTR]: "",
703
+ [commandAttrs.input]: "",
700
704
  autocomplete: "off",
701
705
  autocorrect: "off",
702
706
  spellcheck: false,
@@ -783,7 +787,7 @@ class CommandItemState {
783
787
  "data-disabled": getDataDisabled(this.opts.disabled.current),
784
788
  "data-selected": getDataSelected(this.isSelected),
785
789
  "data-value": this.trueValue,
786
- [COMMAND_ITEM_ATTR]: "",
790
+ [commandAttrs.item]: "",
787
791
  role: "option",
788
792
  onpointermove: this.onpointermove,
789
793
  onclick: this.onclick,
@@ -802,7 +806,7 @@ class CommandLoadingState {
802
806
  "aria-valuemin": 0,
803
807
  "aria-valuemax": 100,
804
808
  "aria-label": "Loading...",
805
- [COMMAND_LOADING_ATTR]: "",
809
+ [commandAttrs.loading]: "",
806
810
  ...attachRef(this.opts.ref),
807
811
  }));
808
812
  }
@@ -818,7 +822,7 @@ class CommandSeparatorState {
818
822
  id: this.opts.id.current,
819
823
  // role="separator" cannot belong to a role="listbox"
820
824
  "aria-hidden": "true",
821
- [COMMAND_SEPARATOR_ATTR]: "",
825
+ [commandAttrs.separator]: "",
822
826
  ...attachRef(this.opts.ref),
823
827
  }));
824
828
  }
@@ -833,7 +837,7 @@ class CommandListState {
833
837
  id: this.opts.id.current,
834
838
  role: "listbox",
835
839
  "aria-label": this.opts.ariaLabel.current,
836
- [COMMAND_LIST_ATTR]: "",
840
+ [commandAttrs.list]: "",
837
841
  ...attachRef(this.opts.ref),
838
842
  }));
839
843
  }
@@ -846,7 +850,7 @@ class CommandLabelState {
846
850
  }
847
851
  props = $derived.by(() => ({
848
852
  id: this.opts.id.current,
849
- [COMMAND_INPUT_LABEL_ATTR]: "",
853
+ [commandAttrs["input-label"]]: "",
850
854
  for: this.opts.for?.current,
851
855
  style: srOnlyStyles,
852
856
  ...attachRef(this.opts.ref, (v) => (this.root.labelNode = v)),
@@ -879,7 +883,7 @@ class CommandViewportState {
879
883
  }
880
884
  props = $derived.by(() => ({
881
885
  id: this.opts.id.current,
882
- [COMMAND_VIEWPORT_ATTR]: "",
886
+ [commandAttrs.viewport]: "",
883
887
  ...attachRef(this.opts.ref, (v) => (this.list.root.viewportNode = v)),
884
888
  }));
885
889
  }
@@ -1,18 +1,19 @@
1
1
  <script lang="ts">
2
+ import { watch } from "runed";
2
3
  import { box } from "svelte-toolbelt";
3
4
  import type { DateValue } from "@internationalized/date";
4
5
  import { useDateFieldRoot } from "../date-field.svelte.js";
5
6
  import type { DateFieldRootProps } from "../types.js";
6
7
  import { noop } from "../../../internal/noop.js";
7
8
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
8
- import { watch } from "runed";
9
+ import { resolveLocaleProp } from "../../utilities/config/prop-resolvers.js";
9
10
 
10
11
  let {
11
12
  disabled = false,
12
13
  granularity,
13
14
  hideTimeZone = false,
14
15
  hourCycle,
15
- locale = "en",
16
+ locale,
16
17
  maxValue,
17
18
  minValue,
18
19
  onPlaceholderChange = noop,
@@ -73,7 +74,7 @@
73
74
  granularity: box.with(() => granularity),
74
75
  hideTimeZone: box.with(() => hideTimeZone),
75
76
  hourCycle: box.with(() => hourCycle),
76
- locale: box.with(() => locale),
77
+ locale: resolveLocaleProp(() => locale),
77
78
  maxValue: box.with(() => maxValue),
78
79
  minValue: box.with(() => minValue),
79
80
  validate: box.with(() => validate),
@@ -7,7 +7,7 @@ import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, WithRefProps }
7
7
  import type { DateAndTimeSegmentObj, DateOnInvalid, DateSegmentObj, DateSegmentPart, DateValidator, Granularity, HourCycle, SegmentPart, SegmentValueObj, TimeSegmentObj, EditableTimeSegmentPart } from "../../shared/date/types.js";
8
8
  import { type Formatter } from "../../internal/date-time/formatter.js";
9
9
  import { type Announcer } from "../../internal/date-time/announcer.js";
10
- export declare const DATE_FIELD_INPUT_ATTR = "data-date-field-input";
10
+ export declare const dateFieldAttrs: import("../../internal/attrs.js").BitsAttrs<readonly ["input", "label", "segment"]>;
11
11
  type SegmentConfig = {
12
12
  min: number | ((root: DateFieldRootState) => number);
13
13
  max: number | ((root: DateFieldRootState) => number);
@@ -138,6 +138,7 @@ export declare class DateFieldRootState {
138
138
  updateSegment<T extends keyof DateAndTimeSegmentObj>(part: T, cb: T extends DateSegmentPart ? Updater<DateSegmentObj[T]> : T extends EditableTimeSegmentPart ? Updater<TimeSegmentObj[T]> : Updater<DateAndTimeSegmentObj[T]>): void;
139
139
  handleSegmentClick(e: BitsMouseEvent): void;
140
140
  getBaseSegmentAttrs(part: SegmentPart, segmentId: string): {
141
+ [dateFieldAttrs.segment]: string;
141
142
  "aria-invalid": "true" | undefined;
142
143
  "aria-disabled": "true" | "false";
143
144
  "aria-readonly": "true" | "false";
@@ -176,7 +177,6 @@ export declare class DateFieldInputState {
176
177
  readonly "aria-disabled": "true" | "false";
177
178
  readonly "data-invalid": "" | undefined;
178
179
  readonly "data-disabled": "" | undefined;
179
- readonly "data-date-field-input": "";
180
180
  };
181
181
  }
182
182
  declare class DateFieldHiddenInputState {
@@ -200,7 +200,6 @@ declare class DateFieldLabelState {
200
200
  readonly id: string;
201
201
  readonly "data-invalid": "" | undefined;
202
202
  readonly "data-disabled": "" | undefined;
203
- readonly "data-date-field-label": "";
204
203
  readonly onclick: (_: BitsMouseEvent) => void;
205
204
  };
206
205
  }
@@ -415,7 +414,6 @@ declare class DateFieldTimeZoneSegmentState {
415
414
  readonly caretColor: "transparent";
416
415
  };
417
416
  readonly onkeydown: (e: BitsKeyboardEvent) => void;
418
- readonly tabindex: 0;
419
417
  } | {
420
418
  readonly "data-readonly": "" | undefined;
421
419
  readonly "aria-labelledby": string;
@@ -1,7 +1,7 @@
1
1
  import { box, onDestroyEffect, attachRef, DOMContext } from "svelte-toolbelt";
2
2
  import { onMount, untrack } from "svelte";
3
3
  import { Context, watch } from "runed";
4
- import { getAriaDisabled, getAriaHidden, getAriaInvalid, getAriaReadonly, getDataDisabled, getDataInvalid, getDataReadonly, } from "../../internal/attrs.js";
4
+ import { createBitsAttrs, getAriaDisabled, getAriaHidden, getAriaInvalid, getAriaReadonly, getDataDisabled, getDataInvalid, getDataReadonly, } from "../../internal/attrs.js";
5
5
  import { isBrowser, isNumberString } from "../../internal/is.js";
6
6
  import { kbd } from "../../internal/kbd.js";
7
7
  import { useId } from "../../internal/use-id.js";
@@ -11,8 +11,10 @@ import { areAllSegmentsFilled, createContent, getValueFromSegments, inferGranula
11
11
  import { DATE_SEGMENT_PARTS, EDITABLE_TIME_SEGMENT_PARTS, } from "../../internal/date-time/field/parts.js";
12
12
  import { getDaysInMonth, isBefore, toDate } from "../../internal/date-time/utils.js";
13
13
  import { getFirstSegment, handleSegmentNavigation, isSegmentNavigationKey, moveToNextSegment, moveToPrevSegment, } from "../../internal/date-time/field/segments.js";
14
- export const DATE_FIELD_INPUT_ATTR = "data-date-field-input";
15
- const DATE_FIELD_LABEL_ATTR = "data-date-field-label";
14
+ export const dateFieldAttrs = createBitsAttrs({
15
+ component: "date-field",
16
+ parts: ["input", "label", "segment"],
17
+ });
16
18
  const SEGMENT_CONFIGS = {
17
19
  day: {
18
20
  min: 1,
@@ -535,6 +537,7 @@ export class DateFieldRootState {
535
537
  "data-disabled": getDataDisabled(this.disabled.current),
536
538
  "data-readonly": getDataReadonly(this.readonly.current || inReadonlySegments),
537
539
  "data-segment": `${part}`,
540
+ [dateFieldAttrs.segment]: "",
538
541
  };
539
542
  if (part === "literal")
540
543
  return defaultAttrs;
@@ -585,7 +588,7 @@ export class DateFieldInputState {
585
588
  "aria-disabled": getAriaDisabled(this.root.disabled.current),
586
589
  "data-invalid": this.root.isInvalid ? "" : undefined,
587
590
  "data-disabled": getDataDisabled(this.root.disabled.current),
588
- [DATE_FIELD_INPUT_ATTR]: "",
591
+ [dateFieldAttrs.input]: "",
589
592
  ...attachRef(this.opts.ref, (v) => this.root.setFieldNode(v)),
590
593
  }));
591
594
  }
@@ -624,7 +627,7 @@ class DateFieldLabelState {
624
627
  id: this.opts.id.current,
625
628
  "data-invalid": getDataInvalid(this.root.isInvalid),
626
629
  "data-disabled": getDataDisabled(this.root.disabled.current),
627
- [DATE_FIELD_LABEL_ATTR]: "",
630
+ [dateFieldAttrs.label]: "",
628
631
  onclick: this.onclick,
629
632
  ...attachRef(this.opts.ref, (v) => this.root.setLabelNode(v)),
630
633
  }));
@@ -1173,7 +1176,6 @@ class DateFieldTimeZoneSegmentState {
1173
1176
  caretColor: "transparent",
1174
1177
  },
1175
1178
  onkeydown: this.onkeydown,
1176
- tabindex: 0,
1177
1179
  ...this.root.getBaseSegmentAttrs("timeZoneName", this.opts.id.current),
1178
1180
  "data-readonly": getDataReadonly(true),
1179
1181
  ...attachRef(this.opts.ref),
@@ -2,7 +2,7 @@
2
2
  import { mergeProps } from "svelte-toolbelt";
3
3
  import type { DatePickerTriggerProps } from "../types.js";
4
4
  import PopoverTrigger from "../../popover/components/popover-trigger.svelte";
5
- import { DATE_FIELD_INPUT_ATTR } from "../../date-field/date-field.svelte.js";
5
+ import { dateFieldAttrs } from "../../date-field/date-field.svelte.js";
6
6
  import {
7
7
  handleSegmentNavigation,
8
8
  isSegmentNavigationKey,
@@ -14,7 +14,7 @@
14
14
  if (isSegmentNavigationKey(e.key)) {
15
15
  const currNode = e.currentTarget as HTMLElement;
16
16
  const dateFieldInputNode = currNode.closest(
17
- `[${DATE_FIELD_INPUT_ATTR}]`
17
+ dateFieldAttrs.selector("input")
18
18
  ) as HTMLElement;
19
19
  if (!dateFieldInputNode) return;
20
20
  handleSegmentNavigation(e, dateFieldInputNode);
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  // Date Picker composes the DateField, Popover, and Calendar components
3
+ import { watch } from "runed";
3
4
  import { box } from "svelte-toolbelt";
4
5
  import type { DateValue } from "@internationalized/date";
5
6
  import { useDatePickerRoot } from "../date-picker.svelte.js";
@@ -9,7 +10,7 @@
9
10
  import { useDateFieldRoot } from "../../date-field/date-field.svelte.js";
10
11
  import { FloatingLayer } from "../../utilities/floating-layer/index.js";
11
12
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
12
- import { watch } from "runed";
13
+ import { resolveLocaleProp } from "../../utilities/config/prop-resolvers.js";
13
14
 
14
15
  let {
15
16
  open = $bindable(false),
@@ -28,7 +29,7 @@
28
29
  granularity,
29
30
  readonlySegments = [],
30
31
  hourCycle,
31
- locale = "en",
32
+ locale,
32
33
  hideTimeZone = false,
33
34
  required = false,
34
35
  calendarLabel = "Event",
@@ -107,7 +108,7 @@
107
108
  granularity: box.with(() => granularity),
108
109
  readonlySegments: box.with(() => readonlySegments),
109
110
  hourCycle: box.with(() => hourCycle),
110
- locale: box.with(() => locale),
111
+ locale: resolveLocaleProp(() => locale),
111
112
  hideTimeZone: box.with(() => hideTimeZone),
112
113
  required: box.with(() => required),
113
114
  calendarLabel: box.with(() => calendarLabel),
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { watch } from "runed";
2
3
  import { box, mergeProps } from "svelte-toolbelt";
3
4
  import type { DateValue } from "@internationalized/date";
4
5
  import { useDateRangeFieldRoot } from "../date-range-field.svelte.js";
@@ -7,7 +8,7 @@
7
8
  import { noop } from "../../../internal/noop.js";
8
9
  import type { DateRange } from "../../../shared/index.js";
9
10
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
10
- import { watch } from "runed";
11
+ import { resolveLocaleProp } from "../../utilities/config/prop-resolvers.js";
11
12
 
12
13
  const uid = $props.id();
13
14
 
@@ -23,7 +24,7 @@
23
24
  required = false,
24
25
  hourCycle,
25
26
  granularity,
26
- locale = "en-US",
27
+ locale,
27
28
  hideTimeZone = false,
28
29
  validate = noop,
29
30
  onInvalid = noop,
@@ -89,7 +90,7 @@
89
90
  required: box.with(() => required),
90
91
  hourCycle: box.with(() => hourCycle),
91
92
  granularity: box.with(() => granularity),
92
- locale: box.with(() => locale),
93
+ locale: resolveLocaleProp(() => locale),
93
94
  hideTimeZone: box.with(() => hideTimeZone),
94
95
  validate: box.with(() => validate),
95
96
  maxValue: box.with(() => maxValue),
@@ -8,7 +8,7 @@ import type { DateOnInvalid, DateRange, DateRangeValidator, SegmentPart } from "
8
8
  import type { WithRefProps } from "../../internal/types.js";
9
9
  import type { Granularity } from "../../shared/date/types.js";
10
10
  import { type Formatter } from "../../internal/date-time/formatter.js";
11
- export declare const DATE_RANGE_FIELD_ROOT_ATTR = "data-date-range-field-root";
11
+ export declare const dateRangeFieldAttrs: import("../../internal/attrs.js").BitsAttrs<readonly ["root", "label"]>;
12
12
  type DateRangeFieldRootStateProps = WithRefProps<WritableBoxedValues<{
13
13
  value: DateRange;
14
14
  placeholder: DateValue;
@@ -58,7 +58,6 @@ export declare class DateRangeFieldRootState {
58
58
  props: {
59
59
  readonly id: string;
60
60
  readonly role: "group";
61
- readonly "data-date-range-field-root": "";
62
61
  readonly "data-invalid": "" | undefined;
63
62
  };
64
63
  }
@@ -72,7 +71,6 @@ declare class DateRangeFieldLabelState {
72
71
  readonly id: string;
73
72
  readonly "data-invalid": "" | undefined;
74
73
  readonly "data-disabled": "" | undefined;
75
- readonly "data-date-range-field-label": "";
76
74
  readonly onclick: () => void;
77
75
  };
78
76
  }
@@ -2,13 +2,15 @@ import { box, onDestroyEffect, attachRef, DOMContext } from "svelte-toolbelt";
2
2
  import { Context, watch } from "runed";
3
3
  import { DateFieldInputState, useDateFieldRoot } from "../date-field/date-field.svelte.js";
4
4
  import { useId } from "../../internal/use-id.js";
5
- import { getDataDisabled, getDataInvalid } from "../../internal/attrs.js";
5
+ import { createBitsAttrs, getDataDisabled, getDataInvalid } from "../../internal/attrs.js";
6
6
  import { createFormatter } from "../../internal/date-time/formatter.js";
7
7
  import { removeDescriptionElement } from "../../internal/date-time/field/helpers.js";
8
8
  import { isBefore } from "../../internal/date-time/utils.js";
9
9
  import { getFirstSegment } from "../../internal/date-time/field/segments.js";
10
- export const DATE_RANGE_FIELD_ROOT_ATTR = "data-date-range-field-root";
11
- const DATE_RANGE_FIELD_LABEL_ATTR = "data-date-range-field-label";
10
+ export const dateRangeFieldAttrs = createBitsAttrs({
11
+ component: "date-range-field",
12
+ parts: ["root", "label"],
13
+ });
12
14
  export class DateRangeFieldRootState {
13
15
  opts;
14
16
  startFieldState = undefined;
@@ -130,7 +132,7 @@ export class DateRangeFieldRootState {
130
132
  props = $derived.by(() => ({
131
133
  id: this.opts.id.current,
132
134
  role: "group",
133
- [DATE_RANGE_FIELD_ROOT_ATTR]: "",
135
+ [dateRangeFieldAttrs.root]: "",
134
136
  "data-invalid": getDataInvalid(this.isInvalid),
135
137
  ...attachRef(this.opts.ref, (v) => (this.fieldNode = v)),
136
138
  }));
@@ -155,7 +157,7 @@ class DateRangeFieldLabelState {
155
157
  // TODO: invalid state for field
156
158
  "data-invalid": getDataInvalid(this.root.isInvalid),
157
159
  "data-disabled": getDataDisabled(this.root.opts.disabled.current),
158
- [DATE_RANGE_FIELD_LABEL_ATTR]: "",
160
+ [dateRangeFieldAttrs.label]: "",
159
161
  onclick: this.#onclick,
160
162
  ...attachRef(this.opts.ref, (v) => (this.root.labelNode = v)),
161
163
  }));
@@ -2,7 +2,7 @@
2
2
  import { mergeProps } from "svelte-toolbelt";
3
3
  import type { DateRangePickerTriggerProps } from "../types.js";
4
4
  import PopoverTrigger from "../../popover/components/popover-trigger.svelte";
5
- import { DATE_RANGE_FIELD_ROOT_ATTR } from "../../date-range-field/date-range-field.svelte.js";
5
+ import { dateRangeFieldAttrs } from "../../date-range-field/date-range-field.svelte.js";
6
6
  import {
7
7
  handleSegmentNavigation,
8
8
  isSegmentNavigationKey,
@@ -14,7 +14,7 @@
14
14
  if (isSegmentNavigationKey(e.key)) {
15
15
  const currNode = e.currentTarget as HTMLElement;
16
16
  const dateFieldInputNode = currNode.closest(
17
- `[${DATE_RANGE_FIELD_ROOT_ATTR}]`
17
+ dateRangeFieldAttrs.selector("root")
18
18
  ) as HTMLElement;
19
19
  if (!dateFieldInputNode) return;
20
20
  handleSegmentNavigation(e, dateFieldInputNode);
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { watch } from "runed";
2
3
  import { box, mergeProps } from "svelte-toolbelt";
3
4
  import type { DateValue } from "@internationalized/date";
4
5
  import { useDateRangePickerRoot } from "../date-range-picker.svelte.js";
@@ -10,7 +11,7 @@
10
11
  import { useId } from "../../../internal/use-id.js";
11
12
  import type { DateRange } from "../../../shared/index.js";
12
13
  import { getDefaultDate } from "../../../internal/date-time/utils.js";
13
- import { watch } from "runed";
14
+ import { resolveLocaleProp } from "../../utilities/config/prop-resolvers.js";
14
15
 
15
16
  let {
16
17
  open = $bindable(false),
@@ -30,7 +31,7 @@
30
31
  granularity,
31
32
  readonlySegments = [],
32
33
  hourCycle,
33
- locale = "en",
34
+ locale,
34
35
  hideTimeZone = false,
35
36
  required = false,
36
37
  calendarLabel = "Event",
@@ -136,7 +137,7 @@
136
137
  granularity: box.with(() => granularity),
137
138
  readonlySegments: box.with(() => readonlySegments),
138
139
  hourCycle: box.with(() => hourCycle),
139
- locale: box.with(() => locale),
140
+ locale: resolveLocaleProp(() => locale),
140
141
  hideTimeZone: box.with(() => hideTimeZone),
141
142
  required: box.with(() => required),
142
143
  calendarLabel: box.with(() => calendarLabel),
@@ -1,6 +1,7 @@
1
1
  import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
2
2
  import type { BitsKeyboardEvent, BitsMouseEvent, WithRefProps } from "../../internal/types.js";
3
3
  type DialogVariant = "alert-dialog" | "dialog";
4
+ declare const dialogAttrs: import("../../internal/attrs.js").BitsAttrs<readonly ["content", "trigger", "overlay", "title", "description", "close", "cancel", "action"]>;
4
5
  type DialogRootStateProps = WritableBoxedValues<{
5
6
  open: boolean;
6
7
  }> & ReadableBoxedValues<{
@@ -16,19 +17,10 @@ declare class DialogRootState {
16
17
  triggerId: string | undefined;
17
18
  descriptionId: string | undefined;
18
19
  cancelNode: HTMLElement | null;
19
- attrs: {
20
- readonly content: "data-dialog-content" | "data-alert-dialog-content";
21
- readonly trigger: "data-dialog-trigger" | "data-alert-dialog-trigger";
22
- readonly overlay: "data-dialog-overlay" | "data-alert-dialog-overlay";
23
- readonly title: "data-dialog-title" | "data-alert-dialog-title";
24
- readonly description: "data-dialog-description" | "data-alert-dialog-description";
25
- readonly close: "data-dialog-close" | "data-alert-dialog-close";
26
- readonly cancel: "data-dialog-cancel" | "data-alert-dialog-cancel";
27
- readonly action: "data-dialog-action" | "data-alert-dialog-action";
28
- };
29
20
  constructor(opts: DialogRootStateProps);
30
21
  handleOpen(): void;
31
22
  handleClose(): void;
23
+ getBitsAttr: typeof dialogAttrs.getAttr;
32
24
  sharedProps: {
33
25
  readonly "data-state": "open" | "closed";
34
26
  };
@@ -58,7 +50,6 @@ type DialogCloseStateProps = WithRefProps & ReadableBoxedValues<{
58
50
  disabled: boolean;
59
51
  }>;
60
52
  declare class DialogCloseState {
61
- #private;
62
53
  readonly opts: DialogCloseStateProps;
63
54
  readonly root: DialogRootState;
64
55
  constructor(opts: DialogCloseStateProps, root: DialogRootState);
@@ -75,7 +66,6 @@ declare class DialogCloseState {
75
66
  }
76
67
  type DialogActionStateProps = WithRefProps;
77
68
  declare class DialogActionState {
78
- #private;
79
69
  readonly opts: DialogActionStateProps;
80
70
  readonly root: DialogRootState;
81
71
  constructor(opts: DialogActionStateProps, root: DialogRootState);
@@ -1,20 +1,12 @@
1
1
  import { attachRef } from "svelte-toolbelt";
2
2
  import { Context } from "runed";
3
- import { getAriaExpanded, getDataOpenClosed } from "../../internal/attrs.js";
3
+ import { createBitsAttrs, getAriaExpanded, getDataOpenClosed } from "../../internal/attrs.js";
4
4
  import { kbd } from "../../internal/kbd.js";
5
5
  import { untrack } from "svelte";
6
- function createAttrs(variant) {
7
- return {
8
- content: `data-${variant}-content`,
9
- trigger: `data-${variant}-trigger`,
10
- overlay: `data-${variant}-overlay`,
11
- title: `data-${variant}-title`,
12
- description: `data-${variant}-description`,
13
- close: `data-${variant}-close`,
14
- cancel: `data-${variant}-cancel`,
15
- action: `data-${variant}-action`,
16
- };
17
- }
6
+ const dialogAttrs = createBitsAttrs({
7
+ component: "dialog",
8
+ parts: ["content", "trigger", "overlay", "title", "description", "close", "cancel", "action"],
9
+ });
18
10
  class DialogRootState {
19
11
  opts;
20
12
  triggerNode = $state(null);
@@ -25,7 +17,6 @@ class DialogRootState {
25
17
  triggerId = $state(undefined);
26
18
  descriptionId = $state(undefined);
27
19
  cancelNode = $state(null);
28
- attrs = $derived.by(() => createAttrs(this.opts.variant.current));
29
20
  constructor(opts) {
30
21
  this.opts = opts;
31
22
  this.handleOpen = this.handleOpen.bind(this);
@@ -41,6 +32,9 @@ class DialogRootState {
41
32
  return;
42
33
  this.opts.open.current = false;
43
34
  }
35
+ getBitsAttr = (part) => {
36
+ return dialogAttrs.getAttr(part, this.opts.variant.current);
37
+ };
44
38
  sharedProps = $derived.by(() => ({
45
39
  "data-state": getDataOpenClosed(this.opts.open.current),
46
40
  }));
@@ -74,7 +68,7 @@ class DialogTriggerState {
74
68
  "aria-haspopup": "dialog",
75
69
  "aria-expanded": getAriaExpanded(this.root.opts.open.current),
76
70
  "aria-controls": this.root.contentId,
77
- [this.root.attrs.trigger]: "",
71
+ [this.root.getBitsAttr("trigger")]: "",
78
72
  onkeydown: this.onkeydown,
79
73
  onclick: this.onclick,
80
74
  disabled: this.opts.disabled.current ? true : undefined,
@@ -88,7 +82,6 @@ class DialogTriggerState {
88
82
  class DialogCloseState {
89
83
  opts;
90
84
  root;
91
- #attr = $derived.by(() => this.root.attrs[this.opts.variant.current]);
92
85
  constructor(opts, root) {
93
86
  this.opts = opts;
94
87
  this.root = root;
@@ -112,7 +105,7 @@ class DialogCloseState {
112
105
  }
113
106
  props = $derived.by(() => ({
114
107
  id: this.opts.id.current,
115
- [this.#attr]: "",
108
+ [this.root.getBitsAttr(this.opts.variant.current)]: "",
116
109
  onclick: this.onclick,
117
110
  onkeydown: this.onkeydown,
118
111
  disabled: this.opts.disabled.current ? true : undefined,
@@ -124,14 +117,13 @@ class DialogCloseState {
124
117
  class DialogActionState {
125
118
  opts;
126
119
  root;
127
- #attr = $derived.by(() => this.root.attrs.action);
128
120
  constructor(opts, root) {
129
121
  this.opts = opts;
130
122
  this.root = root;
131
123
  }
132
124
  props = $derived.by(() => ({
133
125
  id: this.opts.id.current,
134
- [this.#attr]: "",
126
+ [this.root.getBitsAttr("action")]: "",
135
127
  ...this.root.sharedProps,
136
128
  ...attachRef(this.opts.ref),
137
129
  }));
@@ -147,7 +139,7 @@ class DialogTitleState {
147
139
  id: this.opts.id.current,
148
140
  role: "heading",
149
141
  "aria-level": this.opts.level.current,
150
- [this.root.attrs.title]: "",
142
+ [this.root.getBitsAttr("title")]: "",
151
143
  ...this.root.sharedProps,
152
144
  ...attachRef(this.opts.ref, (v) => (this.root.titleId = v?.id)),
153
145
  }));
@@ -161,7 +153,7 @@ class DialogDescriptionState {
161
153
  }
162
154
  props = $derived.by(() => ({
163
155
  id: this.opts.id.current,
164
- [this.root.attrs.description]: "",
156
+ [this.root.getBitsAttr("description")]: "",
165
157
  ...this.root.sharedProps,
166
158
  ...attachRef(this.opts.ref, (v) => {
167
159
  this.root.descriptionNode = v;
@@ -183,7 +175,7 @@ class DialogContentState {
183
175
  "aria-modal": "true",
184
176
  "aria-describedby": this.root.descriptionId,
185
177
  "aria-labelledby": this.root.titleId,
186
- [this.root.attrs.content]: "",
178
+ [this.root.getBitsAttr("content")]: "",
187
179
  style: {
188
180
  pointerEvents: "auto",
189
181
  outline: this.root.opts.variant.current === "alert-dialog" ? "none" : undefined,
@@ -206,7 +198,7 @@ class DialogOverlayState {
206
198
  snippetProps = $derived.by(() => ({ open: this.root.opts.open.current }));
207
199
  props = $derived.by(() => ({
208
200
  id: this.opts.id.current,
209
- [this.root.attrs.overlay]: "",
201
+ [this.root.getBitsAttr("overlay")]: "",
210
202
  style: {
211
203
  pointerEvents: "auto",
212
204
  },
@@ -240,7 +232,7 @@ class AlertDialogCancelState {
240
232
  }
241
233
  props = $derived.by(() => ({
242
234
  id: this.opts.id.current,
243
- [this.root.attrs.cancel]: "",
235
+ [this.root.getBitsAttr("cancel")]: "",
244
236
  onclick: this.onclick,
245
237
  onkeydown: this.onkeydown,
246
238
  tabindex: 0,