@xingxingmofashu/ui 0.1.1 → 0.1.2

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 (37) hide show
  1. package/README.md +19 -9
  2. package/dist/components/accordion.mjs +4 -9
  3. package/dist/components/checkbox.d.ts +1 -1
  4. package/dist/components/checkbox.mjs +27 -19
  5. package/dist/components/icons/check.d.ts +3 -0
  6. package/dist/components/icons/check.mjs +24 -0
  7. package/dist/components/icons/close.d.ts +3 -0
  8. package/dist/components/icons/close.mjs +21 -0
  9. package/dist/components/icons/dash.d.ts +3 -0
  10. package/dist/components/icons/dash.mjs +24 -0
  11. package/dist/components/icons/error.d.ts +3 -0
  12. package/dist/components/icons/error.mjs +23 -0
  13. package/dist/components/icons/info.d.ts +3 -0
  14. package/dist/components/icons/info.mjs +23 -0
  15. package/dist/components/icons/loading.d.ts +3 -0
  16. package/dist/components/icons/loading.mjs +22 -0
  17. package/dist/components/icons/plus.d.ts +3 -0
  18. package/dist/components/icons/plus.mjs +22 -0
  19. package/dist/components/icons/success.d.ts +3 -0
  20. package/dist/components/icons/success.mjs +22 -0
  21. package/dist/components/icons/warning.d.ts +3 -0
  22. package/dist/components/icons/warning.mjs +23 -0
  23. package/dist/components/input.d.ts +1 -1
  24. package/dist/components/input.mjs +17 -1
  25. package/dist/components/slider.d.ts +9 -3
  26. package/dist/components/slider.mjs +33 -0
  27. package/dist/components/switch.d.ts +1 -1
  28. package/dist/components/switch.mjs +24 -1
  29. package/dist/components/toast.d.ts +12 -11
  30. package/dist/components/toast.mjs +58 -87
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.mjs +1 -0
  33. package/dist/internal/aria.d.ts +3 -0
  34. package/dist/internal/aria.mjs +5 -0
  35. package/dist/theme/toast.d.ts +15 -36
  36. package/dist/theme/toast.mjs +28 -20
  37. package/package.json +2 -2
package/README.md CHANGED
@@ -1,4 +1,10 @@
1
- # @xingxingmofashu/ui
1
+ <picture>
2
+ <source media="(prefers-color-scheme: dark)" srcset=".github/assets/banner-dark.png">
3
+ <source media="(prefers-color-scheme: light)" srcset=".github/assets/banner-light.png">
4
+ <img alt="@xingxingmofashu/ui: Between black and white, glass finds its light." width="1247" src=".github/assets/banner-light.png">
5
+ </picture>
6
+
7
+ <div align="center">
2
8
 
3
9
  [![npm version][npm-version-src]][npm-version-href]
4
10
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
@@ -6,8 +12,10 @@
6
12
  [![React][react-src]][react-href]
7
13
  [![Tailwind CSS][tailwind-src]][tailwind-href]
8
14
 
9
- Liquid Glass UI is a collection of accessible, typed [React](https://react.dev)
10
- components built on [Base UI](https://base-ui.com),
15
+ </div>
16
+
17
+ `@xingxingmofashu/ui` is a collection of accessible, typed [React](https://react.dev)
18
+ components with a Liquid Glass visual style, built on [Base UI](https://base-ui.com),
11
19
  [Tailwind CSS](https://tailwindcss.com), and
12
20
  [Tailwind Variants](https://www.tailwind-variants.org). Glass surfaces, rim
13
21
  highlights, and inner shadows are drawn entirely with CSS.
@@ -23,8 +31,8 @@ Toggle, and Toggle Group.
23
31
 
24
32
  ## Documentation
25
33
 
26
- - [English documentation](https://xingxingmofashu.github.io/ui/docs/en/get-started)
27
- - [简体中文文档](https://xingxingmofashu.github.io/ui/docs/zh/get-started)
34
+ - [English](https://xingxingmofashu.github.io/ui/docs/en/get-started/introduction)
35
+ - [简体中文](https://xingxingmofashu.github.io/ui/docs/zh/get-started/introduction)
28
36
 
29
37
  ## Installation
30
38
 
@@ -115,9 +123,12 @@ Light and dark tokens are selected by `.light` / `.dark`, or by
115
123
 
116
124
  ```html
117
125
  <html class="dark">
118
- <!-- or -->
119
- <html data-theme="dark">
120
- </html>
126
+ ```
127
+
128
+ or:
129
+
130
+ ```html
131
+ <html data-theme="dark">
121
132
  ```
122
133
 
123
134
  A nested `.light` / `[data-theme="light"]` subtree can switch back to light
@@ -161,7 +172,6 @@ a reproduction. Before opening a pull request, run `pnpm lint`, `pnpm test`, and
161
172
  - [Base UI](https://base-ui.com)
162
173
  - [Tailwind CSS](https://tailwindcss.com)
163
174
  - [Tailwind Variants](https://www.tailwind-variants.org)
164
- - [cn](https://github.com/shadcn-ui/cn)
165
175
 
166
176
  ## License
167
177
 
@@ -3,6 +3,7 @@ import { Accordion as UIAccordion } from "@base-ui/react/accordion";
3
3
  import { cn } from "cn";
4
4
  import * as React from "react";
5
5
  import theme from "../theme/accordion.mjs";
6
+ import { PlusIcon } from "./icons/plus.mjs";
6
7
  function Accordion({
7
8
  className,
8
9
  size,
@@ -52,17 +53,11 @@ function AccordionItem({
52
53
  className: ui.indicator()
53
54
  },
54
55
  /* @__PURE__ */ React.createElement(
55
- "svg",
56
+ PlusIcon,
56
57
  {
57
58
  "data-slot": "indicator-icon",
58
- className: ui.indicatorIcon(),
59
- viewBox: "0 0 16 16",
60
- fill: "none",
61
- stroke: "currentColor",
62
- strokeLinecap: "square",
63
- strokeLinejoin: "round"
64
- },
65
- /* @__PURE__ */ React.createElement("path", { d: "M1.5 8h13M8 14.5v-13" })
59
+ className: ui.indicatorIcon()
60
+ }
66
61
  )
67
62
  ))),
68
63
  /* @__PURE__ */ React.createElement(UIAccordion.Panel, { "data-slot": "panel", className: ui.panel() }, /* @__PURE__ */ React.createElement("div", { "data-slot": "panel-content", className: ui.panelContent() }, content))
@@ -12,6 +12,6 @@ interface CheckboxProps extends Omit<UICheckbox.Root.Props, "className" | "child
12
12
  /** Optional supporting text. */
13
13
  description?: React.ReactNode;
14
14
  }
15
- declare function Checkbox({ className, label, description, size, indeterminate, ...props }: CheckboxProps): React.JSX.Element;
15
+ declare function Checkbox({ className, label, description, size, indeterminate, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: CheckboxProps): React.JSX.Element;
16
16
  export { Checkbox };
17
17
  export type { CheckboxProps };
@@ -2,37 +2,37 @@
2
2
  import { Checkbox as UICheckbox } from "@base-ui/react/checkbox";
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/checkbox.mjs";
6
- function CheckIcon({ indeterminate }) {
7
- return /* @__PURE__ */ React.createElement(
8
- "svg",
9
- {
10
- "aria-hidden": "true",
11
- "data-icon": indeterminate ? "dash" : "check",
12
- focusable: "false",
13
- viewBox: "0 0 16 16",
14
- fill: "none",
15
- stroke: "currentColor",
16
- strokeLinecap: "round",
17
- strokeLinejoin: "round",
18
- strokeWidth: "1.5"
19
- },
20
- /* @__PURE__ */ React.createElement("path", { d: indeterminate ? "M3.5 8h9" : "m2.5 8.5 4 4 7-9" })
21
- );
22
- }
7
+ import { CheckIcon } from "./icons/check.mjs";
8
+ import { DashIcon } from "./icons/dash.mjs";
23
9
  function Checkbox({
24
10
  className,
25
11
  label,
26
12
  description,
27
13
  size,
28
14
  indeterminate = false,
15
+ "aria-describedby": ariaDescribedBy,
16
+ "aria-label": ariaLabel,
17
+ "aria-labelledby": ariaLabelledBy,
29
18
  ...props
30
19
  }) {
31
20
  const ui = theme({ size });
21
+ const labelId = React.useId();
22
+ const descriptionId = React.useId();
23
+ const hasName = Boolean(label || ariaLabel || ariaLabelledBy);
24
+ const labelledBy = ariaLabelledBy || (label && !ariaLabel ? labelId : void 0);
25
+ const describedBy = mergeIds(
26
+ ariaDescribedBy,
27
+ description && hasName ? descriptionId : void 0
28
+ );
32
29
  return /* @__PURE__ */ React.createElement(
33
30
  UICheckbox.Root,
34
31
  {
35
32
  ...props,
33
+ "aria-describedby": describedBy,
34
+ "aria-label": ariaLabel,
35
+ "aria-labelledby": labelledBy,
36
36
  indeterminate,
37
37
  "data-slot": "root",
38
38
  className: cn(ui.root(), className)
@@ -52,9 +52,17 @@ function Checkbox({
52
52
  "data-slot": "indicator",
53
53
  className: ui.indicator()
54
54
  },
55
- /* @__PURE__ */ React.createElement("span", { "data-slot": "indicator-icon", className: ui.indicatorIcon() }, /* @__PURE__ */ React.createElement(CheckIcon, { indeterminate }))
55
+ /* @__PURE__ */ React.createElement("span", { "data-slot": "indicator-icon", className: ui.indicatorIcon() }, indeterminate ? /* @__PURE__ */ React.createElement(DashIcon, null) : /* @__PURE__ */ React.createElement(CheckIcon, null))
56
56
  )),
57
- label || description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "wrapper", className: ui.wrapper() }, label ? /* @__PURE__ */ React.createElement("span", { "data-slot": "label", className: ui.label() }, label) : null, description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "description", className: ui.description() }, description) : null) : null
57
+ label || description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "wrapper", className: ui.wrapper() }, label ? /* @__PURE__ */ React.createElement("span", { id: labelId, "data-slot": "label", className: ui.label() }, label) : null, description ? /* @__PURE__ */ React.createElement(
58
+ "span",
59
+ {
60
+ id: descriptionId,
61
+ "data-slot": "description",
62
+ className: ui.description()
63
+ },
64
+ description
65
+ ) : null) : null
58
66
  );
59
67
  }
60
68
  export { Checkbox };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function CheckIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { CheckIcon };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ function CheckIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ "aria-hidden": "true",
10
+ "data-icon": "check",
11
+ focusable: "false",
12
+ viewBox: "0 0 24 24",
13
+ fill: "none",
14
+ stroke: "currentColor",
15
+ strokeLinecap: "round",
16
+ strokeLinejoin: "round",
17
+ strokeWidth: "1.5",
18
+ className,
19
+ ...props
20
+ },
21
+ /* @__PURE__ */ React.createElement("path", { d: "m4 12 6 6 10-12" })
22
+ );
23
+ }
24
+ export { CheckIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function CloseIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { CloseIcon };
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ function CloseIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ "aria-hidden": "true",
10
+ viewBox: "0 0 24 24",
11
+ fill: "none",
12
+ stroke: "currentColor",
13
+ strokeWidth: "1.5",
14
+ strokeLinecap: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("path", { d: "m6 6 12 12M18 6 6 18" })
19
+ );
20
+ }
21
+ export { CloseIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function DashIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { DashIcon };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ function DashIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ "aria-hidden": "true",
10
+ "data-icon": "dash",
11
+ focusable: "false",
12
+ viewBox: "0 0 24 24",
13
+ fill: "none",
14
+ stroke: "currentColor",
15
+ strokeLinecap: "round",
16
+ strokeLinejoin: "round",
17
+ strokeWidth: "1.5",
18
+ className,
19
+ ...props
20
+ },
21
+ /* @__PURE__ */ React.createElement("path", { d: "M5 12h14" })
22
+ );
23
+ }
24
+ export { DashIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function ErrorIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { ErrorIcon };
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ function ErrorIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeWidth: "1.5",
13
+ strokeLinecap: "round",
14
+ strokeLinejoin: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "8.5" }),
19
+ /* @__PURE__ */ React.createElement("path", { d: "M12 8v5" }),
20
+ /* @__PURE__ */ React.createElement("path", { d: "M12 16.5h.01" })
21
+ );
22
+ }
23
+ export { ErrorIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function InfoIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { InfoIcon };
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ function InfoIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeWidth: "1.5",
13
+ strokeLinecap: "round",
14
+ strokeLinejoin: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "8.5" }),
19
+ /* @__PURE__ */ React.createElement("path", { d: "M12 11v5" }),
20
+ /* @__PURE__ */ React.createElement("path", { d: "M12 8h.01" })
21
+ );
22
+ }
23
+ export { InfoIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function LoadingIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { LoadingIcon };
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ function LoadingIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeWidth: "1.5",
13
+ strokeLinecap: "round",
14
+ strokeLinejoin: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "8", opacity: "0.25" }),
19
+ /* @__PURE__ */ React.createElement("path", { d: "M12 4a8 8 0 0 1 8 8" })
20
+ );
21
+ }
22
+ export { LoadingIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function PlusIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { PlusIcon };
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ function PlusIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ "aria-hidden": "true",
10
+ viewBox: "0 0 24 24",
11
+ fill: "none",
12
+ stroke: "currentColor",
13
+ strokeWidth: "1.5",
14
+ strokeLinecap: "square",
15
+ strokeLinejoin: "round",
16
+ className,
17
+ ...props
18
+ },
19
+ /* @__PURE__ */ React.createElement("path", { d: "M2.5 12h19M12 21.5v-19" })
20
+ );
21
+ }
22
+ export { PlusIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function SuccessIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { SuccessIcon };
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ function SuccessIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeWidth: "1.5",
13
+ strokeLinecap: "round",
14
+ strokeLinejoin: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("circle", { cx: "12", cy: "12", r: "8.5" }),
19
+ /* @__PURE__ */ React.createElement("path", { d: "m8 12.5 3 3 5.5-6" })
20
+ );
21
+ }
22
+ export { SuccessIcon };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function WarningIcon({ className, ...props }: React.ComponentProps<"svg">): React.JSX.Element;
3
+ export { WarningIcon };
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ function WarningIcon({
3
+ className,
4
+ ...props
5
+ }) {
6
+ return /* @__PURE__ */ React.createElement(
7
+ "svg",
8
+ {
9
+ viewBox: "0 0 24 24",
10
+ fill: "none",
11
+ stroke: "currentColor",
12
+ strokeWidth: "1.5",
13
+ strokeLinecap: "round",
14
+ strokeLinejoin: "round",
15
+ className,
16
+ ...props
17
+ },
18
+ /* @__PURE__ */ React.createElement("path", { d: "M12 4 21 20H3L12 4Z" }),
19
+ /* @__PURE__ */ React.createElement("path", { d: "M12 10v4" }),
20
+ /* @__PURE__ */ React.createElement("path", { d: "M12 17.5h.01" })
21
+ );
22
+ }
23
+ export { WarningIcon };
@@ -14,6 +14,6 @@ interface InputProps extends Omit<UIInput.Props, "className" | "children" | "siz
14
14
  /** Icon rendered after the input. */
15
15
  trailingIcon?: React.ReactNode;
16
16
  }
17
- declare function Input({ className, label, description, leadingIcon, trailingIcon, size, id, disabled, ...props }: InputProps): React.JSX.Element;
17
+ declare function Input({ className, label, description, leadingIcon, trailingIcon, size, id, disabled, "aria-describedby": ariaDescribedBy, ...props }: InputProps): React.JSX.Element;
18
18
  export { Input };
19
19
  export type { InputProps };
@@ -2,6 +2,7 @@
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,
@@ -12,11 +13,17 @@ function Input({
12
13
  size,
13
14
  id,
14
15
  disabled,
16
+ "aria-describedby": ariaDescribedBy,
15
17
  ...props
16
18
  }) {
17
19
  const ui = theme({ size });
18
20
  const generatedId = React.useId();
21
+ const descriptionId = React.useId();
19
22
  const inputId = id ?? generatedId;
23
+ const describedBy = mergeIds(
24
+ ariaDescribedBy,
25
+ description ? descriptionId : void 0
26
+ );
20
27
  return /* @__PURE__ */ React.createElement(
21
28
  "div",
22
29
  {
@@ -46,6 +53,7 @@ function Input({
46
53
  ...props,
47
54
  id: inputId,
48
55
  disabled,
56
+ "aria-describedby": describedBy,
49
57
  "data-slot": "input",
50
58
  className: ui.input()
51
59
  }
@@ -58,7 +66,15 @@ function Input({
58
66
  },
59
67
  trailingIcon
60
68
  ) : null),
61
- description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "description", className: ui.description() }, description) : null
69
+ description ? /* @__PURE__ */ React.createElement(
70
+ "span",
71
+ {
72
+ id: descriptionId,
73
+ "data-slot": "description",
74
+ className: ui.description()
75
+ },
76
+ description
77
+ ) : null
62
78
  );
63
79
  }
64
80
  export { Input };
@@ -1,12 +1,18 @@
1
1
  import { Slider as UISlider } from "@base-ui/react/slider";
2
+ import * as React from "react";
2
3
  type SliderProps<Value extends number | readonly number[] = number> = Omit<UISlider.Root.Props<Value>, "children" | "style" | "className"> & {
3
4
  /** Tailwind classes merged into the root. */
4
5
  className?: any;
6
+ /** Accessible name for the thumb at `index`. Useful for range sliders. */
7
+ getAriaLabel?: UISlider.Thumb.Props["getAriaLabel"];
8
+ /** Accessible value text for the thumb at `index`. */
9
+ getAriaValueText?: UISlider.Thumb.Props["getAriaValueText"];
5
10
  };
6
11
  /**
7
- * Sliders need an accessible name. Pass `aria-labelledby`; Base UI forwards it
8
- * from the root to every thumb.
12
+ * Sliders need an accessible name. Pass `aria-label` or `aria-labelledby`;
13
+ * both are forwarded from the root to every thumb. `aria-describedby` is also
14
+ * forwarded so supporting copy is announced with each thumb.
9
15
  */
10
- declare function Slider<Value extends number | readonly number[] = number>({ className, value, defaultValue, ...props }: SliderProps<Value>): import("react").JSX.Element;
16
+ declare function Slider<Value extends number | readonly number[] = number>({ className, 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
17
  export { Slider };
12
18
  export type { SliderProps };
@@ -1,20 +1,47 @@
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,
7
15
  value,
8
16
  defaultValue,
17
+ "aria-describedby": ariaDescribedBy,
18
+ "aria-errormessage": ariaErrorMessage,
19
+ "aria-invalid": ariaInvalid,
20
+ "aria-label": ariaLabel,
21
+ "aria-labelledby": ariaLabelledBy,
22
+ getAriaLabel,
23
+ getAriaValueText,
9
24
  ...props
10
25
  }) {
11
26
  const ui = theme();
27
+ const syncThumbAria = React.useCallback(
28
+ (input) => {
29
+ if (!input) {
30
+ return;
31
+ }
32
+ setAriaAttribute(input, "aria-invalid", ariaInvalid);
33
+ setAriaAttribute(input, "aria-errormessage", ariaErrorMessage);
34
+ },
35
+ [ariaErrorMessage, ariaInvalid]
36
+ );
12
37
  const values = value ?? defaultValue;
13
38
  const thumbCount = Array.isArray(values) ? Math.max(1, values.length) : 1;
14
39
  return /* @__PURE__ */ React.createElement(
15
40
  UISlider.Root,
16
41
  {
17
42
  ...props,
43
+ "aria-label": ariaLabel,
44
+ "aria-labelledby": ariaLabelledBy,
18
45
  value,
19
46
  defaultValue,
20
47
  "data-slot": "root",
@@ -31,6 +58,12 @@ function Slider({
31
58
  {
32
59
  key: index,
33
60
  index,
61
+ "aria-describedby": ariaDescribedBy,
62
+ "aria-label": ariaLabel,
63
+ "aria-labelledby": ariaLabelledBy,
64
+ getAriaLabel,
65
+ getAriaValueText,
66
+ inputRef: syncThumbAria,
34
67
  "data-slot": "thumb",
35
68
  className: ui.thumb()
36
69
  },
@@ -12,6 +12,6 @@ interface SwitchProps extends Omit<UISwitch.Root.Props, "className" | "children"
12
12
  /** Optional supporting text. */
13
13
  description?: React.ReactNode;
14
14
  }
15
- declare function Switch({ className, label, description, size, disabled, readOnly, onCheckedChange, ...props }: SwitchProps): React.JSX.Element;
15
+ declare function Switch({ className, label, description, size, disabled, readOnly, onCheckedChange, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: SwitchProps): React.JSX.Element;
16
16
  export { Switch };
17
17
  export type { SwitchProps };
@@ -2,6 +2,7 @@
2
2
  import { Switch as UISwitch } from "@base-ui/react/switch";
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/switch.mjs";
6
7
  function LiquidGlassFilter({ id }) {
7
8
  return /* @__PURE__ */ React.createElement("svg", { "aria-hidden": "true", focusable: "false", "data-layer": "filter" }, /* @__PURE__ */ React.createElement("defs", null, /* @__PURE__ */ React.createElement("filter", { id: `${id}-goo` }, /* @__PURE__ */ React.createElement(
@@ -53,10 +54,21 @@ function Switch({
53
54
  disabled,
54
55
  readOnly,
55
56
  onCheckedChange,
57
+ "aria-describedby": ariaDescribedBy,
58
+ "aria-label": ariaLabel,
59
+ "aria-labelledby": ariaLabelledBy,
56
60
  ...props
57
61
  }) {
58
62
  const ui = theme({ size });
59
63
  const filterId = React.useId();
64
+ const labelId = React.useId();
65
+ const descriptionId = React.useId();
66
+ const hasName = Boolean(label || ariaLabel || ariaLabelledBy);
67
+ const labelledBy = ariaLabelledBy || (label && !ariaLabel ? labelId : void 0);
68
+ const describedBy = mergeIds(
69
+ ariaDescribedBy,
70
+ description && hasName ? descriptionId : void 0
71
+ );
60
72
  const filterStyles = {
61
73
  "--ui-switch-goo-filter": `url("#${filterId}-goo")`,
62
74
  "--ui-switch-remove-black-filter": `url("#${filterId}-remove-black")`
@@ -80,6 +92,9 @@ function Switch({
80
92
  UISwitch.Root,
81
93
  {
82
94
  ...props,
95
+ "aria-describedby": describedBy,
96
+ "aria-label": ariaLabel,
97
+ "aria-labelledby": labelledBy,
83
98
  disabled,
84
99
  readOnly,
85
100
  "data-slot": "root",
@@ -109,7 +124,15 @@ function Switch({
109
124
  /* @__PURE__ */ React.createElement("span", { "data-layer": "cover" })
110
125
  )
111
126
  )),
112
- label || description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "wrapper", className: ui.wrapper() }, label ? /* @__PURE__ */ React.createElement("span", { "data-slot": "label", className: ui.label() }, label) : null, description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "description", className: ui.description() }, description) : null) : null
127
+ label || description ? /* @__PURE__ */ React.createElement("span", { "data-slot": "wrapper", className: ui.wrapper() }, label ? /* @__PURE__ */ React.createElement("span", { id: labelId, "data-slot": "label", className: ui.label() }, label) : null, description ? /* @__PURE__ */ React.createElement(
128
+ "span",
129
+ {
130
+ id: descriptionId,
131
+ "data-slot": "description",
132
+ className: ui.description()
133
+ },
134
+ description
135
+ ) : null) : null
113
136
  );
114
137
  }
115
138
  export { Switch };
@@ -1,19 +1,20 @@
1
1
  import { Toast as UIToast } from "@base-ui/react/toast";
2
2
  import * as React from "react";
3
- /** Corner or edge where the toast stack is anchored. */
4
- type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
3
+ /** Corner where the toast stack is anchored. */
4
+ type ToastPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
5
5
  interface ToastProviderProps extends Omit<UIToast.Provider.Props, "children"> {
6
6
  /** App content that can call `useToast`. */
7
7
  children?: React.ReactNode;
8
- /** Corner or edge where the toast stack is anchored. */
8
+ }
9
+ interface ToastProps extends Omit<UIToast.Root.Props, "children" | "className" | "swipeDirection" | "toast"> {
10
+ /** Corner where the toast stack is anchored. */
9
11
  position?: ToastPosition;
10
- /** Accessible label for the close button. */
11
- closeLabel?: string;
12
- /** Accessible label for the notification region. */
13
- viewportLabel?: string;
14
- /** Tailwind classes merged into the viewport. */
12
+ /** Content rendered in place of the default close button. */
13
+ close?: React.ReactNode;
14
+ /** Tailwind classes merged into each toast. */
15
15
  className?: string;
16
16
  }
17
- declare function ToastProvider({ children, position, closeLabel, viewportLabel, className, ...props }: ToastProviderProps): React.JSX.Element;
18
- export { ToastProvider };
19
- export type { ToastPosition, ToastProviderProps };
17
+ declare function ToastProvider({ children, ...props }: ToastProviderProps): React.JSX.Element;
18
+ declare function Toast({ position, close, className, ...props }: ToastProps): React.JSX.Element;
19
+ export { Toast, ToastProvider };
20
+ export type { ToastPosition, ToastProps, ToastProviderProps };
@@ -4,52 +4,31 @@ import { cn } from "cn";
4
4
  import * as React from "react";
5
5
  import { useToast } from "../composables/use-toast.mjs";
6
6
  import theme from "../theme/toast.mjs";
7
- function CloseIcon() {
8
- return /* @__PURE__ */ React.createElement(
9
- "svg",
10
- {
11
- "aria-hidden": "true",
12
- viewBox: "0 0 16 16",
13
- fill: "none",
14
- stroke: "currentColor",
15
- strokeWidth: "1.5",
16
- strokeLinecap: "round",
17
- className: "size-4"
18
- },
19
- /* @__PURE__ */ React.createElement("path", { d: "m4 4 8 8M12 4l-8 8" })
20
- );
21
- }
22
- function statusIconContent(type) {
23
- const svgProps = {
24
- viewBox: "0 0 20 20",
25
- fill: "none",
26
- stroke: "currentColor",
27
- strokeWidth: 1.5,
28
- strokeLinecap: "round",
29
- strokeLinejoin: "round",
30
- className: "size-full"
31
- };
32
- switch (type) {
33
- case "info":
34
- return /* @__PURE__ */ React.createElement("svg", { ...svgProps }, /* @__PURE__ */ React.createElement("circle", { cx: "10", cy: "10", r: "7.25" }), /* @__PURE__ */ React.createElement("path", { d: "M10 9.25v4" }), /* @__PURE__ */ React.createElement("path", { d: "M10 6.75h.01" }));
35
- case "success":
36
- return /* @__PURE__ */ React.createElement("svg", { ...svgProps }, /* @__PURE__ */ React.createElement("circle", { cx: "10", cy: "10", r: "7.25" }), /* @__PURE__ */ React.createElement("path", { d: "m6.75 10.25 2.1 2.1 4.4-4.7" }));
37
- case "warning":
38
- return /* @__PURE__ */ React.createElement("svg", { ...svgProps }, /* @__PURE__ */ React.createElement("path", { d: "M10 3.25 17 16.5H3L10 3.25Z" }), /* @__PURE__ */ React.createElement("path", { d: "M10 8v3.5" }), /* @__PURE__ */ React.createElement("path", { d: "M10 14.25h.01" }));
39
- case "error":
40
- return /* @__PURE__ */ React.createElement("svg", { ...svgProps }, /* @__PURE__ */ React.createElement("circle", { cx: "10", cy: "10", r: "7.25" }), /* @__PURE__ */ React.createElement("path", { d: "M10 6.5v4.25" }), /* @__PURE__ */ React.createElement("path", { d: "M10 13.75h.01" }));
41
- case "loading":
42
- return /* @__PURE__ */ React.createElement("svg", { ...svgProps }, /* @__PURE__ */ React.createElement("circle", { cx: "10", cy: "10", r: "6.75", opacity: "0.25" }), /* @__PURE__ */ React.createElement("path", { d: "M10 3.25a6.75 6.75 0 0 1 6.75 6.75" }));
43
- default:
44
- return null;
45
- }
46
- }
7
+ import { CloseIcon } from "./icons/close.mjs";
8
+ import { ErrorIcon } from "./icons/error.mjs";
9
+ import { InfoIcon } from "./icons/info.mjs";
10
+ import { LoadingIcon } from "./icons/loading.mjs";
11
+ import { SuccessIcon } from "./icons/success.mjs";
12
+ import { WarningIcon } from "./icons/warning.mjs";
13
+ const SWIPE_DIRECTIONS = {
14
+ "top-left": ["up", "left"],
15
+ "top-right": ["up", "right"],
16
+ "bottom-left": ["down", "left"],
17
+ "bottom-right": ["down", "right"]
18
+ };
19
+ const STATUS_ICONS = {
20
+ info: InfoIcon,
21
+ success: SuccessIcon,
22
+ warning: WarningIcon,
23
+ error: ErrorIcon,
24
+ loading: LoadingIcon
25
+ };
47
26
  function ToastStatusIcon({
48
27
  type,
49
28
  className
50
29
  }) {
51
- const content = statusIconContent(type);
52
- if (!content) {
30
+ const Icon = type ? STATUS_ICONS[type] : void 0;
31
+ if (!Icon) {
53
32
  return null;
54
33
  }
55
34
  return /* @__PURE__ */ React.createElement(
@@ -60,61 +39,53 @@ function ToastStatusIcon({
60
39
  "data-icon": type,
61
40
  className
62
41
  },
63
- content
42
+ /* @__PURE__ */ React.createElement(Icon, { className: "size-full" })
64
43
  );
65
44
  }
66
- function ToastList({
67
- placement,
68
- closeLabel
69
- }) {
70
- const { toasts } = useToast();
71
- const ui = theme({ placement });
72
- return toasts.map((toast) => /* @__PURE__ */ React.createElement(
73
- UIToast.Root,
74
- {
75
- key: toast.id,
76
- toast,
77
- "data-slot": "toast",
78
- className: ui.root(),
79
- swipeDirection: placement === "top" ? "up" : "down"
80
- },
81
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "overlay", className: ui.overlay() })),
82
- /* @__PURE__ */ React.createElement(UIToast.Content, { "data-slot": "content", className: ui.content() }, /* @__PURE__ */ React.createElement(ToastStatusIcon, { type: toast.type, className: ui.icon() }), /* @__PURE__ */ React.createElement("div", { "data-slot": "text", className: ui.text() }, /* @__PURE__ */ React.createElement(UIToast.Title, { "data-slot": "title", className: ui.title() }), /* @__PURE__ */ React.createElement(
83
- UIToast.Description,
84
- {
85
- "data-slot": "description",
86
- className: ui.description()
87
- }
88
- )), /* @__PURE__ */ React.createElement("div", { "data-slot": "actions", className: ui.actions() }, /* @__PURE__ */ React.createElement(UIToast.Action, { "data-slot": "action", className: ui.action() }), /* @__PURE__ */ React.createElement(
89
- UIToast.Close,
90
- {
91
- "data-slot": "close",
92
- className: ui.close(),
93
- "aria-label": closeLabel
94
- },
95
- /* @__PURE__ */ React.createElement(CloseIcon, null)
96
- )))
97
- ));
45
+ function ToastProvider({ children, ...props }) {
46
+ return /* @__PURE__ */ React.createElement(UIToast.Provider, { ...props }, children);
98
47
  }
99
- function ToastProvider({
100
- children,
48
+ function Toast({
101
49
  position = "bottom-right",
102
- closeLabel = "Dismiss",
103
- viewportLabel = "Notifications",
50
+ close,
104
51
  className,
105
52
  ...props
106
53
  }) {
107
- const [placement, align] = position.split("-");
108
- const ui = theme({ placement, align });
109
- return /* @__PURE__ */ React.createElement(UIToast.Provider, { ...props }, children, /* @__PURE__ */ React.createElement(UIToast.Portal, null, /* @__PURE__ */ React.createElement(
54
+ const { toasts } = useToast();
55
+ const ui = theme({ position });
56
+ return /* @__PURE__ */ React.createElement(UIToast.Portal, null, /* @__PURE__ */ React.createElement(
110
57
  UIToast.Viewport,
111
58
  {
112
59
  "data-slot": "viewport",
113
60
  "data-position": position,
114
- "aria-label": viewportLabel,
115
- className: cn(ui.viewport(), className)
61
+ className: ui.viewport()
116
62
  },
117
- /* @__PURE__ */ React.createElement(ToastList, { placement, closeLabel })
118
- )));
63
+ toasts.map((toast) => /* @__PURE__ */ React.createElement(
64
+ UIToast.Root,
65
+ {
66
+ ...props,
67
+ key: toast.id,
68
+ toast,
69
+ "data-slot": "toast",
70
+ className: cn(ui.root(), className),
71
+ swipeDirection: SWIPE_DIRECTIONS[position]
72
+ },
73
+ /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
74
+ "span",
75
+ {
76
+ "aria-hidden": "true",
77
+ "data-slot": "overlay",
78
+ className: ui.overlay()
79
+ }
80
+ )),
81
+ /* @__PURE__ */ React.createElement(UIToast.Content, { "data-slot": "content", className: ui.content() }, /* @__PURE__ */ React.createElement(ToastStatusIcon, { type: toast.type, className: ui.icon() }), /* @__PURE__ */ React.createElement("div", { "data-slot": "text", className: ui.text() }, /* @__PURE__ */ React.createElement(UIToast.Title, { "data-slot": "title", className: ui.title() }), /* @__PURE__ */ React.createElement(
82
+ UIToast.Description,
83
+ {
84
+ "data-slot": "description",
85
+ className: ui.description()
86
+ }
87
+ )), /* @__PURE__ */ React.createElement("div", { "data-slot": "actions", className: ui.actions() }, /* @__PURE__ */ React.createElement(UIToast.Action, { "data-slot": "action", className: ui.action() }), close ? close : /* @__PURE__ */ React.createElement(UIToast.Close, { "data-slot": "close", className: ui.close() }, /* @__PURE__ */ React.createElement(CloseIcon, { className: "size-4" }))))
88
+ ))
89
+ ));
119
90
  }
120
- export { ToastProvider };
91
+ export { Toast, ToastProvider };
package/dist/index.d.ts CHANGED
@@ -10,7 +10,7 @@ export { Popover, type PopoverProps } from "./components/popover";
10
10
  export { ScrollArea, type ScrollAreaOrientation, type ScrollAreaProps, } from "./components/scroll-area";
11
11
  export { Slider, type SliderProps } from "./components/slider";
12
12
  export { Switch, type SwitchProps } from "./components/switch";
13
- export { ToastProvider, type ToastPosition, type ToastProviderProps, } from "./components/toast";
13
+ export { Toast, ToastProvider, type ToastPosition, type ToastProps, type ToastProviderProps, } from "./components/toast";
14
14
  export { createToastManager } from "./composables/create-toast-manager";
15
15
  export { useToast, type ToastManager, type ToastManagerAddOptions, type ToastManagerPromiseOptions, type ToastManagerUpdateOptions, type ToastObject, } from "./composables/use-toast";
16
16
  export { Toggle, type ToggleProps } from "./components/toggle";
package/dist/index.mjs CHANGED
@@ -15,6 +15,7 @@ export {
15
15
  export { Slider } from "./components/slider.mjs";
16
16
  export { Switch } from "./components/switch.mjs";
17
17
  export {
18
+ Toast,
18
19
  ToastProvider
19
20
  } from "./components/toast.mjs";
20
21
  export { createToastManager } from "./composables/create-toast-manager.mjs";
@@ -0,0 +1,3 @@
1
+ /** Join space-separated ID references, dropping empty values. */
2
+ declare function mergeIds(...ids: Array<string | null | undefined>): string | undefined;
3
+ export { mergeIds };
@@ -0,0 +1,5 @@
1
+ function mergeIds(...ids) {
2
+ const merged = ids.filter((id) => Boolean(id)).join(" ").trim();
3
+ return merged || void 0;
4
+ }
5
+ export { mergeIds };
@@ -1,22 +1,15 @@
1
1
  declare const _default: import("tailwind-variants").TVReturnType<{
2
- placement: {
3
- top: {
2
+ position: {
3
+ "top-left": {
4
4
  viewport: string;
5
- root: string[];
6
5
  };
7
- bottom: {
6
+ "top-right": {
8
7
  viewport: string;
9
- root: string[];
10
8
  };
11
- };
12
- align: {
13
- left: {
14
- viewport: string;
15
- };
16
- center: {
9
+ "bottom-left": {
17
10
  viewport: string;
18
11
  };
19
- right: {
12
+ "bottom-right": {
20
13
  viewport: string;
21
14
  };
22
15
  };
@@ -34,24 +27,17 @@ declare const _default: import("tailwind-variants").TVReturnType<{
34
27
  action: string[];
35
28
  close: string[];
36
29
  }, undefined, {
37
- placement: {
38
- top: {
30
+ position: {
31
+ "top-left": {
39
32
  viewport: string;
40
- root: string[];
41
33
  };
42
- bottom: {
34
+ "top-right": {
43
35
  viewport: string;
44
- root: string[];
45
36
  };
46
- };
47
- align: {
48
- left: {
37
+ "bottom-left": {
49
38
  viewport: string;
50
39
  };
51
- center: {
52
- viewport: string;
53
- };
54
- right: {
40
+ "bottom-right": {
55
41
  viewport: string;
56
42
  };
57
43
  };
@@ -69,24 +55,17 @@ declare const _default: import("tailwind-variants").TVReturnType<{
69
55
  action: string[];
70
56
  close: string[];
71
57
  }, import("tailwind-variants").TVReturnTypeLike<{
72
- placement: {
73
- top: {
74
- viewport: string;
75
- root: string[];
76
- };
77
- bottom: {
58
+ position: {
59
+ "top-left": {
78
60
  viewport: string;
79
- root: string[];
80
61
  };
81
- };
82
- align: {
83
- left: {
62
+ "top-right": {
84
63
  viewport: string;
85
64
  };
86
- center: {
65
+ "bottom-left": {
87
66
  viewport: string;
88
67
  };
89
- right: {
68
+ "bottom-right": {
90
69
  viewport: string;
91
70
  };
92
71
  };
@@ -14,6 +14,8 @@ export default tv({
14
14
  "data-[expanded]:h-[var(--toast-height)]",
15
15
  "data-[limited]:pointer-events-none data-[limited]:opacity-0",
16
16
  "data-[swiping]:cursor-grabbing",
17
+ "data-[ending-style]:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)_-_150%))]",
18
+ "data-[ending-style]:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)_+_150%))]",
17
19
  "outline-none focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-ui-glass-focus",
18
20
  "motion-reduce:transition-none"
19
21
  ],
@@ -57,9 +59,25 @@ export default tv({
57
59
  ]
58
60
  },
59
61
  variants: {
60
- placement: {
61
- top: {
62
- viewport: "top-[max(1rem,env(safe-area-inset-top))] bottom-auto",
62
+ position: {
63
+ "top-left": {
64
+ viewport: "top-[max(1rem,env(safe-area-inset-top))] bottom-auto left-[max(1rem,env(safe-area-inset-left))] right-auto"
65
+ },
66
+ "top-right": {
67
+ viewport: "top-[max(1rem,env(safe-area-inset-top))] bottom-auto right-[max(1rem,env(safe-area-inset-right))] left-auto"
68
+ },
69
+ "bottom-left": {
70
+ viewport: "bottom-[max(1rem,env(safe-area-inset-bottom))] top-auto left-[max(1rem,env(safe-area-inset-left))] right-auto"
71
+ },
72
+ "bottom-right": {
73
+ viewport: "bottom-[max(1rem,env(safe-area-inset-bottom))] top-auto right-[max(1rem,env(safe-area-inset-right))] left-auto"
74
+ }
75
+ }
76
+ },
77
+ compoundVariants: [
78
+ {
79
+ position: ["top-left", "top-right"],
80
+ class: {
63
81
  root: [
64
82
  "top-0 origin-top",
65
83
  "[--offset-y:calc(var(--toast-offset-y)_+_(var(--toast-index)*var(--gap))_+_var(--toast-swipe-movement-y))]",
@@ -70,9 +88,11 @@ export default tv({
70
88
  "data-[ending-style]:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)_-_150%))]",
71
89
  "after:absolute after:bottom-full after:left-0 after:h-[calc(var(--gap)_+_1px)] after:w-full after:content-['']"
72
90
  ]
73
- },
74
- bottom: {
75
- viewport: "bottom-[max(1rem,env(safe-area-inset-bottom))] top-auto",
91
+ }
92
+ },
93
+ {
94
+ position: ["bottom-left", "bottom-right"],
95
+ class: {
76
96
  root: [
77
97
  "bottom-0 origin-bottom",
78
98
  "[--offset-y:calc(var(--toast-offset-y)*-1_+_(var(--toast-index)*var(--gap)*-1)_+_var(--toast-swipe-movement-y))]",
@@ -84,21 +104,9 @@ export default tv({
84
104
  "after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)_+_1px)] after:w-full after:content-['']"
85
105
  ]
86
106
  }
87
- },
88
- align: {
89
- left: {
90
- viewport: "left-[max(1rem,env(safe-area-inset-left))] right-auto"
91
- },
92
- center: {
93
- viewport: "left-1/2 -translate-x-1/2"
94
- },
95
- right: {
96
- viewport: "right-[max(1rem,env(safe-area-inset-right))] left-auto"
97
- }
98
107
  }
99
- },
108
+ ],
100
109
  defaultVariants: {
101
- placement: "bottom",
102
- align: "right"
110
+ position: "bottom-right"
103
111
  }
104
112
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xingxingmofashu/ui",
3
- "version": "0.1.1",
4
- "description": "Liquid Glass UI components for React 19 and Tailwind CSS 4.",
3
+ "version": "0.1.2",
4
+ "description": "Accessible React components with a Liquid Glass visual style for React 19 and Tailwind CSS 4.",
5
5
  "license": "MIT",
6
6
  "author": "xingxingmofashu",
7
7
  "type": "module",