@pycolors/ui 1.1.1 → 1.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.
package/README.md CHANGED
@@ -65,8 +65,8 @@ This repository is a **distribution mirror**.
65
65
 
66
66
  - NPM publishing happens from the **PyColors monorepo** (Changesets)
67
67
  - This mirror receives version bumps + CHANGELOG via sync PRs
68
- - A GitHub Release is automatically created when `package.json` and
69
- `CHANGELOG.md` change on `main`
68
+ - A GitHub Release is created only when the mirror `main` branch and npm both
69
+ expose the same `@pycolors/ui` version
70
70
 
71
71
  If you want to propose changes, contribute to the monorepo:
72
72
  https://github.com/pycolors-io/pycolors/tree/main/packages/ui
@@ -21,7 +21,7 @@ export function Alert({ className, variant, ariaLive = 'polite', ...props }) {
21
21
  : ariaLive === 'polite'
22
22
  ? 'status'
23
23
  : undefined;
24
- return (_jsx("div", { "data-slot": "alert", role: role, "aria-live": ariaLive === 'off' ? undefined : ariaLive, className: cn(alertVariants({ variant }), className), ...props }));
24
+ return (_jsx("div", { "data-slot": "alert", ...props, role: role, "aria-live": ariaLive === 'off' ? undefined : ariaLive, className: cn(alertVariants({ variant }), className) }));
25
25
  }
26
26
  export function AlertTitle({ className, ...props }) {
27
27
  return (_jsx("h5", { "data-slot": "alert-title", className: cn('mb-1 font-medium leading-none tracking-tight', className), ...props }));
@@ -12,7 +12,7 @@ const badgeVariants = cva('inline-flex items-center gap-1 rounded-full border px
12
12
  secondary: 'border-transparent bg-secondary text-secondary-foreground',
13
13
  muted: 'border-transparent bg-muted text-muted-foreground',
14
14
  outline: 'border-border bg-background text-foreground',
15
- success: 'border-transparent bg-success text-success-foreground text-primary-foreground',
15
+ success: 'border-transparent bg-success text-success-foreground',
16
16
  warning: 'border-transparent bg-warning text-warning-foreground',
17
17
  destructive: 'border-transparent bg-destructive text-destructive-foreground',
18
18
  },
@@ -4,15 +4,42 @@ export declare const cardVariants: (props?: ({
4
4
  variant?: "default" | "muted" | "transparent" | null | undefined;
5
5
  interactive?: boolean | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
- export interface CardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof cardVariants> {
7
+ type CardVariantProps = VariantProps<typeof cardVariants>;
8
+ export interface CardProps extends React.HTMLAttributes<HTMLDivElement>, CardVariantProps {
8
9
  /**
9
- * Render the Card as another element (e.g. <a />, <section />) via Radix Slot.
10
- * Useful for clickable cards while keeping consistent styling.
10
+ * Renders the card through Radix Slot.
11
+ *
12
+ * Use this when the card must behave as a native interactive element:
13
+ *
14
+ * @example
15
+ * <Card asChild interactive>
16
+ * <a href="/products">...</a>
17
+ * </Card>
18
+ *
19
+ * @example
20
+ * <Card asChild interactive>
21
+ * <button type="button" onClick={handleClick}>...</button>
22
+ * </Card>
11
23
  */
12
24
  asChild?: boolean;
25
+ /**
26
+ * Applies interactive visual styles only.
27
+ *
28
+ * This prop does not add `role`, `tabIndex`, `onClick`, or keyboard
29
+ * handlers. Use `asChild` with a native `<a>` or `<button>` to provide
30
+ * accessible interaction semantics.
31
+ */
32
+ interactive?: boolean;
13
33
  }
14
34
  export type CardVariant = NonNullable<CardProps['variant']>;
15
35
  export type CardInteractive = NonNullable<CardProps['interactive']>;
36
+ /**
37
+ * Structural card primitive compatible with React Server Components.
38
+ *
39
+ * Card deliberately does not synthesize event handlers or accessibility
40
+ * semantics. Interactive behavior must be provided by the underlying native
41
+ * element through `asChild`.
42
+ */
16
43
  export declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
17
44
  export type CardHeaderProps = React.HTMLAttributes<HTMLDivElement>;
18
45
  export declare function CardHeader({ className, ...props }: CardHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -24,4 +51,5 @@ export type CardContentProps = React.HTMLAttributes<HTMLDivElement>;
24
51
  export declare function CardContent({ className, ...props }: CardContentProps): import("react/jsx-runtime").JSX.Element;
25
52
  export type CardFooterProps = React.HTMLAttributes<HTMLDivElement>;
26
53
  export declare function CardFooter({ className, ...props }: CardFooterProps): import("react/jsx-runtime").JSX.Element;
54
+ export {};
27
55
  //# sourceMappingURL=card.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,eAAO,MAAM,YAAY;;;8EAqBxB,CAAC;AAIF,MAAM,WAAW,SACf,SACE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,YAAY,CAAC,OAAO,YAAY,CAAC;IACnC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC;AAEpE,eAAO,MAAM,IAAI,kFAmBhB,CAAC;AAIF,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEnE,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,2CAQlE;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAEtE,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,2CAWhE;AAED,MAAM,MAAM,oBAAoB,GAC9B,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAE7C,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,oBAAoB,2CAQtB;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEpE,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,gBAAgB,2CAQlB;AAED,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEnE,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,2CAQlE"}
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,eAAO,MAAM,YAAY;;;8EA2BxB,CAAC;AAEF,KAAK,gBAAgB,GAAG,YAAY,CAAC,OAAO,YAAY,CAAC,CAAC;AAE1D,MAAM,WAAW,SACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,gBAAgB;IAC9D;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC;AAEpE;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,kFA4BhB,CAAC;AAIF,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEnE,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,2CAQlE;AAED,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC;AAEtE,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,2CAWhE;AAED,MAAM,MAAM,oBAAoB,GAC9B,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAE7C,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,oBAAoB,2CAQtB;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEpE,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,gBAAgB,2CAQlB;AAED,MAAM,MAAM,eAAe,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;AAEnE,wBAAgB,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,2CAQlE"}
@@ -11,9 +11,16 @@ export const cardVariants = cva('rounded-lg border text-card-foreground', {
11
11
  transparent: 'bg-transparent',
12
12
  },
13
13
  interactive: {
14
- false: '',
15
- true: 'cursor-pointer transition-colors hover:bg-accent/40 ' +
16
- 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
14
+ false: null,
15
+ true: [
16
+ 'cursor-pointer',
17
+ 'transition-colors',
18
+ 'hover:bg-accent/40',
19
+ 'focus-visible:outline-none',
20
+ 'focus-visible:ring-2',
21
+ 'focus-visible:ring-ring',
22
+ 'focus-visible:ring-offset-2',
23
+ ],
17
24
  },
18
25
  },
19
26
  defaultVariants: {
@@ -21,9 +28,19 @@ export const cardVariants = cva('rounded-lg border text-card-foreground', {
21
28
  interactive: false,
22
29
  },
23
30
  });
24
- export const Card = React.forwardRef(({ className, variant, interactive, asChild = false, ...props }, ref) => {
25
- const Comp = asChild ? Slot : 'div';
26
- return (_jsx(Comp, { ref: ref, "data-slot": "card", className: cn(cardVariants({ variant, interactive }), className), ...props }));
31
+ /**
32
+ * Structural card primitive compatible with React Server Components.
33
+ *
34
+ * Card deliberately does not synthesize event handlers or accessibility
35
+ * semantics. Interactive behavior must be provided by the underlying native
36
+ * element through `asChild`.
37
+ */
38
+ export const Card = React.forwardRef(({ asChild = false, className, variant, interactive = false, ...props }, ref) => {
39
+ const Component = asChild ? Slot : 'div';
40
+ return (_jsx(Component, { ref: ref, "data-slot": "card", className: cn(cardVariants({
41
+ variant,
42
+ interactive,
43
+ }), className), ...props }));
27
44
  });
28
45
  Card.displayName = 'Card';
29
46
  export function CardHeader({ className, ...props }) {
@@ -1,9 +1,10 @@
1
- import * as React from 'react';
1
+ import * as React from "react";
2
2
  export interface EmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
3
3
  icon?: React.ReactNode;
4
4
  title: string;
5
5
  description?: string;
6
6
  action?: React.ReactNode;
7
+ ariaLive?: "off" | "polite" | "assertive";
7
8
  }
8
- export declare function EmptyState({ icon, title, description, action, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function EmptyState({ icon, title, description, action, ariaLive, className, ...props }: EmptyStateProps): import("react/jsx-runtime").JSX.Element;
9
10
  //# sourceMappingURL=empty-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../src/components/ui/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC3E,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,EACN,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,2CAyBjB"}
1
+ {"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../src/components/ui/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC3E,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;CAC3C;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,WAAW,EACX,MAAM,EACN,QAAmB,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,eAAe,2CA+BjB"}
@@ -1,5 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from '../../lib/utils.js';
3
- export function EmptyState({ icon, title, description, action, className, ...props }) {
4
- return (_jsxs("div", { role: "status", className: cn('flex w-full flex-col items-center justify-center rounded-lg border border-dashed border-border p-8 text-center', className), ...props, children: [icon && (_jsx("div", { className: "mb-4 text-muted-foreground", children: icon })), _jsx("h3", { className: "text-sm font-medium", children: title }), description && (_jsx("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: description })), action && _jsx("div", { className: "mt-4", children: action })] }));
2
+ import { cn } from "../../lib/utils.js";
3
+ export function EmptyState({ icon, title, description, action, ariaLive = "polite", className, ...props }) {
4
+ const role = ariaLive === "assertive"
5
+ ? "alert"
6
+ : ariaLive === "polite"
7
+ ? "status"
8
+ : undefined;
9
+ return (_jsxs("div", { ...props, role: role, "aria-live": ariaLive === "off" ? undefined : ariaLive, className: cn("flex w-full flex-col items-center justify-center rounded-lg border border-dashed border-border p-8 text-center", className), children: [icon && _jsx("div", { className: "mb-4 text-muted-foreground", children: icon }), _jsx("h3", { className: "text-sm font-medium", children: title }), description && (_jsx("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: description })), action && _jsx("div", { className: "mt-4", children: action })] }));
5
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,aAAa;;;8EAmBlB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,MAAM,WAAW,UACf,SACE,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,EACzD,YAAY,CAAC,OAAO,aAAa,CAAC;IACpC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,QAAA,MAAM,KAAK,qFAoGV,CAAC;AAIF,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,aAAa;;;8EAmBlB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,MAAM,WAAW,UACf,SACE,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC,EACzD,YAAY,CAAC,OAAO,aAAa,CAAC;IACpC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC5B;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,QAAA,MAAM,KAAK,qFAgHV,CAAC;AAIF,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC"}
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { cn } from '../../lib/utils.js';
6
- const inputVariants = cva('flex w-full items-center gap-2 rounded-md border bg-background text-sm ring-offset-background transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', {
6
+ const inputVariants = cva('flex w-full items-center gap-2 rounded-md border bg-background text-sm ring-offset-background transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2', {
7
7
  variants: {
8
8
  size: {
9
9
  sm: 'h-9 px-3',
@@ -20,18 +20,25 @@ const inputVariants = cva('flex w-full items-center gap-2 rounded-md border bg-b
20
20
  hasError: false,
21
21
  },
22
22
  });
23
- const Input = React.forwardRef(({ label, helperText, error, leftIcon, rightIcon, className, size, id, disabled, required, ...props }, ref) => {
23
+ const Input = React.forwardRef(({ label, helperText, error, leftIcon, rightIcon, className, size, id, disabled, required, 'aria-describedby': consumerDescribedBy, ...props }, ref) => {
24
24
  const generatedId = React.useId();
25
25
  const inputId = id ?? generatedId;
26
- const describedByIds = [];
26
+ const internalDescribedByIds = [];
27
27
  if (helperText && !error)
28
- describedByIds.push(`${inputId}-helper`);
28
+ internalDescribedByIds.push(`${inputId}-helper`);
29
29
  if (error)
30
- describedByIds.push(`${inputId}-error`);
31
- const describedBy = describedByIds.length > 0
32
- ? describedByIds.join(' ')
33
- : undefined;
34
- return (_jsxs("div", { className: "w-full", children: [label && (_jsxs("label", { htmlFor: inputId, className: "mb-1 block text-sm font-medium text-foreground", children: [label, required ? (_jsx("span", { className: "ml-1 text-destructive", children: "*" })) : null] })), _jsxs("div", { className: cn(inputVariants({ size, hasError: !!error }), className), children: [leftIcon && (_jsx("span", { className: "inline-flex shrink-0 items-center justify-center text-muted-foreground", children: leftIcon })), _jsx("input", { id: inputId, ref: ref, disabled: disabled, required: required, "aria-invalid": !!error, "aria-describedby": describedBy, "aria-errormessage": error ? `${inputId}-error` : undefined, "aria-required": required ? true : undefined, className: cn('flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground', !leftIcon && 'pl-1', !rightIcon && 'pr-1'), ...props }), rightIcon && (_jsx("span", { className: "inline-flex shrink-0 items-center justify-center text-muted-foreground", children: rightIcon }))] }), helperText && !error && (_jsx("p", { id: `${inputId}-helper`, className: "mt-1 text-xs text-muted-foreground", children: helperText })), error && (_jsx("p", { id: `${inputId}-error`, className: "mt-1 text-xs text-destructive", children: error }))] }));
30
+ internalDescribedByIds.push(`${inputId}-error`);
31
+ // Compose the consumer's own aria-describedby (if any) with the ids this
32
+ // component owns, rather than letting either side silently clobber the
33
+ // other — both descriptions are legitimate and should be announced.
34
+ const describedBy = [...internalDescribedByIds, consumerDescribedBy]
35
+ .filter(Boolean)
36
+ .join(' ') || undefined;
37
+ return (_jsxs("div", { className: "w-full", children: [label && (_jsxs("label", { htmlFor: inputId, className: "mb-1 block text-sm font-medium text-foreground", children: [label, required ? (_jsx("span", { className: "ml-1 text-destructive", children: "*" })) : null] })), _jsxs("div", { className: cn(inputVariants({ size, hasError: !!error }),
38
+ // The disabled attribute lives on the inner <input>, so the
39
+ // wrapper (which owns the border/background) can never match
40
+ // the `disabled:` pseudo-class — drive it explicitly instead.
41
+ disabled && 'cursor-not-allowed opacity-50', className), children: [leftIcon && (_jsx("span", { className: "inline-flex shrink-0 items-center justify-center text-muted-foreground", children: leftIcon })), _jsx("input", { id: inputId, ref: ref, disabled: disabled, required: required, className: cn('flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground', !leftIcon && 'pl-1', !rightIcon && 'pr-1'), ...props, "aria-invalid": !!error, "aria-describedby": describedBy, "aria-errormessage": error ? `${inputId}-error` : undefined, "aria-required": required ? true : undefined }), rightIcon && (_jsx("span", { className: "inline-flex shrink-0 items-center justify-center text-muted-foreground", children: rightIcon }))] }), helperText && !error && (_jsx("p", { id: `${inputId}-helper`, className: "mt-1 text-xs text-muted-foreground", children: helperText })), error && (_jsx("p", { id: `${inputId}-error`, role: "alert", className: "mt-1 text-xs text-destructive", children: error }))] }));
35
42
  });
36
43
  Input.displayName = 'Input';
37
44
  export { Input, inputVariants };
@@ -1 +1 @@
1
- {"version":3,"file":"password-input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/password-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,UAAU,EACV,MAAM,GAAG,WAAW,CACrB,CAAC;AAEF,eAAO,MAAM,aAAa,6FAoCxB,CAAC"}
1
+ {"version":3,"file":"password-input.d.ts","sourceRoot":"","sources":["../../../src/components/ui/password-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,UAAU,EACV,MAAM,GAAG,WAAW,CACrB,CAAC;AAEF,eAAO,MAAM,aAAa,6FAwCxB,CAAC"}
@@ -3,8 +3,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import * as React from 'react';
4
4
  import { Eye, EyeOff } from 'lucide-react';
5
5
  import { Input } from './input.js';
6
- export const PasswordInput = React.forwardRef((props, ref) => {
6
+ export const PasswordInput = React.forwardRef(({ disabled, ...props }, ref) => {
7
7
  const [visible, setVisible] = React.useState(false);
8
- return (_jsx(Input, { ...props, ref: ref, type: visible ? 'text' : 'password', rightIcon: _jsx("button", { type: "button", "aria-label": visible ? 'Hide password' : 'Show password', "aria-pressed": visible, onClick: () => setVisible((v) => !v), className: "\n rounded-sm p-1\n text-muted-foreground\n hover:text-foreground\n focus-visible:outline-none\n focus-visible:ring-2\n focus-visible:ring-ring\n focus-visible:ring-offset-1\n ", children: visible ? (_jsx(EyeOff, { className: "h-4 w-4", "aria-hidden": "true" })) : (_jsx(Eye, { className: "h-4 w-4", "aria-hidden": "true" })) }) }));
8
+ return (_jsx(Input, { ...props, disabled: disabled, ref: ref, type: visible ? 'text' : 'password', rightIcon: _jsx("button", { type: "button", disabled: disabled, "aria-label": visible ? 'Hide password' : 'Show password', "aria-pressed": visible, onClick: () => setVisible((v) => !v), className: "\n rounded-sm p-1\n text-muted-foreground\n hover:text-foreground\n focus-visible:outline-none\n focus-visible:ring-2\n focus-visible:ring-ring\n focus-visible:ring-offset-1\n disabled:pointer-events-none\n disabled:opacity-50\n ", children: visible ? (_jsx(EyeOff, { className: "h-4 w-4", "aria-hidden": "true" })) : (_jsx(Eye, { className: "h-4 w-4", "aria-hidden": "true" })) }) }));
9
9
  });
10
10
  PasswordInput.displayName = 'PasswordInput';
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/ui/skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,MAAc,EACd,GAAG,KAAK,EACT,EAAE,aAAa,2CAYf"}
1
+ {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/ui/skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,MAAc,EACd,GAAG,KAAK,EACT,EAAE,aAAa,2CAef"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cn } from '../../lib/utils.js';
3
3
  export function Skeleton({ className, circle = false, ...props }) {
4
- return (_jsx("div", { "aria-hidden": "true", className: cn('animate-pulse bg-muted', circle ? 'rounded-full' : 'rounded-md', className), ...props }));
4
+ return (_jsx("div", { className: cn('animate-pulse motion-reduce:animate-none bg-muted', circle ? 'rounded-full' : 'rounded-md', className), ...props, "aria-hidden": "true" }));
5
5
  }
@@ -1,9 +1,9 @@
1
- import * as React from 'react';
1
+ import * as React from "react";
2
2
  export declare function Table({ className, ...props }: React.HTMLAttributes<HTMLTableElement>): import("react/jsx-runtime").JSX.Element;
3
3
  export declare function TableHeader({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>): import("react/jsx-runtime").JSX.Element;
4
4
  export declare function TableBody({ className, ...props }: React.HTMLAttributes<HTMLTableSectionElement>): import("react/jsx-runtime").JSX.Element;
5
5
  export declare function TableRow({ className, ...props }: React.HTMLAttributes<HTMLTableRowElement>): import("react/jsx-runtime").JSX.Element;
6
- export declare function TableHead({ className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>): import("react/jsx-runtime").JSX.Element;
6
+ export declare function TableHead({ scope, className, ...props }: React.ThHTMLAttributes<HTMLTableCellElement>): import("react/jsx-runtime").JSX.Element;
7
7
  export declare function TableCell({ className, ...props }: React.TdHTMLAttributes<HTMLTableCellElement>): import("react/jsx-runtime").JSX.Element;
8
8
  export declare function TableCaption({ className, ...props }: React.HTMLAttributes<HTMLTableCaptionElement>): import("react/jsx-runtime").JSX.Element;
9
9
  export declare function TableEmpty({ colSpan, title, description, }: {
@@ -11,7 +11,9 @@ export declare function TableEmpty({ colSpan, title, description, }: {
11
11
  title?: string;
12
12
  description?: string;
13
13
  }): import("react/jsx-runtime").JSX.Element;
14
- export declare function TableLoading({ colSpan }: {
14
+ export interface TableLoadingProps {
15
15
  colSpan: number;
16
- }): import("react/jsx-runtime").JSX.Element;
16
+ ariaLive?: "off" | "polite" | "assertive";
17
+ }
18
+ export declare function TableLoading({ colSpan, ariaLive, }: TableLoadingProps): import("react/jsx-runtime").JSX.Element;
17
19
  //# sourceMappingURL=table.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/ui/table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,2CASxC;AAED,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAI/C;AAED,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAO/C;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC,2CAU3C;AAED,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,2CAU9C;AAED,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,2CAI9C;AAED,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAO/C;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAoB,EACpB,WAAgE,GACjE,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,2CAaA;AAED,wBAAgB,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,2CAW5D"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/components/ui/table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,wBAAgB,KAAK,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC,2CASxC;AAED,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAE/C;AAED,wBAAgB,SAAS,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAI/C;AAED,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,mBAAmB,CAAC,2CAU3C;AAGD,wBAAgB,SAAS,CAAC,EACxB,KAAa,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,2CAY9C;AAED,wBAAgB,SAAS,CAAC,EAExB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,2CAE9C;AAED,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,uBAAuB,CAAC,2CAO/C;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAoB,EACpB,WAAgE,GACjE,EAAE;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,2CAaA;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,WAAW,CAAC;CAC3C;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAmB,GACpB,EAAE,iBAAiB,2CAyBnB"}
@@ -1,29 +1,38 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from '../../lib/utils.js';
2
+ import { cn } from "../../lib/utils.js";
3
3
  export function Table({ className, ...props }) {
4
- return (_jsx("div", { className: "w-full overflow-auto rounded-lg border border-border/60", children: _jsx("table", { className: cn('w-full caption-bottom text-sm', className), ...props }) }));
4
+ return (_jsx("div", { className: "w-full overflow-auto rounded-lg border border-border/60", children: _jsx("table", { className: cn("w-full caption-bottom text-sm", className), ...props }) }));
5
5
  }
6
6
  export function TableHeader({ className, ...props }) {
7
- return (_jsx("thead", { className: cn('bg-muted/40', className), ...props }));
7
+ return _jsx("thead", { className: cn("bg-muted/40", className), ...props });
8
8
  }
9
9
  export function TableBody({ className, ...props }) {
10
- return (_jsx("tbody", { className: cn('[&_tr:last-child]:border-0', className), ...props }));
10
+ return (_jsx("tbody", { className: cn("[&_tr:last-child]:border-0", className), ...props }));
11
11
  }
12
12
  export function TableRow({ className, ...props }) {
13
- return (_jsx("tr", { className: cn('border-b border-border/60 transition-colors hover:bg-accent/30', className), ...props }));
13
+ return (_jsx("tr", { className: cn("border-b border-border/60 transition-colors hover:bg-accent/30", className), ...props }));
14
14
  }
15
- export function TableHead({ className, ...props }) {
16
- return (_jsx("th", { className: cn('h-10 px-4 text-left align-middle font-medium text-muted-foreground', className), ...props }));
15
+ /* eslint-disable react/prop-types -- TypeScript validates intrinsic table header props. */
16
+ export function TableHead({ scope = "col", className, ...props }) {
17
+ /* eslint-enable react/prop-types */
18
+ return (_jsx("th", { scope: scope, className: cn("h-10 px-4 text-left align-middle font-medium text-muted-foreground", className), ...props }));
17
19
  }
18
- export function TableCell({ className, ...props }) {
19
- return (_jsx("td", { className: cn('p-4 align-middle', className), ...props }));
20
+ export function TableCell({
21
+ // eslint-disable-next-line react/prop-types -- TypeScript validates intrinsic table cell props.
22
+ className, ...props }) {
23
+ return _jsx("td", { className: cn("p-4 align-middle", className), ...props });
20
24
  }
21
25
  export function TableCaption({ className, ...props }) {
22
- return (_jsx("caption", { className: cn('mt-3 text-sm text-muted-foreground', className), ...props }));
26
+ return (_jsx("caption", { className: cn("mt-3 text-sm text-muted-foreground", className), ...props }));
23
27
  }
24
- export function TableEmpty({ colSpan, title = 'No results', description = 'Try adjusting your filters or create a new item.', }) {
28
+ export function TableEmpty({ colSpan, title = "No results", description = "Try adjusting your filters or create a new item.", }) {
25
29
  return (_jsx(TableRow, { className: "hover:bg-transparent", children: _jsx(TableCell, { colSpan: colSpan, className: "py-10", children: _jsxs("div", { className: "text-center", children: [_jsx("div", { className: "font-medium", children: title }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: description })] }) }) }));
26
30
  }
27
- export function TableLoading({ colSpan }) {
28
- return (_jsx(TableRow, { className: "hover:bg-transparent", children: _jsx(TableCell, { colSpan: colSpan, className: "py-10", children: _jsxs("div", { className: "flex items-center justify-center gap-2 text-sm text-muted-foreground", children: [_jsx("span", { className: "inline-block size-4 animate-spin rounded-full border-2 border-muted-foreground/30 border-t-muted-foreground" }), "Loading\u2026"] }) }) }));
31
+ export function TableLoading({ colSpan, ariaLive = "polite", }) {
32
+ const role = ariaLive === "assertive"
33
+ ? "alert"
34
+ : ariaLive === "polite"
35
+ ? "status"
36
+ : undefined;
37
+ return (_jsx(TableRow, { className: "hover:bg-transparent", children: _jsx(TableCell, { colSpan: colSpan, className: "py-10", children: _jsxs("div", { role: role, "aria-live": ariaLive === "off" ? undefined : ariaLive, className: "flex items-center justify-center gap-2 text-sm text-muted-foreground", children: [_jsx("span", { "aria-hidden": "true", className: "inline-block size-4 animate-spin rounded-full border-2 border-muted-foreground/30 border-t-muted-foreground" }), "Loading\u2026"] }) }) }));
29
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/components/ui/textarea.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,gBAAgB;;;;8EA0BrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC9C,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,UAAU,GACV,YAAY,GACZ,MAAM,CAAC;AAEX,MAAM,WAAW,aACf,SACE,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,EAC/D,YAAY,CAAC,OAAO,gBAAgB,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,QAAA,MAAM,QAAQ,2FA0Fb,CAAC;AAIF,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"textarea.d.ts","sourceRoot":"","sources":["../../../src/components/ui/textarea.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIlE,QAAA,MAAM,gBAAgB;;;;8EA0BrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC9C,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,UAAU,GACV,YAAY,GACZ,MAAM,CAAC;AAEX,MAAM,WAAW,aACf,SACE,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,EAC/D,YAAY,CAAC,OAAO,gBAAgB,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,QAAA,MAAM,QAAQ,2FAkGb,CAAC;AAIF,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC"}
@@ -27,24 +27,27 @@ const textareaVariants = cva('flex min-h-24 w-full rounded-md border bg-backgrou
27
27
  resize: 'vertical',
28
28
  },
29
29
  });
30
- const Textarea = React.forwardRef(({ label, helperText, error, className, size, resize, id, disabled, required, ...props }, ref) => {
30
+ const Textarea = React.forwardRef(({ label, helperText, error, className, size, resize, id, disabled, required, 'aria-describedby': consumerDescribedBy, ...props }, ref) => {
31
31
  const generatedId = React.useId();
32
32
  const textareaId = id ?? generatedId;
33
- const describedByIds = [];
33
+ const internalDescribedByIds = [];
34
34
  if (helperText && !error) {
35
- describedByIds.push(`${textareaId}-helper`);
35
+ internalDescribedByIds.push(`${textareaId}-helper`);
36
36
  }
37
37
  if (error) {
38
- describedByIds.push(`${textareaId}-error`);
38
+ internalDescribedByIds.push(`${textareaId}-error`);
39
39
  }
40
- const describedBy = describedByIds.length > 0
41
- ? describedByIds.join(' ')
42
- : undefined;
43
- return (_jsxs("div", { className: "w-full", children: [label ? (_jsxs("label", { htmlFor: textareaId, className: "mb-1 block text-sm font-medium text-foreground", children: [label, required ? (_jsx("span", { className: "ml-1 text-destructive", children: "*" })) : null] })) : null, _jsx("textarea", { id: textareaId, ref: ref, disabled: disabled, required: required, "aria-invalid": !!error, "aria-describedby": describedBy, "aria-errormessage": error ? `${textareaId}-error` : undefined, "aria-required": required ? true : undefined, className: cn(textareaVariants({
40
+ // Compose the consumer's own aria-describedby (if any) with the ids this
41
+ // component owns, rather than letting either side silently clobber the
42
+ // other — both descriptions are legitimate and should be announced.
43
+ const describedBy = [...internalDescribedByIds, consumerDescribedBy]
44
+ .filter(Boolean)
45
+ .join(' ') || undefined;
46
+ return (_jsxs("div", { className: "w-full", children: [label ? (_jsxs("label", { htmlFor: textareaId, className: "mb-1 block text-sm font-medium text-foreground", children: [label, required ? (_jsx("span", { className: "ml-1 text-destructive", children: "*" })) : null] })) : null, _jsx("textarea", { id: textareaId, ref: ref, disabled: disabled, required: required, className: cn(textareaVariants({
44
47
  size,
45
48
  resize,
46
49
  hasError: !!error,
47
- }), className), ...props }), helperText && !error ? (_jsx("p", { id: `${textareaId}-helper`, className: "mt-1 text-xs text-muted-foreground", children: helperText })) : null, error ? (_jsx("p", { id: `${textareaId}-error`, className: "mt-1 text-xs text-destructive", children: error })) : null] }));
50
+ }), className), ...props, "aria-invalid": !!error, "aria-describedby": describedBy, "aria-errormessage": error ? `${textareaId}-error` : undefined, "aria-required": required ? true : undefined }), helperText && !error ? (_jsx("p", { id: `${textareaId}-helper`, className: "mt-1 text-xs text-muted-foreground", children: helperText })) : null, error ? (_jsx("p", { id: `${textareaId}-error`, role: "alert", className: "mt-1 text-xs text-destructive", children: error })) : null] }));
48
51
  });
49
52
  Textarea.displayName = 'Textarea';
50
53
  export { Textarea, textareaVariants };
@@ -1 +1 @@
1
- {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/components/ui/toast.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,aAAa;;8EAkBlB,CAAC;AAEF,eAAO,MAAM,aAAa,6CAA0B,CAAC;AACrD,eAAO,MAAM,aAAa,4GAA0B,CAAC;AAErD,MAAM,WAAW,UACf,SACE,KAAK,CAAC,wBAAwB,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,EAC1D,YAAY,CAAC,OAAO,aAAa,CAAC;CAAG;AAEzC,eAAO,MAAM,KAAK,kFAShB,CAAC;AAGH,eAAO,MAAM,UAAU,uGAAuB,CAAC;AAC/C,eAAO,MAAM,gBAAgB,6GAA6B,CAAC;AAC3D,eAAO,MAAM,UAAU,0GAAuB,CAAC"}
1
+ {"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../../../src/components/ui/toast.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGlE,QAAA,MAAM,aAAa;;8EAkBlB,CAAC;AAEF,eAAO,MAAM,aAAa,6CAA0B,CAAC;AACrD,eAAO,MAAM,aAAa,4GAA0B,CAAC;AAErD,MAAM,WAAW,UACf,SACE,KAAK,CAAC,wBAAwB,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,EAC1D,YAAY,CAAC,OAAO,aAAa,CAAC;CAAG;AAgBzC,eAAO,MAAM,KAAK,kFAchB,CAAC;AAGH,eAAO,MAAM,UAAU,uGAAuB,CAAC;AAC/C,eAAO,MAAM,gBAAgB,6GAA6B,CAAC;AAC3D,eAAO,MAAM,UAAU,0GAAuB,CAAC"}
@@ -19,7 +19,20 @@ const toastVariants = cva('pointer-events-auto relative flex w-full items-center
19
19
  });
20
20
  export const ToastProvider = ToastPrimitive.Provider;
21
21
  export const ToastViewport = ToastPrimitive.Viewport;
22
- export const Toast = React.forwardRef(({ className, variant, ...props }, ref) => (_jsx(ToastPrimitive.Root, { ref: ref, className: cn(toastVariants({ variant }), className), ...props })));
22
+ // Radix announces `type="foreground"` toasts at aria-live="assertive" and
23
+ // `type="background"` toasts at "polite". Only genuinely urgent variants
24
+ // should interrupt; routine confirmations should announce politely. An
25
+ // explicit `type` prop from the consumer always wins over this default.
26
+ const toastTypeByVariant = {
27
+ default: 'background',
28
+ success: 'background',
29
+ warning: 'foreground',
30
+ destructive: 'foreground',
31
+ };
32
+ export const Toast = React.forwardRef(({ className, variant, type, ...props }, ref) => {
33
+ const resolvedVariant = variant ?? 'default';
34
+ return (_jsx(ToastPrimitive.Root, { ref: ref, type: type ?? toastTypeByVariant[resolvedVariant], className: cn(toastVariants({ variant }), className), ...props }));
35
+ });
23
36
  Toast.displayName = 'Toast';
24
37
  export const ToastTitle = ToastPrimitive.Title;
25
38
  export const ToastDescription = ToastPrimitive.Description;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pycolors/ui",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Production-ready UI primitives for modern SaaS apps (Radix + Tailwind-friendly).",
5
5
  "keywords": [
6
6
  "pycolors",
@@ -66,19 +66,25 @@
66
66
  "devDependencies": {
67
67
  "@pycolors/eslint-config": "^1.0.0",
68
68
  "@pycolors/typescript-config": "^1.0.0",
69
+ "@testing-library/jest-dom": "^6.9.1",
70
+ "@testing-library/react": "^16.3.2",
69
71
  "@types/node": "^22.15.3",
70
72
  "@types/react": "19.2.2",
71
73
  "@types/react-dom": "19.2.2",
72
74
  "eslint": "^9.39.1",
73
- "typescript": "5.9.2"
75
+ "jsdom": "^29.1.1",
76
+ "typescript": "5.9.2",
77
+ "vitest": "^4.1.10",
78
+ "vitest-axe": "1.0.0-pre.5"
74
79
  },
75
80
  "scripts": {
76
81
  "clean": "rm -rf dist",
77
- "build": "tsc -p tsconfig.json",
82
+ "build": "tsc -p tsconfig.build.json",
78
83
  "lint": "eslint . --max-warnings 0",
84
+ "test": "vitest run --config vitest.config.ts",
79
85
  "types:check": "tsc --noEmit",
80
- "verify": "pnpm lint && pnpm types:check && pnpm build",
86
+ "verify": "pnpm test && pnpm lint && pnpm types:check && pnpm build",
81
87
  "generate:component": "turbo gen react-component",
82
- "release": "pnpm clean && pnpm build:ts && pnpm publish --access public"
88
+ "release": "pnpm clean && pnpm build && pnpm publish --access public"
83
89
  }
84
90
  }