@carbonid1/design-system 5.6.1 → 5.7.1

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.
@@ -2,6 +2,7 @@ import type { ButtonProps } from './Button.types';
2
2
  declare const buttonVariants: (props?: ({
3
3
  variant?: "primary" | "attention" | "destructive" | "link" | "ghost" | "outline" | "subtle" | "danger" | null | undefined;
4
4
  size?: "default" | "small" | "large" | "icon" | "smallIcon" | "largeIcon" | null | undefined;
5
+ selected?: boolean | null | undefined;
5
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
- declare const Button: ({ className, variant, size, fullWidth, loading, disabled, children, ...props }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
7
+ declare const Button: ({ className, variant, size, selected, fullWidth, loading, disabled, children, ...props }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
7
8
  export { Button, buttonVariants };
@@ -24,11 +24,29 @@ const buttonVariants = cva("group/button inline-flex shrink-0 items-center justi
24
24
  smallIcon: 'size-6 rounded-full',
25
25
  largeIcon: 'size-12 rounded-full',
26
26
  },
27
+ selected: {
28
+ true: 'bg-primary/10 ring-1 ring-primary/20',
29
+ false: '',
30
+ },
27
31
  },
32
+ compoundVariants: [
33
+ // Hold the selection tint on hover instead of letting the variant's own hover background win.
34
+ {
35
+ selected: true,
36
+ variant: 'ghost',
37
+ className: 'hover:bg-primary/10 dark:hover:bg-primary/10',
38
+ },
39
+ {
40
+ selected: true,
41
+ variant: 'outline',
42
+ className: 'hover:bg-primary/10 dark:hover:bg-primary/10',
43
+ },
44
+ ],
28
45
  defaultVariants: {
29
46
  variant: 'ghost',
30
47
  size: 'default',
48
+ selected: false,
31
49
  },
32
50
  });
33
- const Button = ({ className, variant, size, fullWidth, loading, disabled, children, ...props }) => (_jsxs(ButtonPrimitive, { "data-slot": "button", className: cn(buttonVariants({ variant, size }), fullWidth && 'w-full justify-start', className), disabled: disabled ?? loading, "aria-busy": loading ?? undefined, ...props, children: [loading && _jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }), children] }));
51
+ const Button = ({ className, variant, size, selected, fullWidth, loading, disabled, children, ...props }) => (_jsxs(ButtonPrimitive, { "data-slot": "button", className: cn(buttonVariants({ variant, size, selected }), fullWidth && 'w-full justify-start', className), disabled: disabled ?? loading, "aria-busy": loading ?? undefined, ...props, children: [loading && _jsx(Loader2, { className: "size-4 animate-spin", "aria-hidden": "true" }), children] }));
34
52
  export { Button, buttonVariants };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carbonid1/design-system",
3
- "version": "5.6.1",
3
+ "version": "5.7.1",
4
4
  "description": "Shared React UI primitives + design tokens (themes, postcss config)",
5
5
  "repository": {
6
6
  "type": "git",
@@ -11,6 +11,7 @@ Primitives live in `@carbonid1/design-system`. **Check the package's exports and
11
11
  import {
12
12
  Badge,
13
13
  Button,
14
+ buttonVariants,
14
15
  Kbd,
15
16
  ProgressRing,
16
17
  Slider,
@@ -41,6 +42,21 @@ If you're editing `@carbonid1/design-system` itself (adding a primitive, changin
41
42
  - Tooltip: rely on defaults (`position="top"`, `delay={200}`). Only override when the default is wrong (e.g. header → `position="bottom"`, data-viz progressive disclosure → `delay={600}`). When a tooltip trigger also opens a popover, pass `disabled={open}`.
42
43
  - Icon toggle state: `<Icon fill={active ? 'currentColor' : 'none'} />` — not two different components.
43
44
 
45
+ ## Buttons & links
46
+
47
+ - **Active/selected state** — pass `selected` (toolbar toggles, segmented controls, filter chips, tabs, nav links). It applies the selection tokens (`bg-primary/10` + `ring-1 ring-primary/20`, tint held on hover); never hand-layer those classes. `selected` is visual only — set the matching ARIA yourself: `aria-pressed` on toggle buttons, `aria-current` on nav links. It rides both `Button` and `buttonVariants(...)`.
48
+ - **A link that looks like a button** — apply `buttonVariants({ variant, size, selected })` to the `Link`, not `<Button render={<Link/>}>`. Base UI's `Button` is button-semantic: rendering an `<a>` through it either warns or forces `role="button"`, which breaks navigation for screen readers. Keep the element a real link and style it:
49
+ ```tsx
50
+ <Link
51
+ href={href}
52
+ aria-current={active ? 'page' : undefined}
53
+ className={cn(buttonVariants({ variant: 'ghost', size: 'small', selected: active }))}
54
+ >
55
+ {label}
56
+ </Link>
57
+ ```
58
+ The `cn(...)` wrap is load-bearing, not cosmetic: `buttonVariants` is cva, which concatenates without merging, so only `cn` (tailwind-merge) drops the variant's own `hover:bg-accent` in favor of the `selected` tint.
59
+
44
60
  ## Visual Language
45
61
 
46
62
  - **Discrete elements** — rows/cards use `rounded-lg` with `space-y-1` gaps, never flat lists with hairline dividers