@xingxingmofashu/ui 0.1.1 → 0.1.3

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 (71) hide show
  1. package/README.md +39 -14
  2. package/dist/components/accordion.d.ts +14 -10
  3. package/dist/components/accordion.mjs +78 -25
  4. package/dist/components/alert-dialog.d.ts +7 -2
  5. package/dist/components/alert-dialog.mjs +74 -33
  6. package/dist/components/button.d.ts +6 -2
  7. package/dist/components/button.mjs +20 -11
  8. package/dist/components/card.d.ts +6 -1
  9. package/dist/components/card.mjs +27 -4
  10. package/dist/components/checkbox.d.ts +5 -1
  11. package/dist/components/checkbox.mjs +73 -26
  12. package/dist/components/dialog.d.ts +7 -2
  13. package/dist/components/dialog.mjs +66 -20
  14. package/dist/components/drawer.d.ts +7 -2
  15. package/dist/components/drawer.mjs +66 -20
  16. package/dist/components/icons/check.d.ts +3 -0
  17. package/dist/components/icons/check.mjs +24 -0
  18. package/dist/components/icons/close.d.ts +3 -0
  19. package/dist/components/icons/close.mjs +21 -0
  20. package/dist/components/icons/dash.d.ts +3 -0
  21. package/dist/components/icons/dash.mjs +24 -0
  22. package/dist/components/icons/error.d.ts +3 -0
  23. package/dist/components/icons/error.mjs +23 -0
  24. package/dist/components/icons/info.d.ts +3 -0
  25. package/dist/components/icons/info.mjs +23 -0
  26. package/dist/components/icons/loading.d.ts +3 -0
  27. package/dist/components/icons/loading.mjs +22 -0
  28. package/dist/components/icons/plus.d.ts +3 -0
  29. package/dist/components/icons/plus.mjs +22 -0
  30. package/dist/components/icons/success.d.ts +3 -0
  31. package/dist/components/icons/success.mjs +22 -0
  32. package/dist/components/icons/warning.d.ts +3 -0
  33. package/dist/components/icons/warning.mjs +23 -0
  34. package/dist/components/input.d.ts +5 -1
  35. package/dist/components/input.mjs +73 -30
  36. package/dist/components/popover.d.ts +7 -2
  37. package/dist/components/popover.mjs +53 -14
  38. package/dist/components/progress.d.ts +21 -0
  39. package/dist/components/progress.mjs +71 -0
  40. package/dist/components/scroll-area.d.ts +7 -2
  41. package/dist/components/scroll-area.mjs +48 -14
  42. package/dist/components/slider.d.ts +15 -4
  43. package/dist/components/slider.mjs +65 -16
  44. package/dist/components/switch.d.ts +5 -1
  45. package/dist/components/switch.mjs +65 -18
  46. package/dist/components/toast.d.ts +17 -11
  47. package/dist/components/toast.mjs +111 -87
  48. package/dist/components/toggle-group.d.ts +11 -5
  49. package/dist/components/toggle-group.mjs +54 -6
  50. package/dist/components/toggle.d.ts +5 -1
  51. package/dist/components/toggle.mjs +36 -5
  52. package/dist/index.css +1 -1
  53. package/dist/index.d.ts +2 -1
  54. package/dist/index.mjs +2 -0
  55. package/dist/internal/aria.d.ts +3 -0
  56. package/dist/internal/aria.mjs +5 -0
  57. package/dist/internal/tv.d.ts +17 -0
  58. package/dist/internal/tv.mjs +0 -0
  59. package/dist/keyframes.css +1 -1
  60. package/dist/theme/alert-dialog.mjs +1 -1
  61. package/dist/theme/checkbox.mjs +4 -4
  62. package/dist/theme/dialog.mjs +1 -1
  63. package/dist/theme/drawer.mjs +1 -1
  64. package/dist/theme/popover.mjs +2 -2
  65. package/dist/theme/progress.d.ts +80 -0
  66. package/dist/theme/progress.mjs +64 -0
  67. package/dist/theme/slider.mjs +8 -0
  68. package/dist/theme/switch.mjs +2 -0
  69. package/dist/theme/toast.d.ts +15 -36
  70. package/dist/theme/toast.mjs +29 -21
  71. package/package.json +8 -3
@@ -2,9 +2,11 @@
2
2
  import { Input as UIInput } from "@base-ui/react/input";
3
3
  import { cn } from "cn";
4
4
  import * as React from "react";
5
+ import { mergeIds } from "../internal/aria.mjs";
5
6
  import theme from "../theme/input.mjs";
6
7
  function Input({
7
8
  className,
9
+ ui,
8
10
  label,
9
11
  description,
10
12
  leadingIcon,
@@ -12,53 +14,94 @@ function Input({
12
14
  size,
13
15
  id,
14
16
  disabled,
17
+ "aria-describedby": ariaDescribedBy,
15
18
  ...props
16
19
  }) {
17
- const ui = theme({ size });
20
+ const styles = theme({ size });
18
21
  const generatedId = React.useId();
22
+ const descriptionId = React.useId();
19
23
  const inputId = id ?? generatedId;
24
+ const describedBy = mergeIds(
25
+ ariaDescribedBy,
26
+ description ? descriptionId : void 0
27
+ );
20
28
  return /* @__PURE__ */ React.createElement(
21
29
  "div",
22
30
  {
23
31
  "data-slot": "root",
24
32
  "data-disabled": disabled || void 0,
25
- className: cn(ui.root(), className)
33
+ className: cn(styles.root(), ui?.root, className)
26
34
  },
27
- label ? /* @__PURE__ */ React.createElement("label", { htmlFor: inputId, "data-slot": "label", className: ui.label() }, label) : null,
28
- /* @__PURE__ */ React.createElement("span", { "data-slot": "control", className: ui.control() }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
29
- "span",
35
+ label ? /* @__PURE__ */ React.createElement(
36
+ "label",
30
37
  {
31
- "aria-hidden": "true",
32
- "data-slot": "overlay",
33
- className: ui.overlay()
34
- }
35
- )), leadingIcon ? /* @__PURE__ */ React.createElement(
38
+ htmlFor: inputId,
39
+ "data-slot": "label",
40
+ className: cn(styles.label(), ui?.label)
41
+ },
42
+ label
43
+ ) : null,
44
+ /* @__PURE__ */ React.createElement(
36
45
  "span",
37
46
  {
38
- "data-slot": "leading-icon",
39
- className: ui.leadingIcon(),
40
- "aria-hidden": "true"
47
+ "data-slot": "control",
48
+ className: cn(styles.control(), ui?.control)
41
49
  },
42
- leadingIcon
43
- ) : null, /* @__PURE__ */ React.createElement(
44
- UIInput,
45
- {
46
- ...props,
47
- id: inputId,
48
- disabled,
49
- "data-slot": "input",
50
- className: ui.input()
51
- }
52
- ), trailingIcon ? /* @__PURE__ */ React.createElement(
50
+ /* @__PURE__ */ React.createElement(
51
+ "span",
52
+ {
53
+ "aria-hidden": "true",
54
+ "data-slot": "glass",
55
+ className: cn(styles.glass(), ui?.glass)
56
+ },
57
+ /* @__PURE__ */ React.createElement(
58
+ "span",
59
+ {
60
+ "aria-hidden": "true",
61
+ "data-slot": "overlay",
62
+ className: cn(styles.overlay(), ui?.overlay)
63
+ }
64
+ )
65
+ ),
66
+ leadingIcon ? /* @__PURE__ */ React.createElement(
67
+ "span",
68
+ {
69
+ "data-slot": "leading-icon",
70
+ className: cn(styles.leadingIcon(), ui?.leadingIcon),
71
+ "aria-hidden": "true"
72
+ },
73
+ leadingIcon
74
+ ) : null,
75
+ /* @__PURE__ */ React.createElement(
76
+ UIInput,
77
+ {
78
+ ...props,
79
+ id: inputId,
80
+ disabled,
81
+ "aria-describedby": describedBy,
82
+ "data-slot": "input",
83
+ className: cn(styles.input(), ui?.input)
84
+ }
85
+ ),
86
+ trailingIcon ? /* @__PURE__ */ React.createElement(
87
+ "span",
88
+ {
89
+ "data-slot": "trailing-icon",
90
+ className: cn(styles.trailingIcon(), ui?.trailingIcon),
91
+ "aria-hidden": "true"
92
+ },
93
+ trailingIcon
94
+ ) : null
95
+ ),
96
+ description ? /* @__PURE__ */ React.createElement(
53
97
  "span",
54
98
  {
55
- "data-slot": "trailing-icon",
56
- className: ui.trailingIcon(),
57
- "aria-hidden": "true"
99
+ id: descriptionId,
100
+ "data-slot": "description",
101
+ className: cn(styles.description(), ui?.description)
58
102
  },
59
- trailingIcon
60
- ) : null),
61
- description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "description", className: ui.description() }, description) : null
103
+ description
104
+ ) : null
62
105
  );
63
106
  }
64
107
  export { Input };
@@ -1,5 +1,8 @@
1
1
  import { Popover as UIPopover } from "@base-ui/react/popover";
2
2
  import * as React from "react";
3
+ import { type ComponentConfig } from "../internal/tv";
4
+ import theme from "../theme/popover";
5
+ type Popover = ComponentConfig<typeof theme>;
3
6
  type PositionerProps = React.ComponentProps<typeof UIPopover.Positioner>;
4
7
  type PopoverProps = Omit<UIPopover.Root.Props, "children"> & {
5
8
  /** Element that opens the popover. It must forward props and refs. */
@@ -25,8 +28,10 @@ type PopoverProps = Omit<UIPopover.Root.Props, "children"> & {
25
28
  /** Padding between the popup and the edge of the collision boundary. */
26
29
  collisionPadding?: PositionerProps["collisionPadding"];
27
30
  /** Tailwind classes merged into the popup. */
28
- className?: any;
31
+ className?: string;
32
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
33
+ ui?: Popover["slots"];
29
34
  };
30
- declare function Popover({ trigger, title, description, children, footer, arrow, side, align, sideOffset, alignOffset, collisionPadding, className, ...props }: PopoverProps): React.JSX.Element;
35
+ declare function Popover({ trigger, title, description, children, footer, arrow, side, align, sideOffset, alignOffset, collisionPadding, className, ui, ...props }: PopoverProps): React.JSX.Element;
31
36
  export { Popover };
32
37
  export type { PopoverProps };
@@ -16,9 +16,10 @@ function Popover({
16
16
  alignOffset,
17
17
  collisionPadding,
18
18
  className,
19
+ ui,
19
20
  ...props
20
21
  }) {
21
- const ui = theme();
22
+ const styles = theme();
22
23
  return /* @__PURE__ */ React.createElement(UIPopover.Root, { ...props }, /* @__PURE__ */ React.createElement(UIPopover.Trigger, { render: trigger }), /* @__PURE__ */ React.createElement(UIPopover.Portal, null, /* @__PURE__ */ React.createElement(
23
24
  UIPopover.Positioner,
24
25
  {
@@ -28,31 +29,69 @@ function Popover({
28
29
  sideOffset,
29
30
  alignOffset,
30
31
  collisionPadding,
31
- className: ui.positioner()
32
+ className: cn(styles.positioner(), ui?.positioner)
32
33
  },
33
34
  /* @__PURE__ */ React.createElement(
34
35
  UIPopover.Popup,
35
36
  {
36
37
  "data-slot": "popup",
37
- className: cn(ui.popup(), className)
38
+ className: cn(styles.popup(), ui?.popup, className)
38
39
  },
39
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
40
+ /* @__PURE__ */ React.createElement(
40
41
  "span",
41
42
  {
42
43
  "aria-hidden": "true",
43
- "data-slot": "overlay",
44
- className: ui.overlay()
44
+ "data-slot": "glass",
45
+ className: cn(styles.glass(), ui?.glass)
46
+ },
47
+ /* @__PURE__ */ React.createElement(
48
+ "span",
49
+ {
50
+ "aria-hidden": "true",
51
+ "data-slot": "overlay",
52
+ className: cn(styles.overlay(), ui?.overlay)
53
+ }
54
+ )
55
+ ),
56
+ arrow ? /* @__PURE__ */ React.createElement(
57
+ UIPopover.Arrow,
58
+ {
59
+ "data-slot": "arrow",
60
+ className: cn(styles.arrow(), ui?.arrow)
45
61
  }
46
- )),
47
- arrow ? /* @__PURE__ */ React.createElement(UIPopover.Arrow, { "data-slot": "arrow", className: ui.arrow() }) : null,
48
- /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: ui.content() }, /* @__PURE__ */ React.createElement(UIPopover.Title, { "data-slot": "title", className: ui.title() }, title), description ? /* @__PURE__ */ React.createElement(
49
- UIPopover.Description,
62
+ ) : null,
63
+ /* @__PURE__ */ React.createElement(
64
+ "div",
50
65
  {
51
- "data-slot": "description",
52
- className: ui.description()
66
+ "data-slot": "content",
67
+ className: cn(styles.content(), ui?.content)
53
68
  },
54
- description
55
- ) : null, children ? /* @__PURE__ */ React.createElement("div", { "data-slot": "body", className: ui.body() }, children) : null, footer ? /* @__PURE__ */ React.createElement("div", { "data-slot": "footer", className: ui.footer() }, footer) : null)
69
+ /* @__PURE__ */ React.createElement(
70
+ UIPopover.Title,
71
+ {
72
+ "data-slot": "title",
73
+ className: cn(styles.title(), ui?.title)
74
+ },
75
+ title
76
+ ),
77
+ description ? /* @__PURE__ */ React.createElement(
78
+ UIPopover.Description,
79
+ {
80
+ "data-slot": "description",
81
+ className: cn(styles.description(), ui?.description)
82
+ },
83
+ description
84
+ ) : null,
85
+ children ? /* @__PURE__ */ React.createElement("div", { "data-slot": "body", className: cn(styles.body(), ui?.body) }, children) : null,
86
+ footer ? /* @__PURE__ */ React.createElement(
87
+ "div",
88
+ {
89
+ "data-slot": "footer",
90
+ className: cn(styles.footer(), ui?.footer)
91
+ },
92
+ footer
93
+ ) : null
94
+ )
56
95
  )
57
96
  )));
58
97
  }
@@ -0,0 +1,21 @@
1
+ import { Progress as UIProgress } from "@base-ui/react/progress";
2
+ import * as React from "react";
3
+ import { type VariantProps } from "tailwind-variants";
4
+ import { type ComponentConfig } from "../internal/tv";
5
+ import theme from "../theme/progress";
6
+ type Progress = ComponentConfig<typeof theme>;
7
+ type ProgressProps = Omit<UIProgress.Root.Props, "children" | "className" | "style" | "value"> & VariantProps<typeof theme> & {
8
+ /** Current value. Use `null` for an indeterminate progress bar. */
9
+ value?: number | null;
10
+ /** Visible label for the progress bar. */
11
+ label?: React.ReactNode;
12
+ /** Supporting text rendered below the bar. */
13
+ description?: React.ReactNode;
14
+ /** Tailwind classes merged into the root. */
15
+ className?: string;
16
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
17
+ ui?: Progress["slots"];
18
+ };
19
+ declare function Progress({ className, ui, label, description, size, value, "aria-describedby": ariaDescribedBy, ...props }: ProgressProps): React.JSX.Element;
20
+ export { Progress };
21
+ export type { ProgressProps };
@@ -0,0 +1,71 @@
1
+ "use client";
2
+ import { Progress as UIProgress } from "@base-ui/react/progress";
3
+ import { cn } from "cn";
4
+ import * as React from "react";
5
+ import { mergeIds } from "../internal/aria.mjs";
6
+ import theme from "../theme/progress.mjs";
7
+ function Progress({
8
+ className,
9
+ ui,
10
+ label,
11
+ description,
12
+ size,
13
+ value = null,
14
+ "aria-describedby": ariaDescribedBy,
15
+ ...props
16
+ }) {
17
+ const styles = theme({ size });
18
+ const descriptionId = React.useId();
19
+ const describedBy = mergeIds(
20
+ ariaDescribedBy,
21
+ description ? descriptionId : void 0
22
+ );
23
+ return /* @__PURE__ */ React.createElement(
24
+ UIProgress.Root,
25
+ {
26
+ ...props,
27
+ value,
28
+ "aria-describedby": describedBy,
29
+ "data-slot": "root",
30
+ className: cn(styles.root(), ui?.root, className)
31
+ },
32
+ /* @__PURE__ */ React.createElement("div", { "data-slot": "header", className: cn(styles.header(), ui?.header) }, label ? /* @__PURE__ */ React.createElement(
33
+ UIProgress.Label,
34
+ {
35
+ "data-slot": "label",
36
+ className: cn(styles.label(), ui?.label)
37
+ },
38
+ label
39
+ ) : null, /* @__PURE__ */ React.createElement(
40
+ UIProgress.Value,
41
+ {
42
+ "data-slot": "value",
43
+ className: cn(styles.value(), ui?.value)
44
+ }
45
+ )),
46
+ /* @__PURE__ */ React.createElement(
47
+ UIProgress.Track,
48
+ {
49
+ "data-slot": "track",
50
+ className: cn(styles.track(), ui?.track)
51
+ },
52
+ /* @__PURE__ */ React.createElement(
53
+ UIProgress.Indicator,
54
+ {
55
+ "data-slot": "indicator",
56
+ className: cn(styles.indicator(), ui?.indicator)
57
+ }
58
+ )
59
+ ),
60
+ description ? /* @__PURE__ */ React.createElement(
61
+ "span",
62
+ {
63
+ id: descriptionId,
64
+ "data-slot": "description",
65
+ className: cn(styles.description(), ui?.description)
66
+ },
67
+ description
68
+ ) : null
69
+ );
70
+ }
71
+ export { Progress };
@@ -1,14 +1,19 @@
1
1
  import { ScrollArea as UIScrollArea } from "@base-ui/react/scroll-area";
2
2
  import * as React from "react";
3
+ import { type ComponentConfig } from "../internal/tv";
4
+ import theme from "../theme/scroll-area";
3
5
  /** Scrollbar axes rendered by the scroll area. */
4
6
  type ScrollAreaOrientation = "vertical" | "horizontal" | "both";
7
+ type ScrollArea = ComponentConfig<typeof theme>;
5
8
  type ScrollAreaProps = Omit<UIScrollArea.Root.Props, "children" | "className" | "style"> & {
6
9
  /** Scrollable content. */
7
10
  children?: React.ReactNode;
8
11
  /** Scrollbar axes to render. Defaults to `"vertical"`. */
9
12
  orientation?: ScrollAreaOrientation;
10
13
  /** Tailwind classes merged into the root. */
11
- className?: any;
14
+ className?: string;
15
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
16
+ ui?: ScrollArea["slots"];
12
17
  };
13
18
  /**
14
19
  * A native scroll container with custom liquid glass scrollbars.
@@ -16,6 +21,6 @@ type ScrollAreaProps = Omit<UIScrollArea.Root.Props, "children" | "className" |
16
21
  * The root owns the visible glass surface. Give it a height (for example
17
22
  * `className="h-64"`) to create a scrollable viewport.
18
23
  */
19
- declare function ScrollArea({ "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, className, orientation, ...props }: ScrollAreaProps): React.JSX.Element;
24
+ declare function ScrollArea({ "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, className, ui, orientation, ...props }: ScrollAreaProps): React.JSX.Element;
20
25
  export { ScrollArea };
21
26
  export type { ScrollAreaOrientation, ScrollAreaProps };
@@ -9,26 +9,35 @@ function ScrollArea({
9
9
  "aria-labelledby": ariaLabelledBy,
10
10
  children,
11
11
  className,
12
+ ui,
12
13
  orientation = "vertical",
13
14
  ...props
14
15
  }) {
15
- const ui = theme();
16
+ const styles = theme();
16
17
  return /* @__PURE__ */ React.createElement(
17
18
  UIScrollArea.Root,
18
19
  {
19
20
  ...props,
20
21
  "data-slot": "root",
21
22
  "data-orientation": orientation,
22
- className: cn(ui.root(), className)
23
+ className: cn(styles.root(), ui?.root, className)
23
24
  },
24
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
25
+ /* @__PURE__ */ React.createElement(
25
26
  "span",
26
27
  {
27
28
  "aria-hidden": "true",
28
- "data-slot": "overlay",
29
- className: ui.overlay()
30
- }
31
- )),
29
+ "data-slot": "glass",
30
+ className: cn(styles.glass(), ui?.glass)
31
+ },
32
+ /* @__PURE__ */ React.createElement(
33
+ "span",
34
+ {
35
+ "aria-hidden": "true",
36
+ "data-slot": "overlay",
37
+ className: cn(styles.overlay(), ui?.overlay)
38
+ }
39
+ )
40
+ ),
32
41
  /* @__PURE__ */ React.createElement(
33
42
  UIScrollArea.Viewport,
34
43
  {
@@ -36,29 +45,54 @@ function ScrollArea({
36
45
  "aria-label": ariaLabel,
37
46
  "aria-labelledby": ariaLabelledBy,
38
47
  "data-slot": "viewport",
39
- className: ui.viewport()
48
+ className: cn(styles.viewport(), ui?.viewport)
40
49
  },
41
- /* @__PURE__ */ React.createElement(UIScrollArea.Content, { "data-slot": "content", className: ui.content() }, children)
50
+ /* @__PURE__ */ React.createElement(
51
+ UIScrollArea.Content,
52
+ {
53
+ "data-slot": "content",
54
+ className: cn(styles.content(), ui?.content)
55
+ },
56
+ children
57
+ )
42
58
  ),
43
59
  orientation !== "horizontal" ? /* @__PURE__ */ React.createElement(
44
60
  UIScrollArea.Scrollbar,
45
61
  {
46
62
  "data-slot": "scrollbar",
47
63
  orientation: "vertical",
48
- className: ui.scrollbar()
64
+ className: cn(styles.scrollbar(), ui?.scrollbar)
49
65
  },
50
- /* @__PURE__ */ React.createElement(UIScrollArea.Thumb, { "data-slot": "thumb", className: ui.thumb() })
66
+ /* @__PURE__ */ React.createElement(
67
+ UIScrollArea.Thumb,
68
+ {
69
+ "data-slot": "thumb",
70
+ className: cn(styles.thumb(), ui?.thumb)
71
+ }
72
+ )
51
73
  ) : null,
52
74
  orientation !== "vertical" ? /* @__PURE__ */ React.createElement(
53
75
  UIScrollArea.Scrollbar,
54
76
  {
55
77
  "data-slot": "scrollbar",
56
78
  orientation: "horizontal",
57
- className: ui.scrollbar()
79
+ className: cn(styles.scrollbar(), ui?.scrollbar)
58
80
  },
59
- /* @__PURE__ */ React.createElement(UIScrollArea.Thumb, { "data-slot": "thumb", className: ui.thumb() })
81
+ /* @__PURE__ */ React.createElement(
82
+ UIScrollArea.Thumb,
83
+ {
84
+ "data-slot": "thumb",
85
+ className: cn(styles.thumb(), ui?.thumb)
86
+ }
87
+ )
60
88
  ) : null,
61
- orientation === "both" ? /* @__PURE__ */ React.createElement(UIScrollArea.Corner, { "data-slot": "corner", className: ui.corner() }) : null
89
+ orientation === "both" ? /* @__PURE__ */ React.createElement(
90
+ UIScrollArea.Corner,
91
+ {
92
+ "data-slot": "corner",
93
+ className: cn(styles.corner(), ui?.corner)
94
+ }
95
+ ) : null
62
96
  );
63
97
  }
64
98
  export { ScrollArea };
@@ -1,12 +1,23 @@
1
1
  import { Slider as UISlider } from "@base-ui/react/slider";
2
+ import * as React from "react";
3
+ import { type ComponentConfig } from "../internal/tv";
4
+ import theme from "../theme/slider";
5
+ type Slider = ComponentConfig<typeof theme>;
2
6
  type SliderProps<Value extends number | readonly number[] = number> = Omit<UISlider.Root.Props<Value>, "children" | "style" | "className"> & {
3
7
  /** Tailwind classes merged into the root. */
4
- className?: any;
8
+ className?: string;
9
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
10
+ ui?: Slider["slots"];
11
+ /** Accessible name for the thumb at `index`. Useful for range sliders. */
12
+ getAriaLabel?: UISlider.Thumb.Props["getAriaLabel"];
13
+ /** Accessible value text for the thumb at `index`. */
14
+ getAriaValueText?: UISlider.Thumb.Props["getAriaValueText"];
5
15
  };
6
16
  /**
7
- * Sliders need an accessible name. Pass `aria-labelledby`; Base UI forwards it
8
- * from the root to every thumb.
17
+ * Sliders need an accessible name. Pass `aria-label` or `aria-labelledby`;
18
+ * both are forwarded from the root to every thumb. `aria-describedby` is also
19
+ * forwarded so supporting copy is announced with each thumb.
9
20
  */
10
- declare function Slider<Value extends number | readonly number[] = number>({ className, value, defaultValue, ...props }: SliderProps<Value>): import("react").JSX.Element;
21
+ declare function Slider<Value extends number | readonly number[] = number>({ className, ui, value, defaultValue, "aria-describedby": ariaDescribedBy, "aria-errormessage": ariaErrorMessage, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, getAriaLabel, getAriaValueText, ...props }: SliderProps<Value>): React.JSX.Element;
11
22
  export { Slider };
12
23
  export type { SliderProps };
@@ -1,41 +1,90 @@
1
1
  "use client";
2
2
  import { Slider as UISlider } from "@base-ui/react/slider";
3
3
  import { cn } from "cn";
4
+ import * as React from "react";
4
5
  import theme from "../theme/slider.mjs";
6
+ function setAriaAttribute(input, name, value) {
7
+ if (value === void 0 || value === null) {
8
+ input.removeAttribute(name);
9
+ return;
10
+ }
11
+ input.setAttribute(name, String(value));
12
+ }
5
13
  function Slider({
6
14
  className,
15
+ ui,
7
16
  value,
8
17
  defaultValue,
18
+ "aria-describedby": ariaDescribedBy,
19
+ "aria-errormessage": ariaErrorMessage,
20
+ "aria-invalid": ariaInvalid,
21
+ "aria-label": ariaLabel,
22
+ "aria-labelledby": ariaLabelledBy,
23
+ getAriaLabel,
24
+ getAriaValueText,
9
25
  ...props
10
26
  }) {
11
- const ui = theme();
27
+ const styles = theme();
28
+ const syncThumbAria = React.useCallback(
29
+ (input) => {
30
+ if (!input) {
31
+ return;
32
+ }
33
+ setAriaAttribute(input, "aria-invalid", ariaInvalid);
34
+ setAriaAttribute(input, "aria-errormessage", ariaErrorMessage);
35
+ },
36
+ [ariaErrorMessage, ariaInvalid]
37
+ );
12
38
  const values = value ?? defaultValue;
13
39
  const thumbCount = Array.isArray(values) ? Math.max(1, values.length) : 1;
14
40
  return /* @__PURE__ */ React.createElement(
15
41
  UISlider.Root,
16
42
  {
17
43
  ...props,
44
+ "aria-label": ariaLabel,
45
+ "aria-labelledby": ariaLabelledBy,
18
46
  value,
19
47
  defaultValue,
20
48
  "data-slot": "root",
21
- className: cn(ui.root(), className)
49
+ className: cn(styles.root(), ui?.root, className)
22
50
  },
23
- /* @__PURE__ */ React.createElement(UISlider.Control, { "data-slot": "control", className: ui.control() }, /* @__PURE__ */ React.createElement(UISlider.Track, { "data-slot": "track", className: ui.track() }, /* @__PURE__ */ React.createElement(
24
- UISlider.Indicator,
25
- {
26
- "data-slot": "indicator",
27
- className: ui.indicator()
28
- }
29
- )), Array.from({ length: thumbCount }, (_, index) => /* @__PURE__ */ React.createElement(
30
- UISlider.Thumb,
51
+ /* @__PURE__ */ React.createElement(
52
+ UISlider.Control,
31
53
  {
32
- key: index,
33
- index,
34
- "data-slot": "thumb",
35
- className: ui.thumb()
54
+ "data-slot": "control",
55
+ className: cn(styles.control(), ui?.control)
36
56
  },
37
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-layer": "thumb-glass" }, /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-lens" }), /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-specular" }), /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-glare" }))
38
- )))
57
+ /* @__PURE__ */ React.createElement(
58
+ UISlider.Track,
59
+ {
60
+ "data-slot": "track",
61
+ className: cn(styles.track(), ui?.track)
62
+ },
63
+ /* @__PURE__ */ React.createElement(
64
+ UISlider.Indicator,
65
+ {
66
+ "data-slot": "indicator",
67
+ className: cn(styles.indicator(), ui?.indicator)
68
+ }
69
+ )
70
+ ),
71
+ Array.from({ length: thumbCount }, (_, index) => /* @__PURE__ */ React.createElement(
72
+ UISlider.Thumb,
73
+ {
74
+ key: index,
75
+ index,
76
+ "aria-describedby": ariaDescribedBy,
77
+ "aria-label": ariaLabel,
78
+ "aria-labelledby": ariaLabelledBy,
79
+ getAriaLabel,
80
+ getAriaValueText,
81
+ inputRef: syncThumbAria,
82
+ "data-slot": "thumb",
83
+ className: cn(styles.thumb(), ui?.thumb)
84
+ },
85
+ /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-layer": "thumb-glass" }, /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-lens" }), /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-specular" }), /* @__PURE__ */ React.createElement("span", { "data-layer": "thumb-glare" }))
86
+ ))
87
+ )
39
88
  );
40
89
  }
41
90
  export { Slider };
@@ -1,17 +1,21 @@
1
1
  import { Switch as UISwitch } from "@base-ui/react/switch";
2
2
  import * as React from "react";
3
3
  import { type VariantProps } from "tailwind-variants";
4
+ import { type ComponentConfig } from "../internal/tv";
4
5
  import theme from "../theme/switch";
6
+ type Switch = ComponentConfig<typeof theme>;
5
7
  interface SwitchProps extends Omit<UISwitch.Root.Props, "className" | "children" | "style" | "ref">, VariantProps<typeof theme> {
6
8
  /** Ref to the rendered root element. */
7
9
  ref?: React.Ref<HTMLElement>;
8
10
  /** Tailwind classes merged into the Base UI switch root. */
9
11
  className?: string;
12
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
13
+ ui?: Switch["slots"];
10
14
  /** Visible label. */
11
15
  label?: React.ReactNode;
12
16
  /** Optional supporting text. */
13
17
  description?: React.ReactNode;
14
18
  }
15
- declare function Switch({ className, label, description, size, disabled, readOnly, onCheckedChange, ...props }: SwitchProps): React.JSX.Element;
19
+ declare function Switch({ className, ui, label, description, size, disabled, readOnly, onCheckedChange, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: SwitchProps): React.JSX.Element;
16
20
  export { Switch };
17
21
  export type { SwitchProps };