@neasg/design-system 0.3.0 → 0.4.3

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 (94) hide show
  1. package/README.md +37 -1
  2. package/dist/alert.d.ts +15 -0
  3. package/dist/alert.js +24 -0
  4. package/dist/avatar.d.ts +13 -4
  5. package/dist/avatar.js +24 -7
  6. package/dist/back-button.d.ts +6 -0
  7. package/dist/back-button.js +8 -0
  8. package/dist/badge.d.ts +1 -1
  9. package/dist/breadcrumb.js +2 -2
  10. package/dist/button.d.ts +2 -2
  11. package/dist/button.js +3 -4
  12. package/dist/card.d.ts +3 -0
  13. package/dist/card.js +9 -2
  14. package/dist/checkbox.d.ts +13 -0
  15. package/dist/checkbox.js +29 -0
  16. package/dist/collapsible.d.ts +19 -0
  17. package/dist/collapsible.js +20 -0
  18. package/dist/command-search.js +2 -2
  19. package/dist/command.d.ts +1 -1
  20. package/dist/copy-button.d.ts +19 -0
  21. package/dist/copy-button.js +31 -0
  22. package/dist/date-input.js +2 -2
  23. package/dist/dialog-primitive.js +1 -1
  24. package/dist/draggable-tabs.js +1 -1
  25. package/dist/drawer.js +1 -1
  26. package/dist/editable-table.js +2 -2
  27. package/dist/empty-state.js +1 -1
  28. package/dist/field.d.ts +4 -1
  29. package/dist/field.js +3 -3
  30. package/dist/file-upload.d.ts +12 -0
  31. package/dist/file-upload.js +106 -0
  32. package/dist/index.d.ts +47 -6
  33. package/dist/index.js +25 -4
  34. package/dist/input-control.d.ts +1 -1
  35. package/dist/input-control.js +1 -1
  36. package/dist/input.js +2 -2
  37. package/dist/label-value-grid.d.ts +3 -1
  38. package/dist/label-value-grid.js +15 -2
  39. package/dist/label-value.d.ts +4 -1
  40. package/dist/label-value.js +4 -3
  41. package/dist/layout.d.ts +7 -1
  42. package/dist/layout.js +3 -3
  43. package/dist/lib/date-utils.d.ts +9 -0
  44. package/dist/lib/date-utils.js +34 -0
  45. package/dist/link.d.ts +9 -0
  46. package/dist/link.js +19 -0
  47. package/dist/multi-select.d.ts +3 -1
  48. package/dist/multi-select.js +12 -11
  49. package/dist/page-section.d.ts +14 -0
  50. package/dist/page-section.js +13 -0
  51. package/dist/pagination.js +1 -1
  52. package/dist/popover-menu.d.ts +35 -0
  53. package/dist/popover-menu.js +36 -0
  54. package/dist/popover-primitive.d.ts +7 -0
  55. package/dist/popover-primitive.js +11 -0
  56. package/dist/popover.d.ts +10 -5
  57. package/dist/popover.js +6 -9
  58. package/dist/progress.d.ts +10 -0
  59. package/dist/progress.js +17 -0
  60. package/dist/search-input.js +1 -1
  61. package/dist/section-nav.d.ts +22 -0
  62. package/dist/section-nav.js +25 -0
  63. package/dist/select-primitive.js +2 -2
  64. package/dist/select.js +2 -2
  65. package/dist/separator.d.ts +6 -0
  66. package/dist/separator.js +6 -0
  67. package/dist/skeleton.d.ts +4 -0
  68. package/dist/skeleton.js +6 -0
  69. package/dist/spinner.d.ts +22 -0
  70. package/dist/spinner.js +24 -0
  71. package/dist/styles.css +42 -0
  72. package/dist/switch.d.ts +12 -0
  73. package/dist/switch.js +16 -0
  74. package/dist/table.d.ts +7 -1
  75. package/dist/table.js +26 -12
  76. package/dist/tabs.d.ts +24 -1
  77. package/dist/tabs.js +61 -3
  78. package/dist/tailwind-preset.js +9 -0
  79. package/dist/textarea.js +1 -1
  80. package/dist/toaster.js +19 -10
  81. package/dist/typography.d.ts +1 -1
  82. package/dist/use-error-shake.d.ts +7 -0
  83. package/dist/use-error-shake.js +36 -0
  84. package/dist/use-file-upload.d.ts +34 -0
  85. package/dist/use-file-upload.js +133 -0
  86. package/dist/use-sticky-sentinel.d.ts +16 -0
  87. package/dist/use-sticky-sentinel.js +62 -0
  88. package/dist/use-table-sort.d.ts +28 -0
  89. package/dist/use-table-sort.js +53 -0
  90. package/dist/use-viewport-threshold.d.ts +12 -0
  91. package/dist/use-viewport-threshold.js +43 -0
  92. package/package.json +32 -6
  93. package/dist/tab-with-dropdown.d.ts +0 -18
  94. package/dist/tab-with-dropdown.js +0 -70
package/README.md CHANGED
@@ -76,7 +76,42 @@ The package currently includes:
76
76
 
77
77
  ## AI Usage
78
78
 
79
- If you are using an AI coding assistant, give it these instructions explicitly:
79
+ ### MCP Server (recommended)
80
+
81
+ This design system includes the [Storybook MCP addon](https://storybook.js.org/docs/next/ai/mcp/overview/), which gives AI coding assistants direct access to component documentation, props, stories, and usage examples.
82
+
83
+ **Setup:**
84
+
85
+ 1. Start the Storybook dev server in this repo:
86
+ ```bash
87
+ npm run storybook
88
+ ```
89
+ This starts on `http://localhost:6007` with the MCP endpoint at `/mcp`.
90
+
91
+ 2. In your consuming project, add a `.mcp.json` at the project root:
92
+ ```json
93
+ {
94
+ "mcpServers": {
95
+ "nea-design-system": {
96
+ "type": "http",
97
+ "url": "http://localhost:6007/mcp"
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ 3. Restart Claude Code (or your MCP-compatible AI tool) in the consuming project. The following tools become available:
104
+ - **list-all-documentation** — discover all components and their story IDs
105
+ - **get-documentation** — get full component docs, props, and code examples
106
+ - **get-documentation-for-story** — get details for a specific story variant
107
+ - **preview-stories** — generate preview URLs for stories
108
+ - **get-storybook-story-instructions** — get guidance on writing stories
109
+
110
+ The MCP server requires the Storybook dev server to be running. Start it before opening your AI tool.
111
+
112
+ ### Manual instructions
113
+
114
+ If you are not using the MCP server, give your AI coding assistant these instructions explicitly:
80
115
 
81
116
  ```text
82
117
  Use @neasg/design-system as the source of truth for shared UI.
@@ -105,6 +140,7 @@ Use @neasg/design-system as the source of truth for shared UI.
105
140
  - `@neasg/design-system/draggable-tabs`
106
141
  - `@neasg/design-system/layout`
107
142
  - `@neasg/design-system/page-header`
143
+ - `@neasg/design-system/popover`
108
144
  - `@neasg/design-system/pagination`
109
145
  - `@neasg/design-system/table`
110
146
  - `@neasg/design-system/tailwind-preset`
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const alertVariants: (props?: ({
4
+ variant?: "info" | "success" | "warning" | "destructive" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ export interface AlertProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof alertVariants> {
7
+ title?: React.ReactNode;
8
+ description?: React.ReactNode;
9
+ icon?: React.ComponentType<{
10
+ className?: string;
11
+ }>;
12
+ action?: React.ReactNode;
13
+ }
14
+ declare const Alert: React.ForwardRefExoticComponent<AlertProps & React.RefAttributes<HTMLDivElement>>;
15
+ export { Alert, alertVariants };
package/dist/alert.js ADDED
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "./lib/utils";
5
+ import { Typography } from "./typography";
6
+ const alertVariants = cva("relative flex w-full items-start gap-3 rounded-md border px-4 py-3", {
7
+ variants: {
8
+ variant: {
9
+ info: "border-[hsl(var(--status-info-foreground))]/20 bg-[hsl(var(--status-info))] text-[hsl(var(--status-info-foreground))]",
10
+ success: "border-[hsl(var(--status-success-foreground))]/20 bg-[hsl(var(--status-success))] text-[hsl(var(--status-success-foreground))]",
11
+ warning: "border-[hsl(var(--status-warning-foreground))]/20 bg-[hsl(var(--status-warning))] text-[hsl(var(--status-warning-foreground))]",
12
+ destructive: "border-[hsl(var(--status-destructive-foreground))]/20 bg-[hsl(var(--status-destructive))] text-[hsl(var(--status-destructive-foreground))]",
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ variant: "info",
17
+ },
18
+ });
19
+ const Alert = React.forwardRef(({ variant, title, description, icon: Icon, action, className, children, role = "alert", ...props }, ref) => {
20
+ const body = description !== null && description !== void 0 ? description : children;
21
+ return (_jsxs("div", { ref: ref, role: role, className: cn(alertVariants({ variant }), className), ...props, children: [Icon ? (_jsx(Icon, { className: "mt-0.5 h-4 w-4 shrink-0" })) : null, _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [title ? (_jsx(Typography, { as: "p", variant: "bodySm", color: "inherit", className: "font-semibold", children: title })) : null, body ? (_jsx(Typography, { as: "div", variant: "caption", color: "inherit", className: "opacity-90", children: body })) : null] }), action ? _jsx("div", { className: "shrink-0 self-start", children: action }) : null] }));
22
+ });
23
+ Alert.displayName = "Alert";
24
+ export { Alert, alertVariants };
package/dist/avatar.d.ts CHANGED
@@ -3,30 +3,39 @@ import * as AvatarPrimitive from "@radix-ui/react-avatar";
3
3
  declare const AvatarRoot: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
4
4
  declare const AvatarImage: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarImageProps & React.RefAttributes<HTMLImageElement>, "ref"> & React.RefAttributes<HTMLImageElement>>;
5
5
  declare const AvatarFallback: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarFallbackProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
6
+ export type AvatarSize = "sm" | "md";
6
7
  interface AvatarProps extends Omit<React.ComponentPropsWithoutRef<typeof AvatarRoot>, "children"> {
7
8
  src?: string | null;
8
9
  alt?: string;
9
- fallback: React.ReactNode;
10
+ fallback?: React.ReactNode;
11
+ size?: AvatarSize;
12
+ loading?: boolean;
10
13
  imageClassName?: string;
11
14
  fallbackClassName?: string;
12
15
  }
13
16
  interface AvatarProfileProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "role"> {
14
17
  src?: string | null;
15
18
  alt?: string;
16
- fallback: React.ReactNode;
19
+ fallback?: React.ReactNode;
20
+ size?: AvatarSize;
21
+ loading?: boolean;
17
22
  name?: React.ReactNode;
18
23
  role?: React.ReactNode;
19
24
  rolePlacement?: "above" | "below";
25
+ topInfo?: React.ReactNode;
26
+ bottomInfo?: React.ReactNode;
20
27
  avatarClassName?: string;
21
28
  imageClassName?: string;
22
29
  fallbackClassName?: string;
23
30
  contentClassName?: string;
24
31
  nameClassName?: string;
25
32
  roleClassName?: string;
33
+ topInfoClassName?: string;
34
+ bottomInfoClassName?: string;
26
35
  avatarOverlay?: React.ReactNode;
27
36
  }
28
- declare function Avatar({ src, alt, fallback, className, imageClassName, fallbackClassName, ...props }: AvatarProps): import("react/jsx-runtime").JSX.Element;
29
- declare function AvatarProfile({ src, alt, fallback, name, role, rolePlacement, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameClassName, roleClassName, avatarOverlay, ...props }: AvatarProfileProps): import("react/jsx-runtime").JSX.Element;
37
+ declare function Avatar({ src, alt, fallback, size, loading, className, imageClassName, fallbackClassName, ...props }: AvatarProps): import("react/jsx-runtime").JSX.Element;
38
+ declare function AvatarProfile({ src, alt, fallback, size, loading, name, role, rolePlacement, topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }: AvatarProfileProps): import("react/jsx-runtime").JSX.Element;
30
39
  export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback };
31
40
  export type AvatarRootProps = React.ComponentPropsWithoutRef<typeof AvatarRoot>;
32
41
  export type { AvatarProps, AvatarProfileProps };
package/dist/avatar.js CHANGED
@@ -3,19 +3,36 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as AvatarPrimitive from "@radix-ui/react-avatar";
5
5
  import { cn } from "./lib/utils";
6
+ import { Skeleton } from "./skeleton";
6
7
  const AvatarRoot = React.forwardRef(({ className, ...props }, ref) => (_jsx(AvatarPrimitive.Root, { ref: ref, className: cn("relative flex shrink-0 overflow-hidden rounded-full", className), ...props })));
7
8
  AvatarRoot.displayName = "AvatarRoot";
8
9
  const AvatarImage = React.forwardRef(({ className, ...props }, ref) => (_jsx(AvatarPrimitive.Image, { ref: ref, className: cn("aspect-square size-full", className), ...props })));
9
10
  AvatarImage.displayName = "AvatarImage";
10
11
  const AvatarFallback = React.forwardRef(({ className, ...props }, ref) => (_jsx(AvatarPrimitive.Fallback, { ref: ref, className: cn("flex size-full items-center justify-center rounded-full bg-muted", className), ...props })));
11
12
  AvatarFallback.displayName = "AvatarFallback";
12
- function Avatar({ src, alt = "", fallback, className, imageClassName, fallbackClassName, ...props }) {
13
- return (_jsxs(AvatarRoot, { className: cn("h-8 w-8", className), ...props, children: [src ? (_jsx(AvatarImage, { src: src, alt: alt, className: imageClassName })) : null, _jsx(AvatarFallback, { className: cn("bg-green-100 text-xs font-medium text-green-800", fallbackClassName), children: fallback })] }));
13
+ const avatarSizeClasses = {
14
+ sm: "h-8 w-8 text-xs",
15
+ md: "h-10 w-10 text-sm",
16
+ };
17
+ function Avatar({ src, alt = "", fallback, size = "sm", loading = false, className, imageClassName, fallbackClassName, ...props }) {
18
+ if (loading) {
19
+ return (_jsx(Skeleton, { className: cn("shrink-0 rounded-full", avatarSizeClasses[size], className), ...props }));
20
+ }
21
+ return (_jsxs(AvatarRoot, { className: cn(avatarSizeClasses[size], className), ...props, children: [src ? (_jsx(AvatarImage, { src: src, alt: alt, className: imageClassName })) : null, _jsx(AvatarFallback, { className: cn("bg-green-100 font-medium text-green-800", fallbackClassName), children: fallback })] }));
14
22
  }
15
- function AvatarProfile({ src, alt = "", fallback, name, role, rolePlacement = "above", className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameClassName, roleClassName, avatarOverlay, ...props }) {
16
- const hasMeta = name !== undefined || role !== undefined;
17
- const roleNode = role ? (_jsx("span", { className: cn("text-[10px] font-medium uppercase tracking-wide text-muted-foreground", roleClassName), children: role })) : null;
18
- const nameNode = name ? (_jsx("span", { className: cn("truncate text-sm font-medium text-foreground", nameClassName), children: name })) : null;
19
- return (_jsxs("div", { className: cn("flex items-center gap-2", className), ...props, children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(Avatar, { src: src, alt: alt, fallback: fallback, className: cn("h-8 w-8", avatarClassName), imageClassName: imageClassName, fallbackClassName: fallbackClassName }), avatarOverlay] }), hasMeta ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", contentClassName), children: [rolePlacement === "above" ? roleNode : null, nameNode, rolePlacement === "below" ? roleNode : null] })) : null] }));
23
+ function AvatarProfile({ src, alt = "", fallback, size = "sm", loading = false, name, role, rolePlacement = "above", topInfo, bottomInfo, className, avatarClassName, imageClassName, fallbackClassName, contentClassName, nameClassName, roleClassName, topInfoClassName, bottomInfoClassName, avatarOverlay, ...props }) {
24
+ const resolvedTop = topInfo !== null && topInfo !== void 0 ? topInfo : (rolePlacement === "above" ? role : undefined);
25
+ const resolvedBottom = bottomInfo !== null && bottomInfo !== void 0 ? bottomInfo : (rolePlacement === "below" ? role : undefined);
26
+ if (loading) {
27
+ return (_jsxs("div", { className: cn("flex items-center gap-2", className), "aria-busy": "true", ...props, children: [_jsx(Skeleton, { className: cn("shrink-0 rounded-full", avatarSizeClasses[size], avatarClassName) }), _jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col gap-1.5", contentClassName), children: [resolvedTop !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null, _jsx(Skeleton, { className: "h-4 w-32" }), resolvedBottom !== undefined ? (_jsx(Skeleton, { className: "h-3 w-20" })) : null] })] }));
28
+ }
29
+ const hasMeta = name !== undefined ||
30
+ resolvedTop !== undefined ||
31
+ resolvedBottom !== undefined;
32
+ const infoBaseClass = "truncate text-[10px] leading-tight font-medium uppercase tracking-wide text-muted-foreground";
33
+ const topNode = resolvedTop !== undefined && resolvedTop !== null ? (_jsx("span", { className: cn(infoBaseClass, topInfo !== undefined ? topInfoClassName : roleClassName), children: resolvedTop })) : null;
34
+ const bottomNode = resolvedBottom !== undefined && resolvedBottom !== null ? (_jsx("span", { className: cn(infoBaseClass, bottomInfo !== undefined ? bottomInfoClassName : roleClassName), children: resolvedBottom })) : null;
35
+ const nameNode = name ? (_jsx("span", { className: cn("truncate text-sm leading-tight font-medium text-foreground", nameClassName), children: name })) : null;
36
+ return (_jsxs("div", { className: cn("flex items-center gap-2", className), ...props, children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(Avatar, { src: src, alt: alt, fallback: fallback, size: size, className: avatarClassName, imageClassName: imageClassName, fallbackClassName: fallbackClassName }), avatarOverlay] }), hasMeta ? (_jsxs("div", { className: cn("flex min-w-0 flex-1 flex-col", contentClassName), children: [topNode, nameNode, bottomNode] })) : null] }));
20
37
  }
21
38
  export { Avatar, AvatarProfile, AvatarRoot, AvatarImage, AvatarFallback };
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ import { type ButtonProps } from "./button";
3
+ export interface BackButtonProps extends Omit<ButtonProps, "asChild" | "size" | "variant"> {
4
+ }
5
+ declare const BackButton: React.ForwardRefExoticComponent<BackButtonProps & React.RefAttributes<HTMLButtonElement>>;
6
+ export { BackButton };
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { ChevronLeftIcon } from "./animated-icons/chevron-left";
4
+ import { Button } from "./button";
5
+ import { cn } from "./lib/utils";
6
+ const BackButton = React.forwardRef(({ children = "Back", className, type, ...props }, ref) => (_jsxs(Button, { ref: ref, type: type !== null && type !== void 0 ? type : "button", variant: "link", className: cn("h-auto gap-1 px-0", className), ...props, children: [_jsx(ChevronLeftIcon, { "aria-hidden": "true", className: "shrink-0", size: 16 }), _jsx("span", { children: children })] })));
7
+ BackButton.displayName = "BackButton";
8
+ export { BackButton };
package/dist/badge.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const badgeVariants: (props?: ({
4
- variant?: "muted" | "outline" | "secondary" | "destructive" | "success" | "warning" | "info" | "accent" | null | undefined;
4
+ variant?: "muted" | "outline" | "info" | "success" | "warning" | "destructive" | "secondary" | "accent" | null | undefined;
5
5
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
6
  /**
7
7
  * Visual status label used for short categorical values like case state,
@@ -11,14 +11,14 @@ const BreadcrumbItem = React.forwardRef(({ className, ...props }, ref) => (_jsx(
11
11
  BreadcrumbItem.displayName = "BreadcrumbItem";
12
12
  const BreadcrumbLink = React.forwardRef(({ asChild, className, ...props }, ref) => {
13
13
  const Comp = asChild ? Slot : "a";
14
- return (_jsx(Comp, { ref: ref, className: cn("transition-colors hover:text-foreground", className), ...props }));
14
+ return (_jsx(Comp, { ref: ref, className: cn("cursor-pointer transition-colors hover:text-foreground", className), ...props }));
15
15
  });
16
16
  BreadcrumbLink.displayName = "BreadcrumbLink";
17
17
  const BreadcrumbPage = React.forwardRef(({ className, ...props }, ref) => (_jsx("span", { ref: ref, role: "link", "aria-disabled": "true", "aria-current": "page", className: cn("font-normal text-foreground", className), ...props })));
18
18
  BreadcrumbPage.displayName = "BreadcrumbPage";
19
19
  const BreadcrumbSeparator = ({ children, className, ...props }) => (_jsx("li", { role: "presentation", "aria-hidden": "true", className: cn("[&>svg]:h-3.5 [&>svg]:w-3.5", className), ...props, children: children !== null && children !== void 0 ? children : (_jsx("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.75", children: _jsx("path", { d: "M6 3.5 10.5 8 6 12.5" }) })) }));
20
20
  BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
21
- const BreadcrumbEllipsis = ({ className, ...props }) => (_jsxs("span", { role: "presentation", "aria-hidden": "true", className: cn("flex h-9 w-9 items-center justify-center", className), ...props, children: [_jsx("span", { className: "text-lg leading-none", children: "\u2026" }), _jsx("span", { className: "sr-only", children: "More" })] }));
21
+ const BreadcrumbEllipsis = ({ className, ...props }) => (_jsxs("span", { role: "presentation", "aria-hidden": "true", className: cn("flex h-control w-control items-center justify-center", className), ...props, children: [_jsx("span", { className: "text-lg leading-none", children: "\u2026" }), _jsx("span", { className: "sr-only", children: "More" })] }));
22
22
  BreadcrumbEllipsis.displayName = "BreadcrumbEllipsis";
23
23
  function Breadcrumb({ items, separator, className, listClassName, itemClassName, linkClassName, currentClassName, ...props }) {
24
24
  if (!items.length) {
package/dist/button.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const buttonVariants: (props?: ({
4
- variant?: "link" | "default" | "outline" | "secondary" | "destructive" | "ghost" | null | undefined;
5
- size?: "default" | "sm" | "lg" | "icon" | null | undefined;
4
+ variant?: "link" | "default" | "outline" | "destructive" | "secondary" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "icon" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
8
  /**
package/dist/button.js CHANGED
@@ -14,10 +14,9 @@ const buttonVariants = cva("inline-flex cursor-pointer items-center justify-cent
14
14
  link: "text-primary underline-offset-4 hover:underline",
15
15
  },
16
16
  size: {
17
- default: "h-10 px-4 py-2 [&_svg]:h-4 [&_svg]:w-4",
18
- sm: "h-9 rounded-md px-3 text-xs [&_svg]:h-4 [&_svg]:w-4",
19
- lg: "h-11 rounded-md px-8 [&_svg]:h-5 [&_svg]:w-5",
20
- icon: "h-10 w-10 [&_svg]:h-4 [&_svg]:w-4",
17
+ sm: "h-9 px-3 text-sm [&_svg]:h-4 [&_svg]:w-4",
18
+ default: "h-control px-4 py-2 [&_svg]:h-4 [&_svg]:w-4",
19
+ icon: "h-control w-control [&_svg]:h-4 [&_svg]:w-4",
21
20
  },
22
21
  },
23
22
  defaultVariants: {
package/dist/card.d.ts CHANGED
@@ -3,12 +3,15 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "t
3
3
  title: React.ReactNode;
4
4
  description?: React.ReactNode;
5
5
  variant?: "default" | "elevated" | "gradient";
6
+ size?: "default" | "compact";
6
7
  /** Large value displayed above the title — use for stat/metric cards. */
7
8
  stat?: React.ReactNode;
8
9
  /** Small supporting text below the stat or body — use for sub-metrics. */
9
10
  subMetric?: React.ReactNode;
10
11
  footer?: React.ReactNode;
11
12
  active?: boolean;
13
+ /** Replaces title/stat/subMetric with skeleton placeholders while data is loading. */
14
+ loading?: boolean;
12
15
  }
13
16
  declare const Card: React.ForwardRefExoticComponent<CardProps & React.RefAttributes<HTMLDivElement>>;
14
17
  export { Card };
package/dist/card.js CHANGED
@@ -2,8 +2,15 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { cn } from "./lib/utils";
5
+ import { Skeleton } from "./skeleton";
5
6
  import { Typography } from "./typography";
6
- const Card = React.forwardRef(({ title, description, variant = "default", stat, subMetric, footer, active, children, className, onClick, ...props }, ref) => (_jsxs("div", { ref: ref, onClick: onClick, className: cn("rounded-xl border text-card-foreground", variant === "default" && "bg-card", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
7
- "border-primary/20 bg-gradient-to-br from-primary to-primary/80 text-primary-foreground", active && "border-primary bg-primary/10 ring-1 ring-primary/20", onClick && "cursor-pointer transition-colors hover:border-primary", className), ...props, children: [_jsxs("div", { className: "flex flex-col gap-2 p-6", children: [_jsx(Typography, { as: "p", variant: "label", color: variant === "gradient" ? "inherit" : "muted", className: variant === "gradient" ? "opacity-80" : undefined, children: title }), description ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-70" : undefined, children: description })) : null, stat ? (_jsx(Typography, { as: "p", variant: "title", color: variant === "gradient" ? "inherit" : undefined, children: stat })) : null, subMetric ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-80" : undefined, children: subMetric })) : null] }), children ? _jsx("div", { className: "p-6 pt-0", children: children }) : null, footer ? (_jsx("div", { className: "flex items-center p-6 pt-0", children: footer })) : null] })));
7
+ const Card = React.forwardRef(({ title, description, variant = "default", size = "default", stat, subMetric, footer, active, loading = false, children, className, onClick, ...props }, ref) => {
8
+ const renderedTitle = React.isValidElement(title) ? (title) : (_jsx(Typography, { as: "p", variant: "label", color: variant === "gradient" ? "inherit" : "muted", className: variant === "gradient" ? "opacity-80" : undefined, children: title }));
9
+ const renderedDescription = description == null ? null : React.isValidElement(description) ? (description) : (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-70" : undefined, children: description }));
10
+ return (_jsxs("div", { ref: ref, onClick: onClick, className: cn("rounded-lg border text-card-foreground", variant === "default" && "bg-card", variant === "elevated" && "bg-card shadow-sm", variant === "gradient" &&
11
+ "border-primary/20 bg-gradient-to-br from-primary to-primary/80 text-primary-foreground", active && "border-primary bg-primary/[0.04] ring-1 ring-primary/20", onClick && "cursor-pointer transition-colors hover:border-primary", className), ...props, children: [_jsxs("div", { className: cn("flex flex-col gap-2", size === "default" && "p-6", size === "compact" && "p-3"), children: [loading ? (_jsx(Skeleton, { className: "h-3.5 w-24" })) : (renderedTitle), loading
12
+ ? description != null && _jsx(Skeleton, { className: "h-5 w-40" })
13
+ : renderedDescription, loading ? (stat !== undefined && _jsx(Skeleton, { className: "h-8 w-20" })) : stat ? (_jsx(Typography, { as: "p", variant: "title", color: variant === "gradient" ? "inherit" : undefined, children: stat })) : null, loading ? (subMetric !== undefined && _jsx(Skeleton, { className: "h-5 w-28" })) : subMetric ? (_jsx(Typography, { as: "p", variant: "caption", color: variant === "gradient" ? "inherit" : undefined, className: variant === "gradient" ? "opacity-80" : undefined, children: subMetric })) : null] }), children ? (_jsx("div", { className: cn(size === "default" && "p-6 pt-0", size === "compact" && "p-3 pt-0"), children: children })) : null, footer ? (_jsx("div", { className: cn("flex items-center", size === "default" && "p-6 pt-0", size === "compact" && "p-3 pt-0"), children: footer })) : null] }));
14
+ });
8
15
  Card.displayName = "Card";
9
16
  export { Card };
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "type" | "size"> {
3
+ /** Renders the checkbox in an indeterminate (mixed) state. */
4
+ indeterminate?: boolean;
5
+ /** Visual size of the checkbox. */
6
+ size?: "sm" | "md" | "lg";
7
+ /** Label rendered next to the checkbox. When provided, the checkbox and label are wrapped in a `<label>`. */
8
+ label?: React.ReactNode;
9
+ /** Description shown below the label in smaller muted text. */
10
+ description?: React.ReactNode;
11
+ }
12
+ declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
13
+ export { Checkbox };
@@ -0,0 +1,29 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "./lib/utils";
5
+ import { Typography } from "./typography";
6
+ const sizeClasses = {
7
+ sm: "size-3.5",
8
+ md: "size-4",
9
+ lg: "size-5",
10
+ };
11
+ const Checkbox = React.forwardRef(({ className, indeterminate = false, size = "md", checked, disabled, label, description, id, ...props }, ref) => {
12
+ const innerRef = React.useRef(null);
13
+ const generatedId = React.useId();
14
+ const inputId = id !== null && id !== void 0 ? id : `checkbox-${generatedId}`;
15
+ React.useImperativeHandle(ref, () => innerRef.current);
16
+ React.useEffect(() => {
17
+ if (innerRef.current) {
18
+ innerRef.current.indeterminate = indeterminate;
19
+ }
20
+ }, [indeterminate]);
21
+ const box = (_jsxs("span", { className: cn("relative inline-block shrink-0 rounded-sm border bg-background align-middle text-primary-foreground transition-colors", sizeClasses[size], (checked || indeterminate) && !disabled
22
+ ? "border-primary bg-primary"
23
+ : "border-input", disabled && "cursor-not-allowed opacity-50", !label && className), children: [_jsx("input", { ref: innerRef, type: "checkbox", id: inputId, checked: checked, disabled: disabled, className: "absolute inset-0 h-full w-full cursor-pointer appearance-none opacity-0 disabled:cursor-not-allowed", ...props }), indeterminate ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", className: "pointer-events-none absolute inset-0 m-auto h-3 w-3", "aria-hidden": "true", children: _jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) })) : checked ? (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute inset-0 m-auto h-3 w-3", "aria-hidden": "true", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) : null] }));
24
+ if (!label)
25
+ return box;
26
+ return (_jsxs("label", { htmlFor: inputId, className: cn("inline-flex cursor-pointer items-center gap-2 text-sm", disabled && "cursor-not-allowed opacity-50", className), children: [box, _jsxs("div", { className: "select-none", children: [_jsx(Typography, { as: "span", variant: "bodySm", children: label }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "mt-1", children: description })) : null] })] }));
27
+ });
28
+ Checkbox.displayName = "Checkbox";
29
+ export { Checkbox };
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ export interface CollapsibleProps {
3
+ id?: string;
4
+ title: React.ReactNode;
5
+ children: React.ReactNode;
6
+ defaultOpen?: boolean;
7
+ open?: boolean;
8
+ onOpenChange?: (open: boolean) => void;
9
+ /** Element rendered on the right of the header, before the chevron (e.g. an edit button). */
10
+ headerAction?: React.ReactNode;
11
+ /** Element rendered inline after the title (e.g. a tooltip icon). */
12
+ titleAdornment?: React.ReactNode;
13
+ className?: string;
14
+ headerClassName?: string;
15
+ contentClassName?: string;
16
+ }
17
+ declare function Collapsible({ id, title, children, defaultOpen, open: openProp, onOpenChange, headerAction, titleAdornment, className, headerClassName, contentClassName, }: CollapsibleProps): import("react/jsx-runtime").JSX.Element;
18
+ declare const CollapsibleSection: typeof Collapsible;
19
+ export { Collapsible, CollapsibleSection };
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
5
+ import { ChevronUp } from "lucide-react";
6
+ import { cn } from "./lib/utils";
7
+ import { Typography } from "./typography";
8
+ function Collapsible({ id, title, children, defaultOpen = true, open: openProp, onOpenChange, headerAction, titleAdornment, className, headerClassName, contentClassName, }) {
9
+ const [uncontrolled, setUncontrolled] = React.useState(defaultOpen);
10
+ const isControlled = openProp !== undefined;
11
+ const open = isControlled ? openProp : uncontrolled;
12
+ const setOpen = (next) => {
13
+ if (!isControlled)
14
+ setUncontrolled(next);
15
+ onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(next);
16
+ };
17
+ return (_jsxs(CollapsiblePrimitive.Root, { id: id, open: open, onOpenChange: setOpen, className: cn("scroll-mt-24 border-b border-border", className), children: [_jsxs("div", { className: cn("flex items-center gap-2 py-3", headerClassName), children: [_jsx(CollapsiblePrimitive.Trigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex flex-1 cursor-pointer items-center gap-2 text-left text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm", children: [_jsx(Typography, { as: "h3", variant: "subheading", children: title }), titleAdornment] }) }), headerAction, _jsx(CollapsiblePrimitive.Trigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": open ? "Collapse section" : "Expand section", className: "group ml-1 cursor-pointer text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-sm", children: _jsx(ChevronUp, { "aria-hidden": "true", className: "h-4 w-4 transition-transform duration-150 group-data-[state=closed]:rotate-180" }) }) })] }), _jsx(CollapsiblePrimitive.Content, { "data-slot": "collapsible-content", className: "overflow-hidden", children: _jsx("div", { className: cn("pb-6 pt-4", contentClassName), children: children }) })] }));
18
+ }
19
+ const CollapsibleSection = Collapsible;
20
+ export { Collapsible, CollapsibleSection };
@@ -58,8 +58,8 @@ function CommandSearch({ value, onValueChange, sections, children, className, is
58
58
  }
59
59
  }, [isOpen]);
60
60
  return (_jsxs("div", { className: className, ...props, children: [_jsxs(Button, { type: "button", onClick: () => setIsOpen(true), variant: "ghost", className: cn(isCollapsed
61
- ? "h-10 w-full justify-center rounded-lg px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"
62
- : "h-10 w-full min-w-[14rem] justify-start gap-3 rounded-lg border border-gray-200 bg-white px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"), children: [_jsx(SearchIcon, { className: "shrink-0", size: 16 }), !isCollapsed ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex-1 text-left text-sm", children: triggerPlaceholder }), _jsx("kbd", { className: "hidden h-5 items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] text-muted-foreground sm:inline-flex", children: resolvedLabel })] })) : null] }), _jsx(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, children: _jsx(DialogSurface, { className: cn("max-w-xl gap-0 overflow-hidden p-0 sm:max-w-xl", dialogClassName), hideCloseButton: true, children: _jsxs(Command, { shouldFilter: false, className: "rounded-none border-0", children: [_jsx(CommandInput, { ref: inputRef, value: value, onValueChange: onValueChange, placeholder: inputPlaceholder, className: "text-sm" }), allFilter || filters.length ? (_jsxs("div", { className: "flex items-center gap-1 border-b px-3 py-2", children: [allFilter ? (_jsx(FilterToggle, { selected: allFilter.selected, onClick: allFilter.onSelect, children: allFilter.label })) : null, filters.map((filter) => (_jsx(FilterToggle, { selected: filter.selected, onClick: filter.onSelect, children: filter.label }, filter.value)))] })) : null, _jsx(CommandList, { className: cn("max-h-[400px] p-1", resultsClassName), children: children !== undefined ? children : sections ? (visibleSections.length ? (visibleSections.map((section, index) => (_jsxs(React.Fragment, { children: [index > 0 ? _jsx(CommandSeparator, { alwaysRender: true }) : null, _jsx(CommandGroup, { heading: section.heading, children: section.items.map((item) => (_jsx(CommandItem, { value: getCommandSearchItemValue(item), disabled: item.disabled, onSelect: () => {
61
+ ? "h-control w-full justify-center rounded-lg px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"
62
+ : "h-control w-full min-w-[14rem] justify-start gap-3 rounded-lg border border-gray-200 bg-white px-3 !font-normal text-muted-foreground hover:bg-white hover:text-foreground"), children: [_jsx(SearchIcon, { className: "shrink-0", size: 16 }), !isCollapsed ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "flex-1 text-left text-sm", children: triggerPlaceholder }), _jsx("kbd", { className: "hidden h-5 items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] text-muted-foreground sm:inline-flex", children: resolvedLabel })] })) : null] }), _jsx(DialogRoot, { open: isOpen, onOpenChange: setIsOpen, children: _jsx(DialogSurface, { className: cn("max-w-xl gap-0 overflow-hidden p-0 sm:max-w-xl", dialogClassName), hideCloseButton: true, children: _jsxs(Command, { shouldFilter: false, className: "rounded-none border-0", children: [_jsx(CommandInput, { ref: inputRef, value: value, onValueChange: onValueChange, placeholder: inputPlaceholder, className: "text-sm" }), allFilter || filters.length ? (_jsxs("div", { className: "flex items-center gap-1 border-b px-3 py-2", children: [allFilter ? (_jsx(FilterToggle, { selected: allFilter.selected, onClick: allFilter.onSelect, children: allFilter.label })) : null, filters.map((filter) => (_jsx(FilterToggle, { selected: filter.selected, onClick: filter.onSelect, children: filter.label }, filter.value)))] })) : null, _jsx(CommandList, { className: cn("max-h-[400px] p-1", resultsClassName), children: children !== undefined ? children : sections ? (visibleSections.length ? (visibleSections.map((section, index) => (_jsxs(React.Fragment, { children: [index > 0 ? _jsx(CommandSeparator, { alwaysRender: true }) : null, _jsx(CommandGroup, { heading: section.heading, children: section.items.map((item) => (_jsx(CommandItem, { value: getCommandSearchItemValue(item), disabled: item.disabled, onSelect: () => {
63
63
  var _a;
64
64
  (_a = item.onSelect) === null || _a === void 0 ? void 0 : _a.call(item);
65
65
  if (item.closeOnSelect !== false) {
package/dist/command.d.ts CHANGED
@@ -45,7 +45,7 @@ declare const CommandGroup: React.ForwardRefExoticComponent<Omit<{
45
45
  ref?: React.Ref<HTMLDivElement>;
46
46
  } & {
47
47
  asChild?: boolean;
48
- }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "heading"> & {
48
+ }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "heading" | "value"> & {
49
49
  heading?: React.ReactNode;
50
50
  value?: string;
51
51
  forceMount?: boolean;
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ export interface CopyButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onCopy"> {
3
+ /** Text to copy to the clipboard. */
4
+ value: string;
5
+ /** Milliseconds the "copied" state stays visible. */
6
+ feedbackDuration?: number;
7
+ /** Optional label rendered next to the icon. When omitted, renders as icon-only. */
8
+ children?: React.ReactNode;
9
+ /** Called after a successful copy. */
10
+ onCopy?: (value: string) => void;
11
+ /** Called if the clipboard write fails. */
12
+ onError?: (error: unknown) => void;
13
+ /** Accessible label for the icon-only button. Defaults to "Copy". */
14
+ copyLabel?: string;
15
+ /** Accessible label announced after copy. Defaults to "Copied". */
16
+ copiedLabel?: string;
17
+ }
18
+ declare function CopyButton({ value, feedbackDuration, children, onCopy, onError, copyLabel, copiedLabel, className, type, ...props }: CopyButtonProps): import("react/jsx-runtime").JSX.Element;
19
+ export { CopyButton };
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Copy } from "lucide-react";
5
+ import { CheckIcon } from "./animated-icons/check";
6
+ import { cn } from "./lib/utils";
7
+ function CopyButton({ value, feedbackDuration = 1500, children, onCopy, onError, copyLabel = "Copy", copiedLabel = "Copied", className, type = "button", ...props }) {
8
+ const [copied, setCopied] = React.useState(false);
9
+ const timeoutRef = React.useRef(null);
10
+ React.useEffect(() => () => {
11
+ if (timeoutRef.current)
12
+ clearTimeout(timeoutRef.current);
13
+ }, []);
14
+ const handleCopy = React.useCallback(async () => {
15
+ try {
16
+ await navigator.clipboard.writeText(value);
17
+ setCopied(true);
18
+ onCopy === null || onCopy === void 0 ? void 0 : onCopy(value);
19
+ if (timeoutRef.current)
20
+ clearTimeout(timeoutRef.current);
21
+ timeoutRef.current = setTimeout(() => setCopied(false), feedbackDuration);
22
+ }
23
+ catch (error) {
24
+ onError === null || onError === void 0 ? void 0 : onError(error);
25
+ }
26
+ }, [value, feedbackDuration, onCopy, onError]);
27
+ const iconOnly = children === undefined;
28
+ const label = copied ? copiedLabel : copyLabel;
29
+ return (_jsxs(_Fragment, { children: [_jsxs("button", { type: type, onClick: handleCopy, "aria-label": iconOnly ? label : undefined, className: cn("inline-flex cursor-pointer items-center gap-1.5 rounded text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50", !iconOnly && "text-sm font-medium", className), ...props, children: [copied ? (_jsx(CheckIcon, { size: 16, className: "text-green-600" })) : (_jsx(Copy, { className: "h-4 w-4", "aria-hidden": "true" })), iconOnly ? null : _jsx("span", { children: copied ? copiedLabel : children })] }), _jsx("span", { className: "sr-only", "aria-live": "polite", children: copied ? copiedLabel : "" })] }));
30
+ }
31
+ export { CopyButton };
@@ -5,7 +5,7 @@ import { format, parse } from "date-fns";
5
5
  import { Calendar } from "./calendar";
6
6
  import { inputControlClassName } from "./input-control";
7
7
  import { Field, FieldDescription, FieldError, FieldLabel } from "./field";
8
- import { Popover, PopoverContent, PopoverTrigger } from "./popover";
8
+ import { PopoverContent, PopoverRoot, PopoverTrigger } from "./popover-primitive";
9
9
  import { cn } from "./lib/utils";
10
10
  function parseDateString(dateStr) {
11
11
  if (!(dateStr === null || dateStr === void 0 ? void 0 : dateStr.trim()))
@@ -49,7 +49,7 @@ const DateInput = React.forwardRef(({ label, value, onValueChange, description,
49
49
  onValueChange(date ? formatISODate(date) : "");
50
50
  setOpen(false);
51
51
  };
52
- return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: "relative w-full", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", style: { width: 14, height: 14 }, "aria-hidden": "true", children: [_jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", ry: "2" }), _jsx("line", { x1: "16", x2: "16", y1: "2", y2: "6" }), _jsx("line", { x1: "8", x2: "8", y1: "2", y2: "6" }), _jsx("line", { x1: "3", x2: "21", y1: "10", y2: "10" })] }), _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "cursor-pointer pl-9 text-left", !selectedDate && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: displayValue !== null && displayValue !== void 0 ? displayValue : _jsx("span", { children: placeholder }) })] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: (date) => {
52
+ return (_jsxs(Field, { className: className, "data-disabled": disabled ? "true" : undefined, "data-invalid": isInvalid ? "true" : undefined, children: [_jsx(FieldLabel, { htmlFor: inputId, className: cn(hideLabel && "sr-only", labelClassName), children: label }), _jsxs(PopoverRoot, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: "relative w-full", children: [_jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", style: { width: 14, height: 14 }, "aria-hidden": "true", children: [_jsx("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", ry: "2" }), _jsx("line", { x1: "16", x2: "16", y1: "2", y2: "6" }), _jsx("line", { x1: "8", x2: "8", y1: "2", y2: "6" }), _jsx("line", { x1: "3", x2: "21", y1: "10", y2: "10" })] }), _jsx("button", { ref: ref, type: "button", id: inputId, disabled: disabled, "aria-invalid": isInvalid ? "true" : undefined, "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || undefined, className: cn(inputControlClassName, "cursor-pointer pl-9 text-left", !selectedDate && "text-muted-foreground", isInvalid && "border-destructive focus-visible:ring-destructive", triggerClassName), children: displayValue !== null && displayValue !== void 0 ? displayValue : _jsx("span", { children: placeholder }) })] }) }), _jsx(PopoverContent, { className: "w-auto p-0", align: "start", children: _jsx(Calendar, { mode: "single", selected: selectedDate, onSelect: handleSelect, disabled: (date) => {
53
53
  if (minDate && date < minDate)
54
54
  return true;
55
55
  if (maxDate && date > maxDate)
@@ -10,7 +10,7 @@ const DialogPortal = DialogPrimitive.Portal;
10
10
  const DialogClose = DialogPrimitive.Close;
11
11
  const DialogOverlay = React.forwardRef(({ className, ...props }, ref) => (_jsx(DialogPrimitive.Overlay, { ref: ref, className: cn("fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", className), ...props })));
12
12
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
13
- const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 cursor-pointer rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
13
+ const DialogSurface = React.forwardRef(({ className, children, hideCloseButton, ...props }, ref) => (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { ref: ref, className: cn("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] })));
14
14
  DialogSurface.displayName = DialogPrimitive.Content.displayName;
15
15
  const DialogHeader = ({ className, ...props }) => (_jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props }));
16
16
  DialogHeader.displayName = "DialogHeader";
@@ -19,7 +19,7 @@ function TabButton({ item, dragHandleProps, }) {
19
19
  : isDraggable
20
20
  ? "cursor-grab active:cursor-grabbing"
21
21
  : "cursor-pointer", item.active
22
- ? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-green-500"
22
+ ? (_a = item.activeClassName) !== null && _a !== void 0 ? _a : "border-green-500 hover:bg-muted"
23
23
  : (_b = item.inactiveClassName) !== null && _b !== void 0 ? _b : "border-transparent hover:bg-muted", item.className), ...dragHandleProps, children: [_jsxs("button", { type: "button", onClick: item.disabled ? undefined : item.onSelect, disabled: item.disabled, className: cn("flex cursor-pointer items-center gap-2 py-3 pr-1 text-sm font-medium whitespace-nowrap disabled:cursor-not-allowed", labelClassName), children: [item.leading, item.label, item.trailing] }), item.onClose ? (_jsx("button", { type: "button", onClick: (event) => {
24
24
  var _a;
25
25
  event.stopPropagation();
package/dist/drawer.js CHANGED
@@ -46,7 +46,7 @@ const drawerSurfaceVariants = cva("fixed z-50 flex flex-col gap-4 overflow-y-aut
46
46
  },
47
47
  });
48
48
  function DrawerSurface({ side, className, children, hideCloseButton, ...props }) {
49
- return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-4 top-4 cursor-pointer rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] }));
49
+ return (_jsxs(DialogPortal, { children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Content, { className: cn(drawerSurfaceVariants({ side }), className), ...props, children: [children, !hideCloseButton ? (_jsxs(DialogPrimitive.Close, { className: "absolute right-2 top-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-md text-muted-foreground ring-offset-background transition-colors hover:bg-accent hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [_jsx(XIcon, { size: 16 }), _jsx("span", { className: "sr-only", children: "Close" })] })) : null] })] }));
50
50
  }
51
51
  function Drawer({ open, defaultOpen, onOpenChange, modal, trigger, title, description, children, footer, primaryAction, secondaryAction, side = "right", contentClassName, bodyClassName, hideCloseButton, }) {
52
52
  const [isOpen, setIsOpen] = useControllableOpen({
@@ -97,11 +97,11 @@ function EditableTable({ value, onChange, columns, isEditing = false, className,
97
97
  return String(cellValue);
98
98
  };
99
99
  const hasActionsColumn = isEditing || Boolean(renderRowActions);
100
- return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { className: "table-fixed", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "56px", minWidth: renderRowActions ? "120px" : "56px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length + (hasActionsColumn ? 1 : 0), className: "py-8 text-center text-muted-foreground", children: "No data available" }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0 ? "bg-muted/30" : undefined, children: [columns.map((column, columnIndex) => {
100
+ return (_jsxs("div", { className: cn("space-y-2", className), children: [_jsx("div", { className: "rounded-md border", children: _jsxs(Table, { className: "table-fixed", children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [columns.map((column, index) => (_jsx(TableHead, { width: column.width, minWidth: getColumnMinWidth(column), children: _jsx("div", { className: "whitespace-nowrap", children: column.header }) }, `header-${index}`))), hasActionsColumn ? (_jsx(TableHead, { width: renderRowActions ? undefined : "72px", minWidth: renderRowActions ? "120px" : "72px" })) : null] }) }), _jsx(TableBody, { children: value.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: columns.length + (hasActionsColumn ? 1 : 0), className: "py-8 text-center text-muted-foreground", children: "No data available" }) })) : (value.map((row, rowIndex) => (_jsxs(TableRow, { className: rowIndex % 2 === 0 ? "bg-muted/30" : undefined, children: [columns.map((column, columnIndex) => {
101
101
  const cellValue = getNestedValue(row, column.path);
102
102
  const isEditingCell = (editingCell === null || editingCell === void 0 ? void 0 : editingCell.rowIndex) === rowIndex &&
103
103
  (editingCell === null || editingCell === void 0 ? void 0 : editingCell.colPath) === column.path;
104
- return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-10 w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
104
+ return (_jsx(TableCell, { className: cn("whitespace-normal", isEditing && "cursor-pointer hover:bg-muted/50"), minWidth: getColumnMinWidth(column), onClick: () => handleCellClick(rowIndex, column.path), children: isEditingCell ? (_jsx(InputControl, { ref: inputRef, value: editValue, onChange: (event) => setEditValue(event.target.value), onBlur: commitEdit, onKeyDown: handleKeyDown, className: "h-control w-full text-sm" })) : (_jsx("span", { className: cn("block whitespace-normal break-words", cellValue === null ||
105
105
  cellValue === undefined ||
106
106
  cellValue === ""
107
107
  ? "text-muted-foreground"
@@ -2,6 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cn } from "./lib/utils";
3
3
  import { Typography } from "./typography";
4
4
  function EmptyState({ message, description, icon: Icon, action, className, ...props }) {
5
- return (_jsxs("div", { className: cn("flex flex-col items-center justify-center px-6 py-10 text-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-5 w-5 text-muted-foreground/70" })) : null, _jsxs("div", { className: "space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "max-w-md", children: description })) : null] }), action ? _jsx("div", { className: "pt-4", children: action }) : null] }));
5
+ return (_jsxs("div", { className: cn("flex flex-col items-center justify-center px-6 py-10 text-center", className), ...props, children: [Icon ? (_jsx(Icon, { className: "mb-4 h-10 w-10 stroke-[1.5] text-muted-foreground/70" })) : null, _jsxs("div", { className: "space-y-1.5", children: [_jsx(Typography, { as: "p", variant: "bodySm", className: "font-semibold", children: message }), description ? (_jsx(Typography, { as: "p", variant: "caption", className: "max-w-md", children: description })) : null] }), action ? _jsx("div", { className: "pt-6", children: action }) : null] }));
6
6
  }
7
7
  export { EmptyState };
package/dist/field.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import * as React from "react";
2
2
  declare function Field({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
3
- declare function FieldLabel({ className, ...props }: React.ComponentProps<"label">): import("react/jsx-runtime").JSX.Element;
3
+ interface FieldLabelProps extends React.ComponentProps<"label"> {
4
+ required?: boolean;
5
+ }
6
+ declare function FieldLabel({ className, required, children, ...props }: FieldLabelProps): import("react/jsx-runtime").JSX.Element;
4
7
  declare function FieldDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
5
8
  declare function FieldError({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element | null;
6
9
  export { Field, FieldDescription, FieldError, FieldLabel };