@fabio.caffarello/react-design-system 3.0.0 → 3.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.
@@ -13,39 +13,55 @@ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement
13
13
  as?: ElementType;
14
14
  href?: string;
15
15
  target?: string;
16
+ /**
17
+ * When true, render via Radix `Slot`: classes, ARIA, ref and remaining
18
+ * props are projected onto the single child element instead of an
19
+ * intrinsic `<button>`. The child keeps its own element type and props
20
+ * intact — including framework-native props like `<Link href prefetch>`.
21
+ *
22
+ * `asChild` takes precedence over `as`: if both are supplied, `as` is
23
+ * ignored and a dev-only warning is logged.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * <Button asChild variant="primary">
28
+ * <Link href="/profile" prefetch>Open profile</Link>
29
+ * </Button>
30
+ * // → <a class="…button classes" href="/profile" data-prefetch>Open profile</a>
31
+ * ```
32
+ */
33
+ asChild?: boolean;
16
34
  }
17
35
  /**
18
36
  * Button Component
19
37
  *
20
- * A styled button component with variants, sizes, and loading states.
21
- * Follows Atomic Design principles as an Atom component.
22
- * Uses Builder Pattern for class construction.
23
- * Supports polymorphic `as` prop for rendering as different elements (Link, NextLink, etc.).
38
+ * A styled button with variants, sizes, and loading states.
39
+ *
40
+ * Polymorphism two APIs:
41
+ * - `as` (legacy): swap the root element type. `<Button as={Link} href="…">`.
42
+ * - `asChild` (recommended): project Button's styling onto the single
43
+ * child element. Idiomatic Radix Slot pattern, preserves the child's
44
+ * own props and TS type (e.g. `<Link href prefetch>`). When `asChild`
45
+ * is true, `as` is ignored.
24
46
  *
25
47
  * @example
26
48
  * ```tsx
27
49
  * // Basic usage
28
- * <Button variant="primary" size="md" onClick={handleClick}>
29
- * Click me
30
- * </Button>
50
+ * <Button variant="primary" size="md" onClick={handleClick}>Click me</Button>
31
51
  *
32
52
  * // With icons
33
- * <Button leftIcon={<Icon />} rightIcon={<Icon />}>
34
- * Action
35
- * </Button>
53
+ * <Button leftIcon={<Icon />} rightIcon={<Icon />}>Action</Button>
36
54
  *
37
55
  * // Loading state
38
- * <Button isLoading loadingText="Saving...">
39
- * Save
40
- * </Button>
56
+ * <Button isLoading loadingText="Saving...">Save</Button>
41
57
  *
42
- * // As Link
43
- * <Button as={Link} href="/page">
44
- * Navigate
58
+ * // Polymorphic via asChild (preserves Next Link's TS type and native props)
59
+ * <Button asChild variant="primary">
60
+ * <Link href="/page" prefetch>Open</Link>
45
61
  * </Button>
46
62
  *
47
- * // Icon only
48
- * <Button variant="iconOnly" leftIcon={<Icon />} aria-label="Close" />
63
+ * // Polymorphic via legacy `as`
64
+ * <Button as="a" href="/page">Navigate</Button>
49
65
  * ```
50
66
  */
51
67
  declare const Button: import("react").NamedExoticComponent<ButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
@@ -1,17 +1,53 @@
1
1
  import { type ReactNode } from "react";
2
2
  export type ChipVariant = "default" | "outlined" | "filled";
3
3
  export type ChipSize = "sm" | "md" | "lg";
4
- export interface ChipProps {
4
+ interface ChipBaseProps {
5
5
  children: ReactNode;
6
6
  variant?: ChipVariant;
7
7
  size?: ChipSize;
8
- onRemove?: () => void;
9
8
  selected?: boolean;
10
9
  disabled?: boolean;
11
10
  className?: string;
12
11
  "aria-label"?: string;
13
- onClick?: () => void;
14
12
  tabIndex?: number;
15
13
  }
14
+ interface ChipStandardProps extends ChipBaseProps {
15
+ asChild?: false;
16
+ onRemove?: () => void;
17
+ onClick?: () => void;
18
+ }
19
+ /**
20
+ * `asChild` collapses the chip into a single node provided by the
21
+ * consumer (typically `<Link>`). The non-interactive frame + inner
22
+ * label-button + X structure is intentionally NOT rendered — the child
23
+ * IS the chip. As a consequence:
24
+ *
25
+ * - `onClick` and `onRemove` are forbidden at the type level. The
26
+ * child's own click handler (and `href`) is what fires; consumers
27
+ * who need a removable selected filter use the standard
28
+ * (non-asChild) form.
29
+ * - `selected` still applies the visual classes via `chipVariants`,
30
+ * but NO `aria-pressed` is emitted. Toggle-button semantics on
31
+ * `<a>` would lie — a link isn't a two-state control. Consumers
32
+ * that need the selected route surfaced to AT users should pass
33
+ * `aria-current="page"` (or similar) directly on the child Link.
34
+ *
35
+ * @see `.claude/rules/components.md` and the inline a11y notes below.
36
+ */
37
+ interface ChipAsChildProps extends ChipBaseProps {
38
+ asChild: true;
39
+ /**
40
+ * `onClick` is forbidden when `asChild` is true — the child element
41
+ * owns interaction. Pass the handler (or `href`) on the child.
42
+ */
43
+ onClick?: never;
44
+ /**
45
+ * `onRemove` is forbidden when `asChild` is true — the collapsed
46
+ * node has no slot for an X button. Use the standard (non-asChild)
47
+ * form when removal is required.
48
+ */
49
+ onRemove?: never;
50
+ }
51
+ export type ChipProps = ChipStandardProps | ChipAsChildProps;
16
52
  declare const Chip: import("react").ForwardRefExoticComponent<ChipProps & import("react").RefAttributes<HTMLDivElement>>;
17
53
  export default Chip;
@@ -5,19 +5,5 @@ export interface SeparatorProps extends HTMLAttributes<HTMLHRElement> {
5
5
  orientation?: SeparatorOrientation;
6
6
  variant?: SeparatorVariant;
7
7
  }
8
- /**
9
- * Separator Component
10
- *
11
- * A visual separator component for dividing content.
12
- * Follows Atomic Design principles as an Atom component.
13
- * Optimized with React.memo to prevent unnecessary re-renders.
14
- *
15
- * @example
16
- * ```tsx
17
- * <Separator />
18
- *
19
- * <Separator orientation="vertical" variant="dashed" />
20
- * ```
21
- */
22
8
  declare const Separator: import("react").MemoExoticComponent<({ orientation, variant, className, ...props }: SeparatorProps) => import("react").JSX.Element>;
23
9
  export default Separator;
@@ -1,11 +1,16 @@
1
+ export { default as Badge } from "./primitives/Badge/Badge";
2
+ export type { BadgeProps, BadgeSize, BadgeStyle, BadgeVariant, } from "./primitives/Badge/Badge";
1
3
  export { default as Chip } from "./primitives/Chip/Chip";
2
4
  export type { ChipProps, ChipSize, ChipVariant } from "./primitives/Chip/Chip";
3
5
  export { default as ErrorMessage } from "./primitives/ErrorMessage/ErrorMessage";
4
6
  export type { ErrorMessageProps } from "./primitives/ErrorMessage/ErrorMessage";
5
7
  export { default as Info } from "./primitives/Info/Info";
6
8
  export type { InfoProps } from "./primitives/Info/Info";
9
+ export { default as Label } from "./primitives/Label/Label";
7
10
  export { default as Progress } from "./primitives/Progress/Progress";
8
11
  export type { ProgressProps, ProgressSize, ProgressVariant, } from "./primitives/Progress/Progress";
12
+ export { default as Separator } from "./primitives/Separator/Separator";
13
+ export type { SeparatorOrientation, SeparatorProps, SeparatorVariant, } from "./primitives/Separator/Separator";
9
14
  export { default as Skeleton } from "./primitives/Skeleton/Skeleton";
10
15
  export type { SkeletonProps } from "./primitives/Skeleton/Skeleton";
11
16
  export { default as Spinner } from "./primitives/Spinner/Spinner";
@@ -20,6 +25,7 @@ export { default as AutocompleteOption } from "./components/Autocomplete/Autocom
20
25
  export type { AutocompleteOptionProps, AutocompleteOptionType, } from "./components/Autocomplete/AutocompleteOption";
21
26
  export { default as Breadcrumb } from "./components/Breadcrumb/Breadcrumb";
22
27
  export type { BreadcrumbItem } from "./components/Breadcrumb/Breadcrumb";
28
+ export { default as Card } from "./components/Card/Card";
23
29
  export { DialogHeader } from "./components/Dialog/DialogHeader";
24
30
  export type { DialogHeaderProps } from "./components/Dialog/DialogHeader";
25
31
  export { DialogFooter } from "./components/Dialog/DialogFooter";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fabio.caffarello/react-design-system",
3
3
  "private": false,
4
- "version": "3.0.0",
4
+ "version": "3.2.0",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -77,6 +77,7 @@
77
77
  }
78
78
  },
79
79
  "dependencies": {
80
+ "@radix-ui/react-slot": "^1.2.4",
80
81
  "@tailwindcss/postcss": "^4.1.16",
81
82
  "class-variance-authority": "^0.7.1",
82
83
  "clsx": "^2.1.1",