@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
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,25 +12,43 @@
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),
11
- [Tailwind CSS](https://tailwindcss.com), and
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 with
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.
14
22
 
15
- The package ships fifteen components: Accordion, Alert Dialog, Button, Card,
16
- Checkbox, Dialog, Drawer, Input, Popover, Scroll Area, Slider, Switch, Toast,
17
- Toggle, and Toggle Group.
23
+ The package ships sixteen components: Accordion, Alert Dialog, Button, Card,
24
+ Checkbox, Dialog, Drawer, Input, Popover, Progress, Scroll Area, Slider, Switch,
25
+ Toast, Toggle, and Toggle Group.
18
26
 
19
27
  > [!NOTE]
20
28
  > Requires React 19, React DOM 19, Tailwind CSS 4, Node.js 22+, and an
21
29
  > ESM-capable bundler. `Card` is server-safe; the interactive components are
22
30
  > client components.
23
31
 
32
+ ## Preview
33
+
34
+ <picture>
35
+ <source media="(prefers-color-scheme: dark)" srcset=".github/assets/playground-dark.png">
36
+ <source media="(prefers-color-scheme: light)" srcset=".github/assets/playground-light.png">
37
+ <img alt="The Liquid Glass playground showing live component previews in light mode." width="1440" src=".github/assets/playground-light.png">
38
+ </picture>
39
+
40
+ Every component is rendered live in the local playground. Run
41
+ `pnpm playground:dev`, open <http://localhost:3002>, and switch between light and
42
+ dark to compare the same previews in both themes.
43
+
24
44
  ## Documentation
25
45
 
26
- - [English documentation](https://xingxingmofashu.github.io/ui/docs/en/get-started)
27
- - [简体中文文档](https://xingxingmofashu.github.io/ui/docs/zh/get-started)
46
+ - [English](https://xingxingmofashu.github.io/ui/docs/en/get-started/introduction)
47
+ - [简体中文](https://xingxingmofashu.github.io/ui/docs/zh/get-started/introduction)
48
+ - [llms.txt](https://xingxingmofashu.github.io/ui/llms.txt) — a compact index for
49
+ language models and agents
50
+ - [llms-full.txt](https://xingxingmofashu.github.io/ui/llms-full.txt) — every
51
+ guide and component page in one file
28
52
 
29
53
  ## Installation
30
54
 
@@ -115,9 +139,12 @@ Light and dark tokens are selected by `.light` / `.dark`, or by
115
139
 
116
140
  ```html
117
141
  <html class="dark">
118
- <!-- or -->
119
- <html data-theme="dark">
120
- </html>
142
+ ```
143
+
144
+ or:
145
+
146
+ ```html
147
+ <html data-theme="dark">
121
148
  ```
122
149
 
123
150
  A nested `.light` / `[data-theme="light"]` subtree can switch back to light
@@ -158,10 +185,8 @@ a reproduction. Before opening a pull request, run `pnpm lint`, `pnpm test`, and
158
185
 
159
186
  ## Credits
160
187
 
161
- - [Base UI](https://base-ui.com)
162
188
  - [Tailwind CSS](https://tailwindcss.com)
163
189
  - [Tailwind Variants](https://www.tailwind-variants.org)
164
- - [cn](https://github.com/shadcn-ui/cn)
165
190
 
166
191
  ## License
167
192
 
@@ -1,28 +1,32 @@
1
1
  import { Accordion as UIAccordion } from "@base-ui/react/accordion";
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/accordion";
6
+ type Accordion = ComponentConfig<typeof theme>;
5
7
  /** One panel managed by the accordion. */
6
- type AccordionItemProps = {
8
+ type AccordionItemProps<Value extends string = string> = Omit<UIAccordion.Item.Props, "children" | "className" | "style" | "title" | "value"> & {
7
9
  /** Value that identifies the item in the accordion value. */
8
- value: string;
10
+ value: Value;
9
11
  /** Visible heading inside the trigger. */
10
12
  title: React.ReactNode;
11
13
  /** Panel content. */
12
14
  content?: React.ReactNode;
13
- /** Disables this item. */
14
- disabled?: boolean;
15
- /** Called when this panel opens or closes. */
16
- onOpenChange?: UIAccordion.Item.Props["onOpenChange"];
15
+ /** Replaces the default plus icon. Set to `false` to hide the indicator. */
16
+ indicator?: React.ReactNode | false;
17
17
  /** Tailwind classes merged into the item root. */
18
- className?: any;
18
+ className?: string;
19
+ /** Tailwind classes for this item's internal slots, keyed by `data-slot`. */
20
+ ui?: Partial<Pick<Accordion["slots"], "item" | "header" | "trigger" | "title" | "indicator" | "indicatorIcon" | "panel" | "panelContent">>;
19
21
  };
20
22
  type AccordionProps<Value extends string = string> = Omit<UIAccordion.Root.Props<Value>, "className" | "style" | "children"> & VariantProps<typeof theme> & {
21
23
  /** Panels rendered by the accordion. */
22
- items: readonly AccordionItemProps[];
24
+ items: readonly AccordionItemProps<Value>[];
23
25
  /** Tailwind classes merged into the root. */
24
- className?: any;
26
+ className?: string;
27
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
28
+ ui?: Accordion["slots"];
25
29
  };
26
- declare function Accordion<Value extends string = string>({ className, size, items, ...props }: AccordionProps<Value>): React.JSX.Element;
30
+ declare function Accordion<Value extends string = string>({ className, ui, size, items, ...props }: AccordionProps<Value>): React.JSX.Element;
27
31
  export { Accordion };
28
32
  export type { AccordionItemProps, AccordionProps };
@@ -3,29 +3,55 @@ 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,
9
+ ui,
8
10
  size,
9
11
  items,
10
12
  ...props
11
13
  }) {
12
- const ui = theme({ size });
14
+ const styles = theme({ size });
13
15
  return /* @__PURE__ */ React.createElement(
14
16
  UIAccordion.Root,
15
17
  {
16
18
  ...props,
17
19
  "data-slot": "root",
18
- className: cn(ui.root(), className)
20
+ className: cn(styles.root(), ui?.root, className)
19
21
  },
20
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
22
+ /* @__PURE__ */ React.createElement(
21
23
  "span",
22
24
  {
23
25
  "aria-hidden": "true",
24
- "data-slot": "overlay",
25
- className: ui.overlay()
26
+ "data-slot": "glass",
27
+ className: cn(styles.glass(), ui?.glass)
28
+ },
29
+ /* @__PURE__ */ React.createElement(
30
+ "span",
31
+ {
32
+ "aria-hidden": "true",
33
+ "data-slot": "overlay",
34
+ className: cn(styles.overlay(), ui?.overlay)
35
+ }
36
+ )
37
+ ),
38
+ /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: cn(styles.content(), ui?.content) }, items.map((item) => /* @__PURE__ */ React.createElement(
39
+ AccordionItem,
40
+ {
41
+ key: item.value,
42
+ ...item,
43
+ ui: {
44
+ item: cn(ui?.item, item.ui?.item),
45
+ header: cn(ui?.header, item.ui?.header),
46
+ trigger: cn(ui?.trigger, item.ui?.trigger),
47
+ title: cn(ui?.title, item.ui?.title),
48
+ indicator: cn(ui?.indicator, item.ui?.indicator),
49
+ indicatorIcon: cn(ui?.indicatorIcon, item.ui?.indicatorIcon),
50
+ panel: cn(ui?.panel, item.ui?.panel),
51
+ panelContent: cn(ui?.panelContent, item.ui?.panelContent)
52
+ }
26
53
  }
27
- )),
28
- /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: ui.content() }, items.map((item) => /* @__PURE__ */ React.createElement(AccordionItem, { key: item.value, ...item })))
54
+ )))
29
55
  );
30
56
  }
31
57
  function AccordionItem({
@@ -33,39 +59,66 @@ function AccordionItem({
33
59
  title,
34
60
  content,
35
61
  className,
62
+ ui,
63
+ indicator,
64
+ ref,
36
65
  ...props
37
66
  }) {
38
- const ui = theme();
67
+ const styles = theme();
39
68
  return /* @__PURE__ */ React.createElement(
40
69
  UIAccordion.Item,
41
70
  {
42
71
  ...props,
72
+ ref,
43
73
  value,
44
74
  "data-slot": "item",
45
- className: cn(ui.item(), className)
75
+ className: cn(styles.item(), ui?.item, className)
46
76
  },
47
- /* @__PURE__ */ React.createElement(UIAccordion.Header, { "data-slot": "header", className: ui.header() }, /* @__PURE__ */ React.createElement(UIAccordion.Trigger, { "data-slot": "trigger", className: ui.trigger() }, /* @__PURE__ */ React.createElement("span", { "data-slot": "title", className: ui.title() }, title), /* @__PURE__ */ React.createElement(
48
- "span",
77
+ /* @__PURE__ */ React.createElement(
78
+ UIAccordion.Header,
49
79
  {
50
- "aria-hidden": "true",
51
- "data-slot": "indicator",
52
- className: ui.indicator()
80
+ "data-slot": "header",
81
+ className: cn(styles.header(), ui?.header)
82
+ },
83
+ /* @__PURE__ */ React.createElement(
84
+ UIAccordion.Trigger,
85
+ {
86
+ "data-slot": "trigger",
87
+ className: cn(styles.trigger(), ui?.trigger)
88
+ },
89
+ /* @__PURE__ */ React.createElement("span", { "data-slot": "title", className: cn(styles.title(), ui?.title) }, title),
90
+ indicator === false ? null : /* @__PURE__ */ React.createElement(
91
+ "span",
92
+ {
93
+ "aria-hidden": "true",
94
+ "data-slot": "indicator",
95
+ className: cn(styles.indicator(), ui?.indicator)
96
+ },
97
+ indicator === void 0 ? /* @__PURE__ */ React.createElement(
98
+ PlusIcon,
99
+ {
100
+ "data-slot": "indicator-icon",
101
+ className: cn(styles.indicatorIcon(), ui?.indicatorIcon)
102
+ }
103
+ ) : indicator
104
+ )
105
+ )
106
+ ),
107
+ /* @__PURE__ */ React.createElement(
108
+ UIAccordion.Panel,
109
+ {
110
+ "data-slot": "panel",
111
+ className: cn(styles.panel(), ui?.panel)
53
112
  },
54
113
  /* @__PURE__ */ React.createElement(
55
- "svg",
114
+ "div",
56
115
  {
57
- "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"
116
+ "data-slot": "panel-content",
117
+ className: cn(styles.panelContent(), ui?.panelContent)
64
118
  },
65
- /* @__PURE__ */ React.createElement("path", { d: "M1.5 8h13M8 14.5v-13" })
119
+ content
66
120
  )
67
- ))),
68
- /* @__PURE__ */ React.createElement(UIAccordion.Panel, { "data-slot": "panel", className: ui.panel() }, /* @__PURE__ */ React.createElement("div", { "data-slot": "panel-content", className: ui.panelContent() }, content))
121
+ )
69
122
  );
70
123
  }
71
124
  export { Accordion };
@@ -1,5 +1,8 @@
1
1
  import { AlertDialog as UIAlertDialog } from "@base-ui/react/alert-dialog";
2
2
  import * as React from "react";
3
+ import { type ComponentConfig } from "../internal/tv";
4
+ import theme from "../theme/alert-dialog";
5
+ type AlertDialog = ComponentConfig<typeof theme>;
3
6
  type AlertDialogProps = Omit<UIAlertDialog.Root.Props, "children"> & {
4
7
  /** Dialog heading. */
5
8
  title: React.ReactNode;
@@ -16,8 +19,10 @@ type AlertDialogProps = Omit<UIAlertDialog.Root.Props, "children"> & {
16
19
  /** Called when the confirm button is pressed. */
17
20
  onConfirm?: React.MouseEventHandler<HTMLButtonElement>;
18
21
  /** Tailwind classes merged into the popup. */
19
- className?: any;
22
+ className?: string;
23
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
24
+ ui?: AlertDialog["slots"];
20
25
  };
21
- declare function AlertDialog({ title, description, children, cancelLabel, confirmLabel, onCancel, onConfirm, className, ...props }: AlertDialogProps): React.JSX.Element;
26
+ declare function AlertDialog({ title, description, children, cancelLabel, confirmLabel, onCancel, onConfirm, className, ui, ...props }: AlertDialogProps): React.JSX.Element;
22
27
  export { AlertDialog };
23
28
  export type { AlertDialogProps };
@@ -13,49 +13,90 @@ function AlertDialog({
13
13
  onCancel,
14
14
  onConfirm,
15
15
  className,
16
+ ui,
16
17
  ...props
17
18
  }) {
18
- const ui = theme();
19
+ const styles = theme();
19
20
  return /* @__PURE__ */ React.createElement(UIAlertDialog.Root, { ...props }, /* @__PURE__ */ React.createElement(UIAlertDialog.Portal, null, /* @__PURE__ */ React.createElement(
20
21
  UIAlertDialog.Backdrop,
21
22
  {
22
23
  "data-slot": "backdrop",
23
- className: ui.backdrop()
24
+ className: cn(styles.backdrop(), ui?.backdrop)
24
25
  }
25
- ), /* @__PURE__ */ React.createElement(UIAlertDialog.Viewport, { "data-slot": "viewport", className: ui.viewport() }, /* @__PURE__ */ React.createElement(
26
- UIAlertDialog.Popup,
26
+ ), /* @__PURE__ */ React.createElement(
27
+ UIAlertDialog.Viewport,
27
28
  {
28
- "data-slot": "popup",
29
- className: cn(ui.popup(), className)
29
+ "data-slot": "viewport",
30
+ className: cn(styles.viewport(), ui?.viewport)
30
31
  },
31
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", "data-slot": "glass", className: ui.glass() }, /* @__PURE__ */ React.createElement(
32
- "span",
32
+ /* @__PURE__ */ React.createElement(
33
+ UIAlertDialog.Popup,
33
34
  {
34
- "aria-hidden": "true",
35
- "data-slot": "overlay",
36
- className: ui.overlay()
37
- }
38
- )),
39
- /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: ui.content() }, /* @__PURE__ */ React.createElement(UIAlertDialog.Title, { "data-slot": "title", className: ui.title() }, title), description ? /* @__PURE__ */ React.createElement(
40
- UIAlertDialog.Description,
41
- {
42
- "data-slot": "description",
43
- className: ui.description()
35
+ "data-slot": "popup",
36
+ className: cn(styles.popup(), ui?.popup, className)
44
37
  },
45
- description
46
- ) : null, children ? /* @__PURE__ */ React.createElement("div", { "data-slot": "body", className: ui.body() }, children) : null, /* @__PURE__ */ React.createElement("div", { "data-slot": "footer", className: ui.footer() }, /* @__PURE__ */ React.createElement(
47
- UIAlertDialog.Close,
48
- {
49
- onClick: onCancel,
50
- render: /* @__PURE__ */ React.createElement(Button, { label: cancelLabel })
51
- }
52
- ), /* @__PURE__ */ React.createElement(
53
- UIAlertDialog.Close,
54
- {
55
- onClick: onConfirm,
56
- render: /* @__PURE__ */ React.createElement(Button, { label: confirmLabel })
57
- }
58
- )))
59
- ))));
38
+ /* @__PURE__ */ React.createElement(
39
+ "span",
40
+ {
41
+ "aria-hidden": "true",
42
+ "data-slot": "glass",
43
+ className: cn(styles.glass(), ui?.glass)
44
+ },
45
+ /* @__PURE__ */ React.createElement(
46
+ "span",
47
+ {
48
+ "aria-hidden": "true",
49
+ "data-slot": "overlay",
50
+ className: cn(styles.overlay(), ui?.overlay)
51
+ }
52
+ )
53
+ ),
54
+ /* @__PURE__ */ React.createElement(
55
+ "div",
56
+ {
57
+ "data-slot": "content",
58
+ className: cn(styles.content(), ui?.content)
59
+ },
60
+ /* @__PURE__ */ React.createElement(
61
+ UIAlertDialog.Title,
62
+ {
63
+ "data-slot": "title",
64
+ className: cn(styles.title(), ui?.title)
65
+ },
66
+ title
67
+ ),
68
+ description ? /* @__PURE__ */ React.createElement(
69
+ UIAlertDialog.Description,
70
+ {
71
+ "data-slot": "description",
72
+ className: cn(styles.description(), ui?.description)
73
+ },
74
+ description
75
+ ) : null,
76
+ children ? /* @__PURE__ */ React.createElement("div", { "data-slot": "body", className: cn(styles.body(), ui?.body) }, children) : null,
77
+ /* @__PURE__ */ React.createElement(
78
+ "div",
79
+ {
80
+ "data-slot": "footer",
81
+ className: cn(styles.footer(), ui?.footer)
82
+ },
83
+ /* @__PURE__ */ React.createElement(
84
+ UIAlertDialog.Close,
85
+ {
86
+ onClick: onCancel,
87
+ render: /* @__PURE__ */ React.createElement(Button, { label: cancelLabel })
88
+ }
89
+ ),
90
+ /* @__PURE__ */ React.createElement(
91
+ UIAlertDialog.Close,
92
+ {
93
+ onClick: onConfirm,
94
+ render: /* @__PURE__ */ React.createElement(Button, { label: confirmLabel })
95
+ }
96
+ )
97
+ )
98
+ )
99
+ )
100
+ )));
60
101
  }
61
102
  export { AlertDialog };
@@ -1,12 +1,16 @@
1
1
  import { type ButtonProps as UIButtonProps } from "@base-ui/react/button";
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/button";
6
+ type Button = ComponentConfig<typeof theme>;
5
7
  interface ButtonProps extends Omit<UIButtonProps, "ref" | "style" | "className">, VariantProps<typeof theme> {
6
8
  /** Ref to the rendered root element. */
7
9
  ref?: React.Ref<HTMLElement>;
8
10
  /** Tailwind classes merged into the outer click area. */
9
- className?: any;
11
+ className?: string;
12
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
13
+ ui?: Button["slots"];
10
14
  /** Text or content rendered inside the button. */
11
15
  label?: React.ReactNode;
12
16
  /** Icon rendered before the label. */
@@ -14,6 +18,6 @@ interface ButtonProps extends Omit<UIButtonProps, "ref" | "style" | "className">
14
18
  /** Icon rendered after the label. */
15
19
  trailingIcon?: React.ReactNode;
16
20
  }
17
- declare function Button({ className, children, label, leadingIcon, trailingIcon, size, ...props }: ButtonProps): React.JSX.Element;
21
+ declare function Button({ className, ui, children, label, leadingIcon, trailingIcon, size, ...props }: ButtonProps): React.JSX.Element;
18
22
  export { Button };
19
23
  export type { ButtonProps };
@@ -7,6 +7,7 @@ import * as React from "react";
7
7
  import theme from "../theme/button.mjs";
8
8
  function Button({
9
9
  className,
10
+ ui,
10
11
  children,
11
12
  label,
12
13
  leadingIcon,
@@ -14,34 +15,42 @@ function Button({
14
15
  size,
15
16
  ...props
16
17
  }) {
17
- const ui = theme({ size });
18
+ const styles = theme({ size });
18
19
  return /* @__PURE__ */ React.createElement(
19
20
  UIButton,
20
21
  {
21
22
  "data-slot": "root",
22
- className: cn(ui.root(), className),
23
+ className: cn(styles.root(), ui?.root, className),
23
24
  ...props
24
25
  },
25
- /* @__PURE__ */ React.createElement("span", { "data-slot": "base", className: ui.base() }, /* @__PURE__ */ React.createElement("span", { "data-slot": "glass", "aria-hidden": "true", className: ui.glass() }, /* @__PURE__ */ React.createElement(
26
+ /* @__PURE__ */ React.createElement("span", { "data-slot": "base", className: cn(styles.base(), ui?.base) }, /* @__PURE__ */ React.createElement(
26
27
  "span",
27
28
  {
28
- "data-slot": "overlay",
29
- className: ui.overlay(),
30
- "aria-hidden": "true"
31
- }
32
- )), leadingIcon ? /* @__PURE__ */ React.createElement(
29
+ "data-slot": "glass",
30
+ "aria-hidden": "true",
31
+ className: cn(styles.glass(), ui?.glass)
32
+ },
33
+ /* @__PURE__ */ React.createElement(
34
+ "span",
35
+ {
36
+ "data-slot": "overlay",
37
+ className: cn(styles.overlay(), ui?.overlay),
38
+ "aria-hidden": "true"
39
+ }
40
+ )
41
+ ), leadingIcon ? /* @__PURE__ */ React.createElement(
33
42
  "span",
34
43
  {
35
44
  "data-slot": "leading-icon",
36
- className: ui.leadingIcon(),
45
+ className: cn(styles.leadingIcon(), ui?.leadingIcon),
37
46
  "aria-hidden": "true"
38
47
  },
39
48
  leadingIcon
40
- ) : null, /* @__PURE__ */ React.createElement("span", { "data-slot": "label", className: ui.label() }, label || children), trailingIcon ? /* @__PURE__ */ React.createElement(
49
+ ) : null, /* @__PURE__ */ React.createElement("span", { "data-slot": "label", className: cn(styles.label(), ui?.label) }, label || children), trailingIcon ? /* @__PURE__ */ React.createElement(
41
50
  "span",
42
51
  {
43
52
  "data-slot": "trailing-icon",
44
- className: ui.trailingIcon(),
53
+ className: cn(styles.trailingIcon(), ui?.trailingIcon),
45
54
  "aria-hidden": "true"
46
55
  },
47
56
  trailingIcon
@@ -1,7 +1,12 @@
1
1
  import * as React from "react";
2
+ import { type ComponentConfig } from "../internal/tv";
3
+ import theme from "../theme/card";
4
+ type Card = ComponentConfig<typeof theme>;
2
5
  type CardProps = Omit<React.ComponentProps<"div">, "title"> & {
3
6
  /** Classes merged into the root element. */
4
7
  className?: string;
8
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
9
+ ui?: Card["slots"];
5
10
  /** Optional visible title rendered inside the card header. */
6
11
  title?: React.ReactNode;
7
12
  /** Optional supporting copy rendered under the title. */
@@ -9,6 +14,6 @@ type CardProps = Omit<React.ComponentProps<"div">, "title"> & {
9
14
  /** Optional footer row rendered below the body. */
10
15
  footer?: React.ReactNode;
11
16
  };
12
- declare function Card({ className, title, description, footer, children, ...props }: CardProps): React.JSX.Element;
17
+ declare function Card({ className, ui, title, description, footer, children, ...props }: CardProps): React.JSX.Element;
13
18
  export { Card };
14
19
  export type { CardProps };
@@ -3,22 +3,45 @@ import * as React from "react";
3
3
  import theme from "../theme/card.mjs";
4
4
  function Card({
5
5
  className,
6
+ ui,
6
7
  title,
7
8
  description,
8
9
  footer,
9
10
  children,
10
11
  ...props
11
12
  }) {
12
- const ui = theme();
13
+ const styles = theme();
13
14
  return /* @__PURE__ */ React.createElement(
14
15
  "div",
15
16
  {
16
17
  "data-slot": "root",
17
- className: cn(ui.root(), className),
18
+ className: cn(styles.root(), ui?.root, className),
18
19
  ...props
19
20
  },
20
- /* @__PURE__ */ React.createElement("div", { "aria-hidden": "true", className: ui.glass() }, /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true", className: ui.overlay() })),
21
- /* @__PURE__ */ React.createElement("div", { className: ui.layout() }, title || description ? /* @__PURE__ */ React.createElement("div", { "data-slot": "header", className: ui.header() }, title ? /* @__PURE__ */ React.createElement("div", { "data-slot": "title", className: ui.title() }, title) : null, description ? /* @__PURE__ */ React.createElement("div", { "data-slot": "description", className: ui.description() }, description) : null) : 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)
21
+ /* @__PURE__ */ React.createElement(
22
+ "div",
23
+ {
24
+ "aria-hidden": "true",
25
+ "data-slot": "glass",
26
+ className: cn(styles.glass(), ui?.glass)
27
+ },
28
+ /* @__PURE__ */ React.createElement(
29
+ "span",
30
+ {
31
+ "aria-hidden": "true",
32
+ "data-slot": "overlay",
33
+ className: cn(styles.overlay(), ui?.overlay)
34
+ }
35
+ )
36
+ ),
37
+ /* @__PURE__ */ React.createElement("div", { "data-slot": "layout", className: cn(styles.layout(), ui?.layout) }, title || description ? /* @__PURE__ */ React.createElement("div", { "data-slot": "header", className: cn(styles.header(), ui?.header) }, title ? /* @__PURE__ */ React.createElement("div", { "data-slot": "title", className: cn(styles.title(), ui?.title) }, title) : null, description ? /* @__PURE__ */ React.createElement(
38
+ "div",
39
+ {
40
+ "data-slot": "description",
41
+ className: cn(styles.description(), ui?.description)
42
+ },
43
+ description
44
+ ) : null) : null, children ? /* @__PURE__ */ React.createElement("div", { "data-slot": "body", className: cn(styles.body(), ui?.body) }, children) : null, footer ? /* @__PURE__ */ React.createElement("div", { "data-slot": "footer", className: cn(styles.footer(), ui?.footer) }, footer) : null)
22
45
  );
23
46
  }
24
47
  export { Card };
@@ -1,17 +1,21 @@
1
1
  import { Checkbox as UICheckbox } from "@base-ui/react/checkbox";
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/checkbox";
6
+ type Checkbox = ComponentConfig<typeof theme>;
5
7
  interface CheckboxProps extends Omit<UICheckbox.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 checkbox root. */
9
11
  className?: string;
12
+ /** Tailwind classes for internal slots, keyed by `data-slot`. */
13
+ ui?: Checkbox["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 Checkbox({ className, label, description, size, indeterminate, ...props }: CheckboxProps): React.JSX.Element;
19
+ declare function Checkbox({ className, ui, label, description, size, indeterminate, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: CheckboxProps): React.JSX.Element;
16
20
  export { Checkbox };
17
21
  export type { CheckboxProps };