@xingxingmofashu/ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +17 -6
  2. package/dist/components/accordion.d.ts +5 -5
  3. package/dist/components/accordion.mjs +2 -2
  4. package/dist/components/alert-dialog.d.ts +3 -1
  5. package/dist/components/alert-dialog.mjs +3 -1
  6. package/dist/components/button.d.ts +1 -1
  7. package/dist/components/card.d.ts +1 -1
  8. package/dist/components/checkbox-group.d.ts +8 -8
  9. package/dist/components/checkbox-group.mjs +3 -3
  10. package/dist/components/checkbox.d.ts +1 -1
  11. package/dist/components/dialog.d.ts +3 -1
  12. package/dist/components/dialog.mjs +3 -1
  13. package/dist/components/drawer.d.ts +4 -2
  14. package/dist/components/drawer.mjs +3 -1
  15. package/dist/components/field.d.ts +1 -1
  16. package/dist/components/fieldset.d.ts +1 -1
  17. package/dist/components/form.d.ts +1 -1
  18. package/dist/components/input.d.ts +3 -1
  19. package/dist/components/input.mjs +3 -1
  20. package/dist/components/menu.d.ts +10 -8
  21. package/dist/components/menu.mjs +6 -4
  22. package/dist/components/popover.d.ts +3 -1
  23. package/dist/components/popover.mjs +3 -1
  24. package/dist/components/progress.d.ts +1 -1
  25. package/dist/components/radio-group.d.ts +3 -3
  26. package/dist/components/radio-group.mjs +2 -2
  27. package/dist/components/scroll-area.d.ts +1 -1
  28. package/dist/components/select.d.ts +25 -13
  29. package/dist/components/select.mjs +130 -118
  30. package/dist/components/slider.d.ts +2 -2
  31. package/dist/components/switch.d.ts +1 -1
  32. package/dist/components/switch.mjs +22 -69
  33. package/dist/components/tabs.d.ts +9 -9
  34. package/dist/components/tabs.mjs +4 -4
  35. package/dist/components/toggle-group.d.ts +3 -3
  36. package/dist/components/toggle.d.ts +2 -2
  37. package/dist/components/tooltip.d.ts +3 -1
  38. package/dist/components/tooltip.mjs +3 -1
  39. package/dist/index.css +1 -1
  40. package/dist/index.d.ts +1 -1
  41. package/dist/theme/accordion.mjs +4 -1
  42. package/dist/theme/select.d.ts +2 -0
  43. package/dist/theme/select.mjs +2 -0
  44. package/dist/theme/switch.d.ts +5 -5
  45. package/dist/theme/switch.mjs +23 -49
  46. package/package.json +2 -3
package/README.md CHANGED
@@ -39,6 +39,16 @@ Toast, Toggle, Toggle Group, and Tooltip.
39
39
  - [llms-full.txt](https://xingxingmofashu.github.io/ui/llms-full.txt) — every
40
40
  guide and component page in one file
41
41
 
42
+ ## Agent skill
43
+
44
+ The portable skill in
45
+ [`skills/xingxingmofashu-ui`](https://github.com/xingxingmofashu/ui/tree/main/skills/xingxingmofashu-ui)
46
+ teaches coding agents how to install, compose, theme, and troubleshoot the
47
+ components. It lives in the repository and is not included in the npm package.
48
+ See the
49
+ [skill README](https://github.com/xingxingmofashu/ui/blob/main/skills/xingxingmofashu-ui/README.md)
50
+ for OpenCode, Claude Code, and compatible agent setup.
51
+
42
52
  ## Installation
43
53
 
44
54
  ```bash [pnpm]
@@ -142,7 +152,7 @@ import { Button } from "@xingxingmofashu/ui/components/button";
142
152
  import buttonTheme from "@xingxingmofashu/ui/theme/button";
143
153
  ```
144
154
 
145
- Toast hooks live under `@xingxingmofashu/ui/composables`.
155
+ Toast hooks live under `@xingxingmofashu/ui/composables/use-toast`.
146
156
 
147
157
  ## Development
148
158
 
@@ -151,15 +161,16 @@ pnpm install
151
161
  pnpm build # build dist with unbuild
152
162
  pnpm lint # lint with oxlint
153
163
  pnpm test # run the Vitest suite
154
- pnpm test:visual # run the Playwright visual regression suite
155
- pnpm test:visual:update # refresh the Surface Lab screenshots
164
+ pnpm test:e2e # run the Playwright browser suite
156
165
  pnpm typecheck # typecheck the package
157
166
  pnpm docs:dev # docs site on http://localhost:3001
158
- pnpm playground:dev # component playground on http://localhost:3002
167
+ pnpm playground:dev # React REPL on http://localhost:3002
159
168
  ```
160
169
 
161
- The documentation site lives in `docs/` and the playground lives in
162
- `playground/`; both import the package from the workspace.
170
+ The documentation site lives in `docs/` and the React REPL lives in
171
+ `playground/`; both import the package from the workspace. The REPL compiles
172
+ TSX in the browser with Monaco's TypeScript worker and runs the result against
173
+ a small import whitelist.
163
174
 
164
175
  ## Contribution
165
176
 
@@ -5,9 +5,9 @@ import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/accordion";
6
6
  type Accordion = ComponentConfig<typeof theme>;
7
7
  /** One panel managed by the accordion. */
8
- type AccordionItemProps<Value extends string = string> = Omit<UIAccordion.Item.Props, "children" | "className" | "content" | "style" | "title" | "value"> & {
8
+ type AccordionItemProps = Omit<UIAccordion.Item.Props, "children" | "className" | "content" | "title" | "value"> & {
9
9
  /** Value that identifies the item in the accordion value. */
10
- value: Value;
10
+ value: any;
11
11
  /** Visible heading inside the trigger. */
12
12
  title: React.ReactNode;
13
13
  /** Panel content. */
@@ -19,14 +19,14 @@ type AccordionItemProps<Value extends string = string> = Omit<UIAccordion.Item.P
19
19
  /** Tailwind classes for this item's internal slots, keyed by `data-slot`. */
20
20
  ui?: Partial<Pick<Accordion["slots"], "item" | "header" | "trigger" | "title" | "indicator" | "indicatorIcon" | "panel" | "panelContent">>;
21
21
  };
22
- type AccordionProps<Value extends string = string> = Omit<UIAccordion.Root.Props<Value>, "className" | "style" | "children"> & VariantProps<typeof theme> & {
22
+ type AccordionProps<Value = any> = Omit<UIAccordion.Root.Props<Value>, "className" | "children"> & VariantProps<typeof theme> & {
23
23
  /** Panels rendered by the accordion. */
24
- items: readonly AccordionItemProps<Value>[];
24
+ items: readonly AccordionItemProps[];
25
25
  /** Tailwind classes merged into the root. */
26
26
  className?: string;
27
27
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
28
28
  ui?: Accordion["slots"];
29
29
  };
30
- declare function Accordion<Value extends string = string>({ className, ui, size, items, ...props }: AccordionProps<Value>): React.JSX.Element;
30
+ declare function Accordion<Value = any>({ className, ui, size, items, ...props }: AccordionProps<Value>): React.JSX.Element;
31
31
  export { Accordion };
32
32
  export type { AccordionItemProps, AccordionProps };
@@ -35,10 +35,10 @@ function Accordion({
35
35
  }
36
36
  )
37
37
  ),
38
- /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: cn(styles.content(), ui?.content) }, items.map((item) => /* @__PURE__ */ React.createElement(
38
+ /* @__PURE__ */ React.createElement("div", { "data-slot": "content", className: cn(styles.content(), ui?.content) }, items.map((item, index) => /* @__PURE__ */ React.createElement(
39
39
  AccordionItem,
40
40
  {
41
- key: item.value,
41
+ key: index,
42
42
  ...item,
43
43
  ui: {
44
44
  item: cn(ui?.item, item.ui?.item),
@@ -20,9 +20,11 @@ type AlertDialogProps = Omit<UIAlertDialog.Root.Props, "children"> & {
20
20
  onConfirm?: React.MouseEventHandler<HTMLButtonElement>;
21
21
  /** Tailwind classes merged into the popup. */
22
22
  className?: string;
23
+ /** Inline styles merged into the popup. */
24
+ style?: React.CSSProperties;
23
25
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
24
26
  ui?: AlertDialog["slots"];
25
27
  };
26
- declare function AlertDialog({ title, description, children, cancelLabel, confirmLabel, onCancel, onConfirm, className, ui, ...props }: AlertDialogProps): React.JSX.Element;
28
+ declare function AlertDialog({ title, description, children, cancelLabel, confirmLabel, onCancel, onConfirm, className, style, ui, ...props }: AlertDialogProps): React.JSX.Element;
27
29
  export { AlertDialog };
28
30
  export type { AlertDialogProps };
@@ -13,6 +13,7 @@ function AlertDialog({
13
13
  onCancel,
14
14
  onConfirm,
15
15
  className,
16
+ style,
16
17
  ui,
17
18
  ...props
18
19
  }) {
@@ -33,7 +34,8 @@ function AlertDialog({
33
34
  UIAlertDialog.Popup,
34
35
  {
35
36
  "data-slot": "popup",
36
- className: cn(styles.popup(), ui?.popup, className)
37
+ className: cn(styles.popup(), ui?.popup, className),
38
+ style
37
39
  },
38
40
  /* @__PURE__ */ React.createElement(
39
41
  "span",
@@ -4,7 +4,7 @@ import { type VariantProps } from "tailwind-variants";
4
4
  import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/button";
6
6
  type Button = ComponentConfig<typeof theme>;
7
- interface ButtonProps extends Omit<UIButtonProps, "ref" | "style" | "className">, VariantProps<typeof theme> {
7
+ interface ButtonProps extends Omit<UIButtonProps, "ref" | "className">, VariantProps<typeof theme> {
8
8
  /** Ref to the rendered root element. */
9
9
  ref?: React.Ref<HTMLElement>;
10
10
  /** Tailwind classes merged into the outer click area. */
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import { type ComponentConfig } from "../internal/tv";
3
3
  import theme from "../theme/card";
4
4
  type Card = ComponentConfig<typeof theme>;
5
- type CardProps = Omit<React.ComponentProps<"div">, "style" | "title"> & {
5
+ type CardProps = Omit<React.ComponentProps<"div">, "title"> & {
6
6
  /** Classes merged into the root element. */
7
7
  className?: string;
8
8
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
@@ -6,9 +6,9 @@ import { type ComponentConfig } from "../internal/tv";
6
6
  import theme from "../theme/checkbox-group";
7
7
  type CheckboxGroup = ComponentConfig<typeof theme>;
8
8
  /** One entry in the group. */
9
- type CheckboxGroupItemProps<Value extends string = string> = Omit<UICheckbox.Root.Props, "checked" | "defaultChecked" | "children" | "className" | "onCheckedChange" | "parent" | "style" | "value"> & {
9
+ type CheckboxGroupItemProps = Omit<UICheckbox.Root.Props, "checked" | "defaultChecked" | "children" | "className" | "onCheckedChange" | "parent" | "value"> & {
10
10
  /** Value that identifies the option in the group value. */
11
- value: Value;
11
+ value: string;
12
12
  /** Visible label rendered next to the control. */
13
13
  label?: React.ReactNode;
14
14
  /** Supporting text rendered under the label. */
@@ -18,24 +18,24 @@ type CheckboxGroupItemProps<Value extends string = string> = Omit<UICheckbox.Roo
18
18
  /** Tailwind classes for control slots, keyed by `data-slot`. */
19
19
  ui?: Partial<Pick<CheckboxGroup["slots"], "item" | "box" | "fill" | "glass" | "overlay" | "indicator" | "indicatorIcon" | "wrapper" | "itemLabel" | "itemDescription">>;
20
20
  };
21
- type CheckboxGroupProps<Value extends string = string> = Omit<UICheckboxGroup.Props, "allValues" | "children" | "className" | "defaultValue" | "onValueChange" | "style" | "value"> & VariantProps<typeof theme> & Pick<UICheckbox.Root.Props, "name" | "form" | "readOnly"> & {
21
+ type CheckboxGroupProps = Omit<UICheckboxGroup.Props, "allValues" | "children" | "className" | "defaultValue" | "onValueChange" | "value"> & VariantProps<typeof theme> & Pick<UICheckbox.Root.Props, "name" | "form" | "readOnly"> & {
22
22
  /** Entries rendered by the group. */
23
- items: readonly CheckboxGroupItemProps<Value>[];
23
+ items: readonly CheckboxGroupItemProps[];
24
24
  /** Visible label for the group. */
25
25
  label?: React.ReactNode;
26
26
  /** Supporting text rendered under the group label. */
27
27
  description?: React.ReactNode;
28
28
  /** Controlled checked values. */
29
- value?: readonly Value[];
29
+ value?: readonly string[];
30
30
  /** Initial checked values when uncontrolled. */
31
- defaultValue?: readonly Value[];
31
+ defaultValue?: readonly string[];
32
32
  /** Called when a checkbox in the group is ticked or unticked. */
33
- onValueChange?: (value: Value[], details: UICheckboxGroup.ChangeEventDetails) => void;
33
+ onValueChange?: (value: string[], details: UICheckboxGroup.ChangeEventDetails) => void;
34
34
  /** Tailwind classes merged into the group root. */
35
35
  className?: string;
36
36
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
37
37
  ui?: CheckboxGroup["slots"];
38
38
  };
39
- declare function CheckboxGroup<Value extends string = string>({ className, ui, size, items, label, description, name, form, readOnly, disabled, value, defaultValue, onValueChange, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: CheckboxGroupProps<Value>): React.JSX.Element;
39
+ declare function CheckboxGroup({ className, ui, size, items, label, description, name, form, readOnly, disabled, value, defaultValue, onValueChange, "aria-describedby": ariaDescribedBy, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: CheckboxGroupProps): React.JSX.Element;
40
40
  export { CheckboxGroup };
41
41
  export type { CheckboxGroupItemProps, CheckboxGroupProps };
@@ -44,13 +44,13 @@ function CheckboxGroup({
44
44
  UICheckboxGroup,
45
45
  {
46
46
  ...props,
47
+ value,
48
+ defaultValue,
49
+ onValueChange: handleValueChange,
47
50
  "aria-describedby": describedBy,
48
51
  "aria-label": ariaLabel,
49
52
  ...labelledBy ? { "aria-labelledby": labelledBy } : {},
50
53
  disabled: fieldsetDisabled,
51
- value,
52
- defaultValue,
53
- onValueChange: handleValueChange,
54
54
  "data-slot": "root",
55
55
  className: cn(styles.root(), ui?.root, className)
56
56
  },
@@ -4,7 +4,7 @@ import { type VariantProps } from "tailwind-variants";
4
4
  import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/checkbox";
6
6
  type Checkbox = ComponentConfig<typeof theme>;
7
- interface CheckboxProps extends Omit<UICheckbox.Root.Props, "className" | "children" | "style" | "ref">, VariantProps<typeof theme> {
7
+ interface CheckboxProps extends Omit<UICheckbox.Root.Props, "className" | "children" | "ref">, VariantProps<typeof theme> {
8
8
  /** Ref to the rendered root element. */
9
9
  ref?: React.Ref<HTMLElement>;
10
10
  /** Tailwind classes merged into the Base UI checkbox root. */
@@ -14,9 +14,11 @@ type DialogProps = Omit<UIDialog.Root.Props, "children"> & {
14
14
  footer?: React.ReactNode;
15
15
  /** Tailwind classes merged into the popup. */
16
16
  className?: string;
17
+ /** Inline styles merged into the popup. */
18
+ style?: React.CSSProperties;
17
19
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
18
20
  ui?: Dialog["slots"];
19
21
  };
20
- declare function Dialog({ title, description, children, footer, className, ui, ...props }: DialogProps): React.JSX.Element;
22
+ declare function Dialog({ title, description, children, footer, className, style, ui, ...props }: DialogProps): React.JSX.Element;
21
23
  export { Dialog };
22
24
  export type { DialogProps };
@@ -9,6 +9,7 @@ function Dialog({
9
9
  children,
10
10
  footer,
11
11
  className,
12
+ style,
12
13
  ui,
13
14
  ...props
14
15
  }) {
@@ -29,7 +30,8 @@ function Dialog({
29
30
  UIDialog.Popup,
30
31
  {
31
32
  "data-slot": "popup",
32
- className: cn(styles.popup(), ui?.popup, className)
33
+ className: cn(styles.popup(), ui?.popup, className),
34
+ style
33
35
  },
34
36
  /* @__PURE__ */ React.createElement(
35
37
  "span",
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { type ComponentConfig } from "../internal/tv";
4
4
  import theme from "../theme/drawer";
5
5
  type Drawer = ComponentConfig<typeof theme>;
6
- interface DrawerProps extends Omit<UIDrawer.Root.Props, "children" | "className" | "style" | "swipeDirection"> {
6
+ interface DrawerProps extends Omit<UIDrawer.Root.Props, "children" | "className" | "swipeDirection"> {
7
7
  /** Drawer heading. */
8
8
  title: React.ReactNode;
9
9
  /** Supporting copy under the title. */
@@ -16,9 +16,11 @@ interface DrawerProps extends Omit<UIDrawer.Root.Props, "children" | "className"
16
16
  direction?: NonNullable<UIDrawer.Root.Props["swipeDirection"]>;
17
17
  /** Tailwind classes merged into the popup. */
18
18
  className?: string;
19
+ /** Inline styles merged into the popup. */
20
+ style?: React.CSSProperties;
19
21
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
20
22
  ui?: Drawer["slots"];
21
23
  }
22
- declare function Drawer({ title, description, children, footer, direction, className, ui, ...props }: DrawerProps): React.JSX.Element;
24
+ declare function Drawer({ title, description, children, footer, direction, className, style, ui, ...props }: DrawerProps): React.JSX.Element;
23
25
  export { Drawer };
24
26
  export type { DrawerProps };
@@ -10,6 +10,7 @@ function Drawer({
10
10
  footer,
11
11
  direction = "down",
12
12
  className,
13
+ style,
13
14
  ui,
14
15
  ...props
15
16
  }) {
@@ -30,7 +31,8 @@ function Drawer({
30
31
  UIDrawer.Popup,
31
32
  {
32
33
  "data-slot": "popup",
33
- className: cn(styles.popup(), ui?.popup, className)
34
+ className: cn(styles.popup(), ui?.popup, className),
35
+ style
34
36
  },
35
37
  /* @__PURE__ */ React.createElement(
36
38
  "span",
@@ -4,7 +4,7 @@ import { type VariantProps } from "tailwind-variants";
4
4
  import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/field";
6
6
  type Field = ComponentConfig<typeof theme>;
7
- interface FieldProps extends Omit<UIField.Root.Props, "children" | "className" | "style">, VariantProps<typeof theme> {
7
+ interface FieldProps extends Omit<UIField.Root.Props, "children" | "className">, VariantProps<typeof theme> {
8
8
  /** Single Base UI control labelled and validated by the field. */
9
9
  children: React.ReactElement;
10
10
  /** Visible label associated with the control. */
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { type ComponentConfig } from "../internal/tv";
4
4
  import theme from "../theme/fieldset";
5
5
  type Fieldset = ComponentConfig<typeof theme>;
6
- interface FieldsetProps extends Omit<UIFieldset.Root.Props, "children" | "className" | "style"> {
6
+ interface FieldsetProps extends Omit<UIFieldset.Root.Props, "children" | "className"> {
7
7
  /** Visible legend naming the group. */
8
8
  legend?: React.ReactNode;
9
9
  /** Fields and controls grouped by the fieldset. */
@@ -3,7 +3,7 @@ import * as React from "react";
3
3
  import { type ComponentConfig } from "../internal/tv";
4
4
  import theme from "../theme/form";
5
5
  type Form = ComponentConfig<typeof theme>;
6
- type FormProps<FormValues extends Record<string, any> = Record<string, any>> = Omit<UIForm.Props<FormValues>, "className" | "style"> & {
6
+ type FormProps<FormValues extends Record<string, any> = Record<string, any>> = Omit<UIForm.Props<FormValues>, "className"> & {
7
7
  /** Tailwind classes merged into the form element. */
8
8
  className?: string;
9
9
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
@@ -7,6 +7,8 @@ type Input = ComponentConfig<typeof theme>;
7
7
  interface InputProps extends Omit<UIInput.Props, "className" | "children" | "size" | "style">, VariantProps<typeof theme> {
8
8
  /** Tailwind classes merged into the root element. */
9
9
  className?: string;
10
+ /** Inline styles merged into the outer root. Use `ui.input` for the native input. */
11
+ style?: React.CSSProperties;
10
12
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
11
13
  ui?: Input["slots"];
12
14
  /** Icon rendered before the input. */
@@ -14,6 +16,6 @@ interface InputProps extends Omit<UIInput.Props, "className" | "children" | "siz
14
16
  /** Icon rendered after the input. */
15
17
  trailingIcon?: React.ReactNode;
16
18
  }
17
- declare function Input({ className, ui, leadingIcon, trailingIcon, size, disabled, ...props }: InputProps): React.JSX.Element;
19
+ declare function Input({ className, ui, leadingIcon, trailingIcon, size, disabled, style, ...props }: InputProps): React.JSX.Element;
18
20
  export { Input };
19
21
  export type { InputProps };
@@ -11,6 +11,7 @@ function Input({
11
11
  trailingIcon,
12
12
  size,
13
13
  disabled,
14
+ style,
14
15
  ...props
15
16
  }) {
16
17
  const styles = theme({ size });
@@ -20,7 +21,8 @@ function Input({
20
21
  {
21
22
  "data-slot": "root",
22
23
  "data-disabled": fieldsetDisabled || void 0,
23
- className: cn(styles.root(), ui?.root, className)
24
+ className: cn(styles.root(), ui?.root, className),
25
+ style
24
26
  },
25
27
  /* @__PURE__ */ React.createElement(
26
28
  "span",
@@ -4,10 +4,10 @@ import { type ComponentConfig } from "../internal/tv";
4
4
  import theme from "../theme/menu";
5
5
  type Menu = ComponentConfig<typeof theme>;
6
6
  /** One action item in the menu. */
7
- type MenuItemProps<Value extends string = string> = Omit<UIMenu.Item.Props, "children" | "className" | "style" | "label" | "onClick"> & {
7
+ type MenuItemProps = Omit<UIMenu.Item.Props, "children" | "className" | "label" | "onClick"> & {
8
8
  type?: "item";
9
9
  /** Value that identifies the item in the menu. */
10
- value: Value;
10
+ value: string;
11
11
  /** Visible content inside the item. */
12
12
  label: React.ReactNode;
13
13
  /** Plain-text label used for keyboard navigation. Defaults to the rendered text. */
@@ -24,35 +24,37 @@ type MenuItemProps<Value extends string = string> = Omit<UIMenu.Item.Props, "chi
24
24
  ui?: Partial<Pick<Menu["slots"], "item" | "itemIcon" | "itemLabel" | "shortcut">>;
25
25
  };
26
26
  /** A labelled group of menu items. */
27
- type MenuGroupProps<Value extends string = string> = Omit<UIMenu.Group.Props, "children" | "className" | "style"> & {
27
+ type MenuGroupProps = Omit<UIMenu.Group.Props, "children" | "className"> & {
28
28
  type: "group";
29
29
  /** Group heading. */
30
30
  label: React.ReactNode;
31
31
  /** Items rendered inside the group. */
32
- items: readonly MenuItemProps<Value>[];
32
+ items: readonly MenuItemProps[];
33
33
  /** Tailwind classes merged into the group. */
34
34
  className?: string;
35
35
  /** Tailwind classes for the group slots. */
36
36
  ui?: Partial<Pick<Menu["slots"], "group" | "groupLabel" | "item" | "itemIcon" | "itemLabel" | "shortcut">>;
37
37
  };
38
38
  /** A separator between menu items. */
39
- type MenuSeparatorProps = Omit<UIMenu.Separator.Props, "children" | "className" | "orientation" | "style"> & {
39
+ type MenuSeparatorProps = Omit<UIMenu.Separator.Props, "children" | "className" | "orientation"> & {
40
40
  type: "separator";
41
41
  /** Tailwind classes merged into the separator. */
42
42
  className?: string;
43
43
  /** Tailwind classes for the separator slot. */
44
44
  ui?: Partial<Pick<Menu["slots"], "separator">>;
45
45
  };
46
- type MenuProps<Value extends string = string> = Omit<UIMenu.Root.Props, "children" | "className" | "style"> & Pick<UIMenu.Positioner.Props, "side" | "align" | "sideOffset" | "alignOffset" | "collisionPadding"> & {
46
+ type MenuProps = Omit<UIMenu.Root.Props, "children" | "className"> & Pick<UIMenu.Positioner.Props, "side" | "align" | "sideOffset" | "alignOffset" | "collisionPadding"> & {
47
47
  /** Element that opens the menu. It must forward props and refs. */
48
48
  trigger: React.ReactElement;
49
49
  /** Items, groups, and separators rendered by the menu. */
50
- items: readonly (MenuItemProps<Value> | MenuGroupProps<Value> | MenuSeparatorProps)[];
50
+ items: readonly (MenuItemProps | MenuGroupProps | MenuSeparatorProps)[];
51
51
  /** Tailwind classes merged into the popup. */
52
52
  className?: string;
53
+ /** Inline styles merged into the popup. */
54
+ style?: React.CSSProperties;
53
55
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
54
56
  ui?: Menu["slots"];
55
57
  };
56
- declare function Menu<Value extends string = string>({ trigger, items, side, align, sideOffset, alignOffset, collisionPadding, className, ui, ...props }: MenuProps<Value>): React.JSX.Element;
58
+ declare function Menu({ trigger, items, side, align, sideOffset, alignOffset, collisionPadding, className, style, ui, ...props }: MenuProps): React.JSX.Element;
57
59
  export { Menu };
58
60
  export type { MenuGroupProps, MenuItemProps, MenuProps, MenuSeparatorProps, };
@@ -12,6 +12,7 @@ function Menu({
12
12
  alignOffset,
13
13
  collisionPadding,
14
14
  className,
15
+ style,
15
16
  ui,
16
17
  ...props
17
18
  }) {
@@ -31,7 +32,8 @@ function Menu({
31
32
  UIMenu.Popup,
32
33
  {
33
34
  "data-slot": "popup",
34
- className: cn(styles.popup(), ui?.popup, className)
35
+ className: cn(styles.popup(), ui?.popup, className),
36
+ style
35
37
  },
36
38
  /* @__PURE__ */ React.createElement(
37
39
  "span",
@@ -85,7 +87,7 @@ function Menu({
85
87
  return /* @__PURE__ */ React.createElement(
86
88
  MenuActionItem,
87
89
  {
88
- key: entry.value,
90
+ key: index,
89
91
  ...entry,
90
92
  ui: {
91
93
  item: cn(ui?.item, entry.ui?.item),
@@ -172,10 +174,10 @@ function MenuGroup({
172
174
  },
173
175
  label
174
176
  ),
175
- items.map((item) => /* @__PURE__ */ React.createElement(
177
+ items.map((item, index) => /* @__PURE__ */ React.createElement(
176
178
  MenuActionItem,
177
179
  {
178
- key: item.value,
180
+ key: index,
179
181
  ...item,
180
182
  ui: {
181
183
  item: cn(ui?.item, item.ui?.item),
@@ -18,9 +18,11 @@ type PopoverProps = Omit<UIPopover.Root.Props, "children"> & Pick<UIPopover.Posi
18
18
  arrow?: boolean;
19
19
  /** Tailwind classes merged into the popup. */
20
20
  className?: string;
21
+ /** Inline styles merged into the popup. */
22
+ style?: React.CSSProperties;
21
23
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
22
24
  ui?: Popover["slots"];
23
25
  };
24
- declare function Popover({ trigger, title, description, children, footer, arrow, side, align, sideOffset, alignOffset, collisionPadding, className, ui, ...props }: PopoverProps): React.JSX.Element;
26
+ declare function Popover({ trigger, title, description, children, footer, arrow, side, align, sideOffset, alignOffset, collisionPadding, className, style, ui, ...props }: PopoverProps): React.JSX.Element;
25
27
  export { Popover };
26
28
  export type { PopoverProps };
@@ -16,6 +16,7 @@ function Popover({
16
16
  alignOffset,
17
17
  collisionPadding,
18
18
  className,
19
+ style,
19
20
  ui,
20
21
  ...props
21
22
  }) {
@@ -35,7 +36,8 @@ function Popover({
35
36
  UIPopover.Popup,
36
37
  {
37
38
  "data-slot": "popup",
38
- className: cn(styles.popup(), ui?.popup, className)
39
+ className: cn(styles.popup(), ui?.popup, className),
40
+ style
39
41
  },
40
42
  /* @__PURE__ */ React.createElement(
41
43
  "span",
@@ -4,7 +4,7 @@ import { type VariantProps } from "tailwind-variants";
4
4
  import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/progress";
6
6
  type Progress = ComponentConfig<typeof theme>;
7
- type ProgressProps = Omit<UIProgress.Root.Props, "children" | "className" | "style" | "value"> & VariantProps<typeof theme> & {
7
+ type ProgressProps = Omit<UIProgress.Root.Props, "children" | "className" | "value"> & VariantProps<typeof theme> & {
8
8
  /** Current value. Use `null` for an indeterminate progress bar. */
9
9
  value?: number | null;
10
10
  /** Visible label for the progress bar. */
@@ -6,7 +6,7 @@ import { type ComponentConfig } from "../internal/tv";
6
6
  import theme from "../theme/radio-group";
7
7
  type RadioGroup = ComponentConfig<typeof theme>;
8
8
  /** One option managed by the radio group. */
9
- type RadioGroupItemProps<Value extends string = string> = Omit<UIRadio.Root.Props<Value>, "className" | "children" | "style" | "value"> & {
9
+ type RadioGroupItemProps<Value = any> = Omit<UIRadio.Root.Props<Value>, "className" | "children" | "value"> & {
10
10
  /** Value that identifies the option in the group value. */
11
11
  value: Value;
12
12
  /** Visible label rendered next to the control. */
@@ -18,7 +18,7 @@ type RadioGroupItemProps<Value extends string = string> = Omit<UIRadio.Root.Prop
18
18
  /** Tailwind classes for this item's internal slots, keyed by `data-slot`. */
19
19
  ui?: Partial<Pick<RadioGroup["slots"], "item" | "box" | "glass" | "overlay" | "indicator" | "dot" | "wrapper" | "itemLabel" | "itemDescription">>;
20
20
  };
21
- type RadioGroupProps<Value extends string = string> = Omit<UIRadioGroup.Props<Value>, "className" | "style" | "children"> & VariantProps<typeof theme> & {
21
+ type RadioGroupProps<Value = any> = Omit<UIRadioGroup.Props<Value>, "className" | "children"> & VariantProps<typeof theme> & {
22
22
  /** Options rendered by the radio group. */
23
23
  items: readonly RadioGroupItemProps<Value>[];
24
24
  /** Visible label for the group. */
@@ -30,6 +30,6 @@ type RadioGroupProps<Value extends string = string> = Omit<UIRadioGroup.Props<Va
30
30
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
31
31
  ui?: RadioGroup["slots"];
32
32
  };
33
- declare function RadioGroup<Value extends string = string>({ className, ui, size, items, label, description, disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...props }: RadioGroupProps<Value>): React.JSX.Element;
33
+ declare function RadioGroup<Value>({ className, ui, size, items, label, description, disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...props }: RadioGroupProps<Value>): React.JSX.Element;
34
34
  export { RadioGroup };
35
35
  export type { RadioGroupItemProps, RadioGroupProps };
@@ -59,10 +59,10 @@ function RadioGroup({
59
59
  },
60
60
  description
61
61
  ) : null) : null,
62
- /* @__PURE__ */ React.createElement("div", { "data-slot": "items", className: cn(styles.items(), ui?.items) }, items.map((item) => /* @__PURE__ */ React.createElement(
62
+ /* @__PURE__ */ React.createElement("div", { "data-slot": "items", className: cn(styles.items(), ui?.items) }, items.map((item, index) => /* @__PURE__ */ React.createElement(
63
63
  RadioGroupItem,
64
64
  {
65
- key: item.value,
65
+ key: index,
66
66
  ...item,
67
67
  ui: {
68
68
  item: cn(ui?.item, item.ui?.item),
@@ -5,7 +5,7 @@ import theme from "../theme/scroll-area";
5
5
  /** Scrollbar axes rendered by the scroll area. */
6
6
  type ScrollAreaOrientation = "vertical" | "horizontal" | "both";
7
7
  type ScrollArea = ComponentConfig<typeof theme>;
8
- type ScrollAreaProps = Omit<UIScrollArea.Root.Props, "children" | "className" | "style"> & {
8
+ type ScrollAreaProps = Omit<UIScrollArea.Root.Props, "children" | "className"> & {
9
9
  /** Scrollable content. */
10
10
  children?: React.ReactNode;
11
11
  /** Scrollbar axes to render. Defaults to `"vertical"`. */
@@ -5,9 +5,9 @@ import { type ComponentConfig } from "../internal/tv";
5
5
  import theme from "../theme/select";
6
6
  type Select = ComponentConfig<typeof theme>;
7
7
  /** One option rendered by the select. */
8
- type SelectItemProps<Value extends string = string> = {
8
+ type SelectItemProps = {
9
9
  /** Value submitted and passed to `onValueChange`. */
10
- value: Value;
10
+ value: any;
11
11
  /** Visible content inside the option and the trigger. */
12
12
  label: React.ReactNode;
13
13
  /** Plain-text label used for keyboard navigation. Defaults to a string label. */
@@ -15,21 +15,31 @@ type SelectItemProps<Value extends string = string> = {
15
15
  /** Whether the option is disabled. */
16
16
  disabled?: boolean;
17
17
  };
18
- type SelectProps<Value extends string = string> = Omit<UISelect.Root.Props<Value>, "children" | "className" | "style" | "items" | "multiple" | "value" | "defaultValue" | "onValueChange"> & VariantProps<typeof theme> & Pick<UISelect.Positioner.Props, "side" | "align" | "sideOffset" | "alignOffset" | "collisionPadding" | "alignItemWithTrigger"> & {
19
- /** Options rendered by the select. */
20
- items: readonly SelectItemProps<Value>[];
18
+ /** A labelled group of options. */
19
+ type SelectItemGroupProps = {
20
+ /** Visible heading rendered above the group. */
21
+ label: React.ReactNode;
22
+ /** Options in the group. */
23
+ items: readonly SelectItemProps[];
24
+ };
25
+ /** An option or a labelled group of options. */
26
+ type SelectEntry = SelectItemProps | SelectItemGroupProps;
27
+ /** Value shape exposed to `renderValue` for the active selection mode. */
28
+ type SelectValue<Value, Multiple extends boolean | undefined> = Multiple extends true ? readonly Value[] : Value | null;
29
+ type SelectProps<Value, Multiple extends boolean | undefined = false> = Omit<UISelect.Root.Props<Value, Multiple>, "children" | "className" | "items"> & VariantProps<typeof theme> & Pick<UISelect.Positioner.Props, "side" | "align" | "sideOffset" | "alignOffset" | "collisionPadding" | "alignItemWithTrigger"> & {
30
+ /** Options rendered by the select, optionally grouped. */
31
+ items: readonly SelectEntry[];
21
32
  /** Visible label associated with the trigger. */
22
33
  label?: React.ReactNode;
23
34
  /** Supporting text under the trigger. */
24
35
  description?: React.ReactNode;
25
36
  /** Text shown when no value is selected. */
26
37
  placeholder?: React.ReactNode;
27
- /** Controlled value. */
28
- value?: Value | null;
29
- /** Initial value when uncontrolled. */
30
- defaultValue?: Value | null;
31
- /** Called when the selected value changes. */
32
- onValueChange?: (value: Value | null, details: UISelect.Root.ChangeEventDetails) => void;
38
+ /**
39
+ * Formats the selected value inside the trigger.
40
+ * When provided, it overrides `placeholder`.
41
+ */
42
+ renderValue?: (value: SelectValue<Value, Multiple>) => React.ReactNode;
33
43
  /** Accessible name for the trigger when no visible label is rendered. */
34
44
  "aria-label"?: string;
35
45
  /** Names the trigger from another element. */
@@ -38,9 +48,11 @@ type SelectProps<Value extends string = string> = Omit<UISelect.Root.Props<Value
38
48
  "aria-describedby"?: string;
39
49
  /** Tailwind classes merged into the root element. */
40
50
  className?: string;
51
+ /** Inline styles merged into the root element. */
52
+ style?: React.CSSProperties;
41
53
  /** Tailwind classes for internal slots, keyed by `data-slot`. */
42
54
  ui?: Select["slots"];
43
55
  };
44
- declare function Select<Value extends string = string>({ className, ui, size, items, label, description, placeholder, value, defaultValue, onValueChange, side, align, sideOffset, alignOffset, collisionPadding, alignItemWithTrigger, disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...props }: SelectProps<Value>): React.JSX.Element;
56
+ declare function Select<Value, Multiple extends boolean | undefined = false>({ className, ui, size, items, label, description, placeholder, renderValue, side, align, sideOffset, alignOffset, collisionPadding, alignItemWithTrigger, disabled, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, style, ...props }: SelectProps<Value, Multiple>): React.JSX.Element;
45
57
  export { Select };
46
- export type { SelectItemProps, SelectProps };
58
+ export type { SelectEntry, SelectItemGroupProps, SelectItemProps, SelectProps, };