@robr0/design-system 0.1.0 → 0.2.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 (39) hide show
  1. package/README.md +6 -4
  2. package/components/Breadcrumb/Breadcrumb.css +9 -1
  3. package/components/Button/Button.d.ts +32 -16
  4. package/components/Button/Button.js +66 -58
  5. package/components/Card/Card.d.ts +17 -5
  6. package/components/Card/Card.js +101 -80
  7. package/components/Checkbox/Checkbox.d.ts +24 -12
  8. package/components/Checkbox/Checkbox.js +99 -85
  9. package/components/Combobox/Combobox.d.ts +19 -7
  10. package/components/Combobox/Combobox.js +18 -9
  11. package/components/DateInput/DateInput.d.ts +18 -21
  12. package/components/DateInput/DateInput.js +71 -63
  13. package/components/DatePicker/DatePicker.d.ts +9 -2
  14. package/components/DatePicker/DatePicker.js +127 -129
  15. package/components/Dialog/Dialog.d.ts +15 -4
  16. package/components/Dialog/Dialog.js +133 -116
  17. package/components/Drawer/Drawer.d.ts +15 -4
  18. package/components/Drawer/Drawer.js +133 -119
  19. package/components/Dropdown/Dropdown.d.ts +24 -8
  20. package/components/Dropdown/Dropdown.js +226 -186
  21. package/components/FileInput/FileInput.d.ts +13 -17
  22. package/components/FileInput/FileInput.js +177 -158
  23. package/components/Input/Input.d.ts +23 -22
  24. package/components/Input/Input.js +87 -65
  25. package/components/RadioButton/RadioButton.d.ts +26 -13
  26. package/components/RadioButton/RadioButton.js +95 -70
  27. package/components/SelectionCard/SelectionCard.d.ts +10 -4
  28. package/components/SelectionCard/SelectionCard.js +72 -56
  29. package/components/Slider/Slider.d.ts +19 -10
  30. package/components/Slider/Slider.js +50 -40
  31. package/components/Table/Table.d.ts +10 -2
  32. package/components/Table/Table.js +58 -58
  33. package/components/Textarea/Textarea.d.ts +21 -22
  34. package/components/Textarea/Textarea.js +77 -68
  35. package/components/ToggleGroup/ToggleGroup.d.ts +18 -8
  36. package/components/ToggleGroup/ToggleGroup.js +61 -44
  37. package/components/ToggleSwitch/ToggleSwitch.d.ts +17 -9
  38. package/components/ToggleSwitch/ToggleSwitch.js +57 -44
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # robr0 — Portfolio + Design System
2
2
 
3
3
  [![CI](https://github.com/robritacca-dotcom/design-system/actions/workflows/ci.yml/badge.svg)](https://github.com/robritacca-dotcom/design-system/actions/workflows/ci.yml)
4
+ <!-- npm-badge:start -->
5
+ [![npm](https://img.shields.io/npm/v/@robr0%2Fdesign-system?logo=npm&color=CB3837)](https://www.npmjs.com/package/@robr0/design-system)
6
+ <!-- npm-badge:end -->
4
7
 
5
8
  A personal portfolio site built on a custom React design system I designed and engineered from scratch. The DS isn't a side project — it's the backbone every portfolio page is built on, ensuring the work is presented consistently and with the same craft standards I apply professionally.
6
9
 
@@ -107,7 +110,7 @@ Full spec in [`design.md`](design.md).
107
110
  Every push and pull request runs a GitHub Actions pipeline ([`ci.yml`](.github/workflows/ci.yml)) with four jobs: **lint + library build**, **story tests** (every Storybook story rendered in headless Chromium via Vitest), **Storybook build**, and **website build**. The same checklist runs locally with one command:
108
111
 
109
112
  ```bash
110
- npm run verify # lint + library build + story tests + Storybook build + website build
113
+ npm run verify # lint + library type-check + package build + story tests + Storybook build + website build
111
114
  ```
112
115
 
113
116
  CI also guards against documentation drift: generated surfaces (this README's component count and list, the website's skills pages, the published CLAUDE.md/design.md blueprints) are rebuilt from their source registries on every build, and CI fails if the committed copies are stale. The numbers on the site are never hand-written.
@@ -120,8 +123,7 @@ CI also guards against documentation drift: generated surfaces (this README's co
120
123
  # Storybook (the library's dev sandbox)
121
124
  npm run storybook # http://localhost:6006
122
125
 
123
- # Portfolio + documentation website
124
- cd website
126
+ # Portfolio + documentation website (npm workspace — install once at the root)
125
127
  npm install
126
- npm run dev # http://localhost:3000
128
+ npm run dev --workspace website # http://localhost:3000
127
129
  ```
@@ -74,8 +74,16 @@
74
74
  SEPARATOR
75
75
  ============================================ */
76
76
 
77
+ /*
78
+ Size via --icon-size, never font-size: .material-symbols-rounded derives
79
+ the glyph size AND the layout box from that one variable. Setting
80
+ font-size alone shrank the glyph but left a 24px box around it, so the
81
+ chevron floated above the text baseline. --icon-size-sm (20px) also
82
+ matches the 20px line-height of the paragraph-sm labels either side.
83
+ */
77
84
  .ds-breadcrumb__separator {
78
- font-size: 18px;
85
+ --icon-size: var(--icon-size-sm);
86
+ flex: none;
79
87
  color: var(--color-text-tertiary);
80
88
  user-select: none;
81
89
  }
@@ -1,21 +1,18 @@
1
1
  import { default as React } from 'react';
2
- export interface ButtonProps {
2
+ /** Props owned by Button itself — everything else falls through to the DOM node. */
3
+ type ButtonOwnProps = {
3
4
  /** Button text content */
4
5
  label?: string;
5
6
  /** Icon for left side — Material Symbol name (string) or custom element (ReactNode) */
6
7
  iconLeft?: string | React.ReactNode;
7
8
  /** Icon for right side — Material Symbol name (string) or custom element (ReactNode) */
8
9
  iconRight?: string | React.ReactNode;
9
- /** Button priority/variant */
10
- priority?: 'primary' | 'secondary' | 'tertiary' | 'destructive';
11
- /** Button state */
12
- state?: 'default' | 'hover' | 'active' | 'disabled';
10
+ /** Visual treatment */
11
+ variant?: 'primary' | 'secondary' | 'tertiary' | 'destructive';
13
12
  /** Button size */
14
13
  size?: 'default' | 'compact';
15
- /** Show text label */
16
- text?: boolean;
17
- /** Optional click handler */
18
- onClick?: () => void;
14
+ /** Whether the button is disabled */
15
+ disabled?: boolean;
19
16
  /** Optional href — renders as <a> instead of <button> */
20
17
  href?: string;
21
18
  /** Optional target attribute for links */
@@ -24,16 +21,35 @@ export interface ButtonProps {
24
21
  rel?: string;
25
22
  /** Marks this link as the current page (adds aria-current="page") */
26
23
  ariaCurrent?: boolean;
27
- /** Id of an element describing this button — set automatically by Tooltip */
28
- 'aria-describedby'?: string;
29
24
  /** Additional CSS classes */
30
25
  className?: string;
31
- /** @deprecated Use iconLeft instead */
26
+ /** @deprecated Use `variant` instead. */
27
+ priority?: 'primary' | 'secondary' | 'tertiary' | 'destructive';
28
+ /**
29
+ * @deprecated Use `disabled` for the disabled state.
30
+ *
31
+ * Documentation-only affordance for rendering a *static* interaction state in
32
+ * Storybook and the showcase site. Real hover/active styling comes from CSS
33
+ * pseudo-classes and needs no prop — for docs, prefer `className="ds-button--hover"`.
34
+ */
35
+ state?: 'default' | 'hover' | 'active' | 'disabled';
36
+ /** @deprecated Use `iconLeft` instead. */
32
37
  icon?: string;
38
+ /**
39
+ * @deprecated Will be removed once `label` loses its default in the next major;
40
+ * an icon-only button will simply omit `label`.
41
+ */
42
+ text?: boolean;
43
+ };
44
+ export interface ButtonProps extends ButtonOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof ButtonOwnProps | 'type'> {
33
45
  }
34
46
  /**
35
- * Button component from Figma design system
36
- * Supports primary and secondary variants with multiple states
37
- * Icons can be placed on the left and/or right side of the text
47
+ * Button component from Figma design system.
48
+ * Supports primary, secondary, tertiary and destructive variants.
49
+ * Icons can be placed on the left and/or right side of the text.
50
+ *
51
+ * Renders a `<button>`, or an `<a>` when `href` is supplied. Forwards a ref to
52
+ * whichever element it renders, and spreads unrecognised props onto it.
38
53
  */
39
- export declare const Button: ({ label, iconLeft, iconRight, priority, state, size, text, onClick, href, target, rel, ariaCurrent, "aria-describedby": ariaDescribedby, className, icon, }: ButtonProps) => React.JSX.Element;
54
+ export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
55
+ export {};
@@ -1,71 +1,79 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import "react";
2
+ import React from "react";
3
3
  import "./Button.css";
4
4
  import "../../fonts/material-symbols.css";
5
- const Button = ({
6
- label = "Button",
7
- iconLeft,
8
- iconRight,
9
- priority = "primary",
10
- state = "default",
11
- size = "default",
12
- text = true,
13
- onClick,
14
- href,
15
- target,
16
- rel,
17
- ariaCurrent,
18
- "aria-describedby": ariaDescribedby,
19
- className = "",
20
- icon
21
- // deprecated, maps to iconLeft for backwards compatibility
22
- }) => {
23
- const baseClass = "ds-button";
24
- const variantClass = `${baseClass}--${priority}`;
25
- const stateClass = `${baseClass}--${state}`;
26
- const sizeClass = `${baseClass}--${size}`;
27
- const classes = [baseClass, variantClass, stateClass, sizeClass, className].filter(Boolean).join(" ");
28
- const isDisabled = state === "disabled";
29
- const iconClass = "material-symbols-rounded";
30
- const leftIcon = iconLeft || icon;
31
- const renderIcon = (iconProp) => {
32
- if (typeof iconProp === "string") {
33
- return /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon ${iconClass}`, "aria-hidden": "true", children: iconProp });
5
+ const Button = React.forwardRef(
6
+ ({
7
+ label = "Button",
8
+ iconLeft,
9
+ iconRight,
10
+ variant,
11
+ size = "default",
12
+ disabled,
13
+ href,
14
+ target,
15
+ rel,
16
+ ariaCurrent,
17
+ className = "",
18
+ priority,
19
+ state,
20
+ icon,
21
+ text = true,
22
+ ...rest
23
+ }, ref) => {
24
+ const baseClass = "ds-button";
25
+ const resolvedVariant = variant ?? priority ?? "primary";
26
+ const isDisabled = disabled ?? state === "disabled";
27
+ const resolvedState = state ?? (isDisabled ? "disabled" : "default");
28
+ const classes = [
29
+ baseClass,
30
+ `${baseClass}--${resolvedVariant}`,
31
+ `${baseClass}--${resolvedState}`,
32
+ `${baseClass}--${size}`,
33
+ className
34
+ ].filter(Boolean).join(" ");
35
+ const iconClass = "material-symbols-rounded";
36
+ const leftIcon = iconLeft || icon;
37
+ const renderIcon = (iconProp) => {
38
+ if (typeof iconProp === "string") {
39
+ return /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon ${iconClass}`, "aria-hidden": "true", children: iconProp });
40
+ }
41
+ return /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: iconProp });
42
+ };
43
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
44
+ leftIcon && renderIcon(leftIcon),
45
+ text && /* @__PURE__ */ jsx("span", { className: `${baseClass}__text`, children: label }),
46
+ iconRight && renderIcon(iconRight)
47
+ ] });
48
+ if (href && !isDisabled) {
49
+ return /* @__PURE__ */ jsx(
50
+ "a",
51
+ {
52
+ ...rest,
53
+ ref,
54
+ className: classes,
55
+ href,
56
+ target,
57
+ rel,
58
+ "aria-current": ariaCurrent ? "page" : void 0,
59
+ children: content
60
+ }
61
+ );
34
62
  }
35
- return /* @__PURE__ */ jsx("span", { className: `${baseClass}__icon`, "aria-hidden": "true", children: iconProp });
36
- };
37
- const children = /* @__PURE__ */ jsxs(Fragment, { children: [
38
- leftIcon && renderIcon(leftIcon),
39
- text && /* @__PURE__ */ jsx("span", { className: `${baseClass}__text`, children: label }),
40
- iconRight && renderIcon(iconRight)
41
- ] });
42
- if (href && !isDisabled) {
43
63
  return /* @__PURE__ */ jsx(
44
- "a",
64
+ "button",
45
65
  {
66
+ ...rest,
67
+ ref,
68
+ type: "button",
46
69
  className: classes,
47
- href,
48
- target,
49
- rel,
50
- "aria-current": ariaCurrent ? "page" : void 0,
51
- "aria-describedby": ariaDescribedby,
52
- onClick,
53
- children
70
+ disabled: isDisabled,
71
+ children: content
54
72
  }
55
73
  );
56
74
  }
57
- return /* @__PURE__ */ jsx(
58
- "button",
59
- {
60
- type: "button",
61
- className: classes,
62
- onClick,
63
- disabled: isDisabled,
64
- "aria-describedby": ariaDescribedby,
65
- children
66
- }
67
- );
68
- };
75
+ );
76
+ Button.displayName = "Button";
69
77
  export {
70
78
  Button
71
79
  };
@@ -1,15 +1,17 @@
1
1
  import { default as React } from 'react';
2
- export interface CardProps {
2
+ /** Props owned by Card itself — everything else falls through to the DOM node. */
3
+ type CardOwnProps = {
3
4
  /** Card variant */
4
5
  variant?: 'default' | 'case-study';
5
- /** Card title displayed below the preview */
6
+ /**
7
+ * Card title displayed below the preview.
8
+ * Note: this shadows the native `title` tooltip attribute, which Card does not expose.
9
+ */
6
10
  title: string;
7
11
  /** Preview content rendered inside the card (default variant only) */
8
12
  children?: React.ReactNode;
9
13
  /** Whether the card is interactive (hoverable) */
10
14
  interactive?: boolean;
11
- /** Click handler */
12
- onClick?: () => void;
13
15
  /** Additional CSS classes */
14
16
  className?: string;
15
17
  /** Navigation href — renders the card as an <a> tag */
@@ -26,5 +28,15 @@ export interface CardProps {
26
28
  dek?: string;
27
29
  /** Render as a disabled placeholder (no href, dimmed, not interactive) */
28
30
  placeholder?: boolean;
31
+ };
32
+ export interface CardProps extends CardOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof CardOwnProps> {
29
33
  }
30
- export declare const Card: ({ variant, title, children, interactive, onClick, className, href, coverSrc, coverAlt, companyLogo, companyName, dek, placeholder, }: CardProps) => React.JSX.Element;
34
+ /**
35
+ * Card renders a preview tile, or a case-study tile when `variant="case-study"`.
36
+ *
37
+ * Renders a `<div>`, or an `<a>` in the case-study variant when `href` is
38
+ * supplied. Forwards a ref to whichever element it renders and spreads
39
+ * unrecognised props onto it.
40
+ */
41
+ export declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement | HTMLAnchorElement>>;
42
+ export {};
@@ -1,90 +1,111 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import "react";
2
+ import React from "react";
3
3
  import "./Card.css";
4
4
  import "../../fonts/material-symbols.css";
5
- const Card = ({
6
- variant = "default",
7
- title,
8
- children,
9
- interactive = false,
10
- onClick,
11
- className = "",
12
- href,
13
- coverSrc,
14
- coverAlt,
15
- companyLogo,
16
- companyName,
17
- dek,
18
- placeholder = false
19
- }) => {
20
- if (variant === "case-study") {
21
- const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
22
- /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-wrap", children: coverSrc ? /* @__PURE__ */ jsx(
23
- "img",
5
+ const Card = React.forwardRef(
6
+ ({
7
+ variant = "default",
8
+ title,
9
+ children,
10
+ interactive = false,
11
+ onClick,
12
+ onKeyDown,
13
+ className = "",
14
+ href,
15
+ coverSrc,
16
+ coverAlt,
17
+ companyLogo,
18
+ companyName,
19
+ dek,
20
+ placeholder = false,
21
+ ...rest
22
+ }, ref) => {
23
+ if (variant === "case-study") {
24
+ const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
25
+ /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-wrap", children: coverSrc ? /* @__PURE__ */ jsx(
26
+ "img",
27
+ {
28
+ src: coverSrc,
29
+ alt: coverAlt ?? `${title} cover`,
30
+ className: "ds-card--case-study__cover-image"
31
+ }
32
+ ) : /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-placeholder", children: companyLogo && /* @__PURE__ */ jsx(
33
+ "img",
34
+ {
35
+ src: companyLogo,
36
+ alt: "",
37
+ className: "ds-card--case-study__cover-placeholder-logo"
38
+ }
39
+ ) }) }),
40
+ /* @__PURE__ */ jsxs("div", { className: "ds-card--case-study__body", children: [
41
+ (companyLogo || companyName) && /* @__PURE__ */ jsxs("div", { className: "ds-card--case-study__eyebrow", children: [
42
+ companyLogo && /* @__PURE__ */ jsx("img", { src: companyLogo, alt: "", className: "ds-card--case-study__company-logo" }),
43
+ companyName && /* @__PURE__ */ jsx("span", { className: "ds-card--case-study__company-name", children: companyName })
44
+ ] }),
45
+ /* @__PURE__ */ jsx("h3", { className: "ds-card--case-study__title", children: title }),
46
+ dek && /* @__PURE__ */ jsx("p", { className: "ds-card--case-study__dek", children: dek })
47
+ ] })
48
+ ] });
49
+ const classes2 = [
50
+ "ds-card",
51
+ "ds-card--case-study",
52
+ placeholder ? "ds-card--case-study--placeholder" : "",
53
+ className
54
+ ].filter(Boolean).join(" ");
55
+ if (placeholder || !href) {
56
+ return /* @__PURE__ */ jsx(
57
+ "div",
58
+ {
59
+ ...rest,
60
+ ref,
61
+ className: classes2,
62
+ "aria-disabled": "true",
63
+ children: inner
64
+ }
65
+ );
66
+ }
67
+ return /* @__PURE__ */ jsx(
68
+ "a",
24
69
  {
25
- src: coverSrc,
26
- alt: coverAlt ?? `${title} cover`,
27
- className: "ds-card--case-study__cover-image"
70
+ ...rest,
71
+ ref,
72
+ href,
73
+ className: classes2,
74
+ onClick,
75
+ children: inner
28
76
  }
29
- ) : /* @__PURE__ */ jsx("div", { className: "ds-card--case-study__cover-placeholder", children: companyLogo && /* @__PURE__ */ jsx(
30
- "img",
31
- {
32
- src: companyLogo,
33
- alt: "",
34
- className: "ds-card--case-study__cover-placeholder-logo"
35
- }
36
- ) }) }),
37
- /* @__PURE__ */ jsxs("div", { className: "ds-card--case-study__body", children: [
38
- (companyLogo || companyName) && /* @__PURE__ */ jsxs("div", { className: "ds-card--case-study__eyebrow", children: [
39
- companyLogo && /* @__PURE__ */ jsx(
40
- "img",
41
- {
42
- src: companyLogo,
43
- alt: "",
44
- className: "ds-card--case-study__company-logo"
45
- }
46
- ),
47
- companyName && /* @__PURE__ */ jsx("span", { className: "ds-card--case-study__company-name", children: companyName })
48
- ] }),
49
- /* @__PURE__ */ jsx("h3", { className: "ds-card--case-study__title", children: title }),
50
- dek && /* @__PURE__ */ jsx("p", { className: "ds-card--case-study__dek", children: dek })
51
- ] })
52
- ] });
53
- const classes2 = [
54
- "ds-card",
55
- "ds-card--case-study",
56
- placeholder ? "ds-card--case-study--placeholder" : "",
57
- className
58
- ].filter(Boolean).join(" ");
59
- if (placeholder || !href) {
60
- return /* @__PURE__ */ jsx("div", { className: classes2, "aria-disabled": "true", children: inner });
77
+ );
61
78
  }
62
- return /* @__PURE__ */ jsx("a", { href, className: classes2, children: inner });
79
+ const baseClass = "ds-card";
80
+ const classes = [baseClass, interactive ? `${baseClass}--interactive` : "", className].filter(Boolean).join(" ");
81
+ const handleKeyDown = (e) => {
82
+ onKeyDown?.(e);
83
+ if (!interactive) return;
84
+ if (e.key === "Enter" || e.key === " ") {
85
+ e.preventDefault();
86
+ onClick?.(e);
87
+ }
88
+ };
89
+ return /* @__PURE__ */ jsxs(
90
+ "div",
91
+ {
92
+ ...rest,
93
+ ref,
94
+ className: classes,
95
+ onClick: interactive ? onClick : void 0,
96
+ onKeyDown: handleKeyDown,
97
+ role: interactive ? "button" : void 0,
98
+ tabIndex: interactive ? 0 : void 0,
99
+ "aria-label": interactive ? title : void 0,
100
+ children: [
101
+ /* @__PURE__ */ jsx("div", { className: `${baseClass}__preview`, children }),
102
+ /* @__PURE__ */ jsx("h3", { className: `${baseClass}__title`, children: title })
103
+ ]
104
+ }
105
+ );
63
106
  }
64
- const baseClass = "ds-card";
65
- const interactiveClass = interactive ? `${baseClass}--interactive` : "";
66
- const classes = [baseClass, interactiveClass, className].filter(Boolean).join(" ");
67
- return /* @__PURE__ */ jsxs(
68
- "div",
69
- {
70
- className: classes,
71
- onClick: interactive ? onClick : void 0,
72
- onKeyDown: interactive ? (e) => {
73
- if (e.key === "Enter" || e.key === " ") {
74
- e.preventDefault();
75
- onClick?.();
76
- }
77
- } : void 0,
78
- role: interactive ? "button" : void 0,
79
- tabIndex: interactive ? 0 : void 0,
80
- "aria-label": interactive ? title : void 0,
81
- children: [
82
- /* @__PURE__ */ jsx("div", { className: `${baseClass}__preview`, children }),
83
- /* @__PURE__ */ jsx("h3", { className: `${baseClass}__title`, children: title })
84
- ]
85
- }
86
- );
87
- };
107
+ );
108
+ Card.displayName = "Card";
88
109
  export {
89
110
  Card
90
111
  };
@@ -1,5 +1,6 @@
1
1
  import { default as React } from 'react';
2
- export interface CheckboxProps {
2
+ /** Props owned by Checkbox itself — everything else falls through to the wrapper. */
3
+ type CheckboxOwnProps = {
3
4
  /** Label text */
4
5
  label?: string;
5
6
  /** Whether the checkbox is checked */
@@ -10,18 +11,25 @@ export interface CheckboxProps {
10
11
  disabled?: boolean;
11
12
  /** Component size */
12
13
  size?: 'default' | 'compact';
13
- /** Callback when toggled */
14
- onChange?: (checked: boolean) => void;
14
+ /** Called with the next checked state when toggled */
15
+ onCheckedChange?: (checked: boolean) => void;
15
16
  /** Additional CSS classes */
16
17
  className?: string;
17
- /** Accessible label override */
18
+ /** @deprecated Use `onCheckedChange` instead. */
19
+ onChange?: (checked: boolean) => void;
20
+ /** @deprecated Pass the native `aria-label` attribute instead. */
18
21
  ariaLabel?: string;
19
- /** HTML name attribute */
22
+ /**
23
+ * @deprecated No-op. This component renders a `<div role="checkbox">`, not a
24
+ * native `<input>`, so it cannot participate in native form submission.
25
+ * Declared only so the attribute is not forwarded to an element that rejects it.
26
+ */
20
27
  name?: string;
21
- /** HTML id attribute */
22
- id?: string;
28
+ };
29
+ export interface CheckboxProps extends CheckboxOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof CheckboxOwnProps> {
23
30
  }
24
- export interface CheckboxGroupProps {
31
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLDivElement>>;
32
+ type CheckboxGroupOwnProps = {
25
33
  /** Group label */
26
34
  label?: string;
27
35
  /** Checkbox options */
@@ -36,10 +44,14 @@ export interface CheckboxGroupProps {
36
44
  direction?: 'vertical' | 'horizontal';
37
45
  /** Component size */
38
46
  size?: 'default' | 'compact';
39
- /** Callback when selection changes */
40
- onChange?: (values: string[]) => void;
47
+ /** Called with the next selected values */
48
+ onValuesChange?: (values: string[]) => void;
41
49
  /** Additional CSS classes */
42
50
  className?: string;
51
+ /** @deprecated Use `onValuesChange` instead. */
52
+ onChange?: (values: string[]) => void;
53
+ };
54
+ export interface CheckboxGroupProps extends CheckboxGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof CheckboxGroupOwnProps> {
43
55
  }
44
- export declare const CheckboxGroup: ({ label, items, values, direction, size, onChange, className, }: CheckboxGroupProps) => React.JSX.Element;
45
- export declare const Checkbox: ({ label, checked, indeterminate, disabled, size, onChange, className, ariaLabel, }: CheckboxProps) => React.JSX.Element;
56
+ export declare const CheckboxGroup: React.ForwardRefExoticComponent<CheckboxGroupProps & React.RefAttributes<HTMLDivElement>>;
57
+ export {};