@neasg/design-system 0.1.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.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # NEA Design System
2
+
3
+ Shared NEA UI primitives, theme tokens, and Storybook documentation.
4
+
5
+ ## Local Development
6
+
7
+ ```bash
8
+ npm install
9
+ npm test
10
+ npm run build
11
+ npm run storybook
12
+ ```
13
+
14
+ ## Package Usage
15
+
16
+ ```ts
17
+ import "@neasg/design-system/styles.css";
18
+ import { Button, Badge } from "@neasg/design-system";
19
+ ```
20
+
21
+ For Tailwind-based apps, include the package build output in your content globs so the component utility classes are not purged:
22
+
23
+ ```ts
24
+ // tailwind.config.ts
25
+ content: [
26
+ "./app/**/*.{ts,tsx}",
27
+ "./components/**/*.{ts,tsx}",
28
+ "./node_modules/@neasg/design-system/dist/**/*.js"
29
+ ]
30
+ ```
31
+
32
+ Theme tokens are provided through the exported stylesheet. Import `@neasg/design-system/styles.css` once at your app root before rendering package components.
33
+
34
+ ## Available Exports
35
+
36
+ - `@neasg/design-system`
37
+ - `@neasg/design-system/button`
38
+ - `@neasg/design-system/badge`
39
+ - `@neasg/design-system/table`
40
+ - `@neasg/design-system/tabs`
41
+ - `@neasg/design-system/tooltip`
42
+ - `@neasg/design-system/theme`
43
+ - `@neasg/design-system/styles.css`
44
+
45
+ ## Publishing
46
+
47
+ This package is built to `dist/` before publish. The public package entry points are the compiled files in `dist`, not the raw `src` files.
48
+
49
+ One-time setup:
50
+
51
+ 1. Create the npm scope/package you want to publish to. This repo is currently configured for `@neasg/design-system`, so the `@neasg` scope must exist in npm.
52
+ 2. Add a GitHub Actions secret named `NPM_TOKEN` with publish access to that scope.
53
+
54
+ Release flow:
55
+
56
+ ```bash
57
+ npm version patch
58
+ git push origin main --follow-tags
59
+ ```
60
+
61
+ Pushing a `v*` tag triggers `.github/workflows/publish.yml`, which runs tests, builds the package, and publishes it to npm.
62
+
63
+ ## Storybook Deployment
64
+
65
+ `vercel.json` is configured to deploy the built Storybook static site:
66
+
67
+ - Install command: `npm ci`
68
+ - Build command: `npm run build-storybook`
69
+ - Output directory: `storybook-static`
70
+
71
+ One-time Vercel setup:
72
+
73
+ 1. Import this GitHub repo into Vercel.
74
+ 2. Let Vercel use the repo root as the project root.
75
+ 3. Keep the build settings from `vercel.json`.
76
+
77
+ After that, every push to the tracked branch deploys Storybook automatically in Vercel.
@@ -0,0 +1,13 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const badgeVariants: (props?: ({
4
+ variant?: "default" | "secondary" | "muted" | "destructive" | "outline" | "success" | "warning" | "info" | "actionRead" | "actionCreate" | "actionUpdate" | "actionDelete" | "actionExport" | null | undefined;
5
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
6
+ /**
7
+ * Visual status label used for short categorical values like case state, action type,
8
+ * or approval result. Badges truncate long text and surface the full label via `title`.
9
+ */
10
+ export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
11
+ }
12
+ declare function Badge({ className, variant, children, ...props }: BadgeProps): import("react/jsx-runtime").JSX.Element;
13
+ export { Badge, badgeVariants };
package/dist/badge.js ADDED
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "./lib/utils";
5
+ const badgeVariants = cva("inline-flex items-center justify-center rounded-md border px-1.5 py-1 text-[11px] font-semibold leading-none uppercase transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 max-w-[200px] truncate", {
6
+ variants: {
7
+ variant: {
8
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
9
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
10
+ muted: "border-transparent bg-muted text-muted-foreground",
11
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
12
+ outline: "text-foreground",
13
+ success: "border-transparent bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300",
14
+ warning: "border-transparent bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300",
15
+ info: "border-transparent bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",
16
+ actionRead: "border-transparent bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300",
17
+ actionCreate: "border-transparent bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300",
18
+ actionUpdate: "border-transparent bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-300",
19
+ actionDelete: "border-transparent bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300",
20
+ actionExport: "border-transparent bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ },
26
+ });
27
+ function Badge({ className, variant, children, ...props }) {
28
+ const textContent = typeof children === "string"
29
+ ? children
30
+ : React.Children.toArray(children)
31
+ .filter((child) => typeof child === "string")
32
+ .join("");
33
+ return (_jsx("div", { className: cn(badgeVariants({ variant }), className), title: textContent || undefined, ...props, children: children }));
34
+ }
35
+ export { Badge, badgeVariants };
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "secondary" | "destructive" | "outline" | "link" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
+ /**
9
+ * When `true`, renders the button styles onto the child element instead of a native `<button>`.
10
+ * Use this for links or custom interactive elements that should look like a button.
11
+ */
12
+ asChild?: boolean;
13
+ /**
14
+ * Shows a loading indicator, disables interaction, and sets `aria-busy`.
15
+ * When used with `asChild`, the component also prevents click handling and sets `aria-disabled`.
16
+ */
17
+ loading?: boolean;
18
+ /**
19
+ * Optional replacement label shown while `loading` is active.
20
+ * When omitted, the existing `children` content stays visible next to the spinner.
21
+ */
22
+ loadingText?: React.ReactNode;
23
+ /**
24
+ * Optional custom loading indicator. Defaults to a small circular spinner.
25
+ */
26
+ loadingIndicator?: React.ReactNode;
27
+ }
28
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
29
+ export { Button, buttonVariants };
package/dist/button.js ADDED
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import { cva } from "class-variance-authority";
5
+ import { cn } from "./lib/utils";
6
+ const buttonVariants = cva("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0", {
7
+ variants: {
8
+ variant: {
9
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
10
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
11
+ outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
12
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
13
+ ghost: "hover:bg-accent hover:text-accent-foreground",
14
+ link: "text-primary underline-offset-4 hover:underline",
15
+ },
16
+ size: {
17
+ default: "h-10 px-4 py-2 [&_svg]:h-4 [&_svg]:w-4",
18
+ sm: "h-9 rounded-md px-3 [&_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-5 [&_svg]:w-5",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ size: "default",
26
+ },
27
+ });
28
+ function DefaultLoadingIndicator() {
29
+ return (_jsx("span", { "aria-hidden": "true", className: "h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent" }));
30
+ }
31
+ function hasTextLikeContent(node) {
32
+ if (typeof node === "string") {
33
+ return node.trim().length > 0;
34
+ }
35
+ if (typeof node === "number") {
36
+ return true;
37
+ }
38
+ if (node == null || typeof node === "boolean") {
39
+ return false;
40
+ }
41
+ if (Array.isArray(node)) {
42
+ return node.some(hasTextLikeContent);
43
+ }
44
+ if (React.isValidElement(node)) {
45
+ if (node.type === "svg") {
46
+ return false;
47
+ }
48
+ return hasTextLikeContent(node.props.children);
49
+ }
50
+ return false;
51
+ }
52
+ const Button = React.forwardRef(({ className, variant, size, asChild = false, loading = false, loadingText, loadingIndicator, disabled, children, onClick, tabIndex, ...props }, ref) => {
53
+ const Comp = asChild ? Slot : "button";
54
+ const isDisabled = disabled || loading;
55
+ const loadingLabel = loadingText !== null && loadingText !== void 0 ? loadingText : children;
56
+ if (size === "icon" && hasTextLikeContent(children)) {
57
+ throw new Error('NEA Button `size="icon"` only accepts icon components or SVG content. Do not pass text or emoji.');
58
+ }
59
+ const content = loading ? (loadingLabel ? (_jsxs("span", { className: "inline-flex items-center gap-2", children: [loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}), _jsx("span", { children: loadingLabel })] })) : (loadingIndicator !== null && loadingIndicator !== void 0 ? loadingIndicator : _jsx(DefaultLoadingIndicator, {}))) : (children);
60
+ const handleClick = (event) => {
61
+ if (isDisabled && asChild) {
62
+ event.preventDefault();
63
+ event.stopPropagation();
64
+ return;
65
+ }
66
+ onClick === null || onClick === void 0 ? void 0 : onClick(event);
67
+ };
68
+ return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, "aria-busy": loading || undefined, "aria-disabled": isDisabled || undefined, "data-loading": loading ? "" : undefined, "data-disabled": isDisabled ? "" : undefined, onClick: handleClick, tabIndex: isDisabled && asChild ? -1 : tabIndex, disabled: !asChild ? isDisabled : undefined, ...props, children: content }));
69
+ });
70
+ Button.displayName = "Button";
71
+ export { Button, buttonVariants };
@@ -0,0 +1,9 @@
1
+ export { Badge, badgeVariants } from "./badge";
2
+ export type { BadgeProps } from "./badge";
3
+ export { Button, buttonVariants } from "./button";
4
+ export type { ButtonProps } from "./button";
5
+ export { neaPalette, semanticColorTokens } from "./theme";
6
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, } from "./table";
7
+ export { Tabs, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
8
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./tooltip";
9
+ export { cn } from "./lib/utils";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { Badge, badgeVariants } from "./badge";
2
+ export { Button, buttonVariants } from "./button";
3
+ export { neaPalette, semanticColorTokens } from "./theme";
4
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, } from "./table";
5
+ export { Tabs, TabsList, TabsTrigger, TabsContent, useTabsContext, } from "./tabs";
6
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./tooltip";
7
+ export { cn } from "./lib/utils";
@@ -0,0 +1,2 @@
1
+ import { type ClassValue } from "clsx";
2
+ export declare function cn(...inputs: ClassValue[]): string;
@@ -0,0 +1,5 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
@@ -0,0 +1,102 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --nea-green-50: 140 57% 96%;
8
+ --nea-green-100: 141 50% 90%;
9
+ --nea-green-200: 142 45% 80%;
10
+ --nea-green-300: 143 44% 67%;
11
+ --nea-green-400: 144 50% 53%;
12
+ --nea-green-500: 144 66% 40%;
13
+ --nea-green-600: 144 84% 33%;
14
+ --nea-green-700: 144 100% 27.5%;
15
+ --nea-green-800: 145 100% 21%;
16
+ --nea-green-900: 146 100% 15%;
17
+
18
+ --nea-neutral-0: 0 0% 100%;
19
+ --nea-neutral-50: 210 20% 98%;
20
+ --nea-neutral-100: 210 18% 96%;
21
+ --nea-neutral-200: 214 17% 91%;
22
+ --nea-neutral-300: 215 16% 84%;
23
+ --nea-neutral-400: 215 16% 65%;
24
+ --nea-neutral-500: 215 16% 47%;
25
+ --nea-neutral-600: 217 19% 27%;
26
+ --nea-neutral-700: 222 20% 18%;
27
+ --nea-neutral-800: 222 36% 11%;
28
+ --nea-neutral-900: 222 84% 5%;
29
+
30
+ --background: var(--nea-neutral-0);
31
+ --foreground: var(--nea-neutral-900);
32
+
33
+ --card: var(--nea-neutral-0);
34
+ --card-foreground: var(--nea-neutral-900);
35
+
36
+ --popover: var(--nea-neutral-0);
37
+ --popover-foreground: var(--nea-neutral-900);
38
+
39
+ --primary: var(--nea-green-700);
40
+ --primary-foreground: var(--nea-neutral-0);
41
+
42
+ --secondary: var(--nea-neutral-100);
43
+ --secondary-foreground: 222.2 47.4% 11.2%;
44
+
45
+ --muted: var(--nea-neutral-100);
46
+ --muted-foreground: var(--nea-neutral-500);
47
+
48
+ --accent: var(--nea-neutral-100);
49
+ --accent-foreground: 222.2 47.4% 11.2%;
50
+
51
+ --destructive: 0 84.2% 60.2%;
52
+ --destructive-foreground: 210 40% 98%;
53
+
54
+ --border: var(--nea-neutral-200);
55
+ --input: var(--nea-neutral-200);
56
+ --ring: var(--nea-green-700);
57
+
58
+ --radius: 0.5rem;
59
+ }
60
+
61
+ .dark {
62
+ --background: 222.2 84% 4.9%;
63
+ --foreground: 210 40% 98%;
64
+
65
+ --card: 222.2 84% 4.9%;
66
+ --card-foreground: 210 40% 98%;
67
+
68
+ --popover: 222.2 84% 4.9%;
69
+ --popover-foreground: 210 40% 98%;
70
+
71
+ --primary: 210 40% 98%;
72
+ --primary-foreground: 222.2 47.4% 11.2%;
73
+
74
+ --secondary: 217.2 32.6% 17.5%;
75
+ --secondary-foreground: 210 40% 98%;
76
+
77
+ --muted: 217.2 32.6% 17.5%;
78
+ --muted-foreground: 215 20.2% 65.1%;
79
+
80
+ --accent: 217.2 32.6% 17.5%;
81
+ --accent-foreground: 210 40% 98%;
82
+
83
+ --destructive: 0 62.8% 30.6%;
84
+ --destructive-foreground: 210 40% 98%;
85
+
86
+ --border: 217.2 32.6% 17.5%;
87
+ --input: 217.2 32.6% 17.5%;
88
+ --ring: 212.7 26.8% 83.9%;
89
+ }
90
+
91
+ * {
92
+ @apply border-border;
93
+ }
94
+
95
+ html {
96
+ font-size: 14px;
97
+ }
98
+
99
+ body {
100
+ @apply bg-background text-foreground;
101
+ }
102
+ }
@@ -0,0 +1,23 @@
1
+ import * as React from "react";
2
+ interface TableProps extends React.HTMLAttributes<HTMLTableElement> {
3
+ wrapperClassName?: string;
4
+ }
5
+ declare const Table: React.ForwardRefExoticComponent<TableProps & React.RefAttributes<HTMLTableElement>>;
6
+ declare const TableHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
7
+ declare const TableBody: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
8
+ declare const TableFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableSectionElement> & React.RefAttributes<HTMLTableSectionElement>>;
9
+ declare const TableRow: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableRowElement> & React.RefAttributes<HTMLTableRowElement>>;
10
+ declare const TableHead: React.ForwardRefExoticComponent<React.ThHTMLAttributes<HTMLTableCellElement> & {
11
+ width?: string;
12
+ minWidth?: string;
13
+ maxWidth?: string;
14
+ wrap?: boolean;
15
+ } & React.RefAttributes<HTMLTableCellElement>>;
16
+ declare const TableCell: React.ForwardRefExoticComponent<React.TdHTMLAttributes<HTMLTableCellElement> & {
17
+ width?: string;
18
+ minWidth?: string;
19
+ maxWidth?: string;
20
+ wrap?: boolean;
21
+ } & React.RefAttributes<HTMLTableCellElement>>;
22
+ declare const TableCaption: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLTableCaptionElement> & React.RefAttributes<HTMLTableCaptionElement>>;
23
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, };
package/dist/table.js ADDED
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "./lib/utils";
4
+ const Table = React.forwardRef(({ className, wrapperClassName, ...props }, ref) => (_jsx("div", { className: cn("w-full overflow-x-auto", wrapperClassName), children: _jsx("table", { ref: ref, className: cn("w-full caption-bottom text-sm", className), ...props }) })));
5
+ Table.displayName = "Table";
6
+ const TableHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("thead", { ref: ref, className: cn("bg-muted [&_tr]:border-b", className), ...props })));
7
+ TableHeader.displayName = "TableHeader";
8
+ const TableBody = React.forwardRef(({ className, ...props }, ref) => (_jsx("tbody", { ref: ref, className: cn("[&_tr:last-child]:border-0", className), ...props })));
9
+ TableBody.displayName = "TableBody";
10
+ const TableFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("tfoot", { ref: ref, className: cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className), ...props })));
11
+ TableFooter.displayName = "TableFooter";
12
+ const TableRow = React.forwardRef(({ className, ...props }, ref) => (_jsx("tr", { ref: ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props })));
13
+ TableRow.displayName = "TableRow";
14
+ const TableHead = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, ...props }, ref) => (_jsx("th", { ref: ref, className: cn("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0", wrap ? "whitespace-normal" : "whitespace-nowrap", className), style: {
15
+ ...style,
16
+ ...(width ? { width } : {}),
17
+ ...(minWidth ? { minWidth } : {}),
18
+ ...(maxWidth ? { maxWidth } : {}),
19
+ }, ...props })));
20
+ TableHead.displayName = "TableHead";
21
+ const TableCell = React.forwardRef(({ className, style, width, minWidth, maxWidth, wrap = false, ...props }, ref) => (_jsx("td", { ref: ref, className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", wrap ? "whitespace-normal" : "whitespace-nowrap", className), style: {
22
+ ...style,
23
+ ...(width ? { width } : {}),
24
+ ...(minWidth ? { minWidth } : {}),
25
+ ...(maxWidth ? { maxWidth } : {}),
26
+ }, ...props })));
27
+ TableCell.displayName = "TableCell";
28
+ const TableCaption = React.forwardRef(({ className, ...props }, ref) => (_jsx("caption", { ref: ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props })));
29
+ TableCaption.displayName = "TableCaption";
30
+ export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, };
package/dist/tabs.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ type TabsContextValue = {
3
+ value: string;
4
+ setValue: (value: string) => void;
5
+ };
6
+ export declare function useTabsContext(): TabsContextValue | null;
7
+ interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {
8
+ defaultValue: string;
9
+ value?: string;
10
+ onValueChange?: (value: string) => void;
11
+ }
12
+ declare function Tabs({ defaultValue, value: valueProp, onValueChange, className, children, ...props }: TabsProps): import("react/jsx-runtime").JSX.Element;
13
+ declare const TabsList: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
14
+ interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
15
+ value: string;
16
+ }
17
+ declare const TabsTrigger: React.ForwardRefExoticComponent<TabsTriggerProps & React.RefAttributes<HTMLButtonElement>>;
18
+ interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {
19
+ value: string;
20
+ }
21
+ declare const TabsContent: React.ForwardRefExoticComponent<TabsContentProps & React.RefAttributes<HTMLDivElement>>;
22
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
package/dist/tabs.js ADDED
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { cn } from "./lib/utils";
5
+ const TabsContext = React.createContext(null);
6
+ export function useTabsContext() {
7
+ return React.useContext(TabsContext);
8
+ }
9
+ function Tabs({ defaultValue, value: valueProp, onValueChange, className, children, ...props }) {
10
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
11
+ const isControlled = valueProp !== undefined;
12
+ const value = isControlled ? valueProp : uncontrolledValue;
13
+ const setValue = React.useCallback((next) => {
14
+ if (!isControlled)
15
+ setUncontrolledValue(next);
16
+ onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(next);
17
+ }, [isControlled, onValueChange]);
18
+ const ctx = React.useMemo(() => ({ value, setValue }), [value, setValue]);
19
+ return (_jsx(TabsContext.Provider, { value: ctx, children: _jsx("div", { className: cn(className), ...props, children: children }) }));
20
+ }
21
+ const TabsList = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("inline-flex h-fit items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground", className), ...props })));
22
+ TabsList.displayName = "TabsList";
23
+ const TabsTrigger = React.forwardRef(({ className, value, disabled, ...props }, ref) => {
24
+ const ctx = React.useContext(TabsContext);
25
+ if (!ctx) {
26
+ throw new Error("TabsTrigger must be used within Tabs");
27
+ }
28
+ const isActive = ctx.value === value;
29
+ return (_jsx("button", { ref: ref, type: "button", onClick: () => !disabled && ctx.setValue(value), "data-state": isActive ? "active" : "inactive", disabled: disabled, className: cn("inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm", className), ...props }));
30
+ });
31
+ TabsTrigger.displayName = "TabsTrigger";
32
+ const TabsContent = React.forwardRef(({ className, value, ...props }, ref) => {
33
+ const ctx = React.useContext(TabsContext);
34
+ if (!ctx) {
35
+ throw new Error("TabsContent must be used within Tabs");
36
+ }
37
+ if (ctx.value !== value)
38
+ return null;
39
+ return (_jsx("div", { ref: ref, className: cn("focus-visible:outline-none", className), ...props }));
40
+ });
41
+ TabsContent.displayName = "TabsContent";
42
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,112 @@
1
+ export declare const neaPalette: {
2
+ readonly green: readonly [{
3
+ readonly name: "Green 50";
4
+ readonly token: "--nea-green-50";
5
+ }, {
6
+ readonly name: "Green 100";
7
+ readonly token: "--nea-green-100";
8
+ }, {
9
+ readonly name: "Green 200";
10
+ readonly token: "--nea-green-200";
11
+ }, {
12
+ readonly name: "Green 300";
13
+ readonly token: "--nea-green-300";
14
+ }, {
15
+ readonly name: "Green 400";
16
+ readonly token: "--nea-green-400";
17
+ }, {
18
+ readonly name: "Green 500";
19
+ readonly token: "--nea-green-500";
20
+ }, {
21
+ readonly name: "Green 600";
22
+ readonly token: "--nea-green-600";
23
+ }, {
24
+ readonly name: "Green 700";
25
+ readonly token: "--nea-green-700";
26
+ }, {
27
+ readonly name: "Green 800";
28
+ readonly token: "--nea-green-800";
29
+ }, {
30
+ readonly name: "Green 900";
31
+ readonly token: "--nea-green-900";
32
+ }];
33
+ readonly neutral: readonly [{
34
+ readonly name: "Neutral 0";
35
+ readonly token: "--nea-neutral-0";
36
+ }, {
37
+ readonly name: "Neutral 50";
38
+ readonly token: "--nea-neutral-50";
39
+ }, {
40
+ readonly name: "Neutral 100";
41
+ readonly token: "--nea-neutral-100";
42
+ }, {
43
+ readonly name: "Neutral 200";
44
+ readonly token: "--nea-neutral-200";
45
+ }, {
46
+ readonly name: "Neutral 300";
47
+ readonly token: "--nea-neutral-300";
48
+ }, {
49
+ readonly name: "Neutral 400";
50
+ readonly token: "--nea-neutral-400";
51
+ }, {
52
+ readonly name: "Neutral 500";
53
+ readonly token: "--nea-neutral-500";
54
+ }, {
55
+ readonly name: "Neutral 600";
56
+ readonly token: "--nea-neutral-600";
57
+ }, {
58
+ readonly name: "Neutral 700";
59
+ readonly token: "--nea-neutral-700";
60
+ }, {
61
+ readonly name: "Neutral 800";
62
+ readonly token: "--nea-neutral-800";
63
+ }, {
64
+ readonly name: "Neutral 900";
65
+ readonly token: "--nea-neutral-900";
66
+ }];
67
+ };
68
+ export declare const semanticColorTokens: readonly [{
69
+ readonly name: "Background";
70
+ readonly token: "--background";
71
+ readonly foregroundToken: "--foreground";
72
+ }, {
73
+ readonly name: "Foreground";
74
+ readonly token: "--foreground";
75
+ }, {
76
+ readonly name: "Card";
77
+ readonly token: "--card";
78
+ readonly foregroundToken: "--card-foreground";
79
+ }, {
80
+ readonly name: "Popover";
81
+ readonly token: "--popover";
82
+ readonly foregroundToken: "--popover-foreground";
83
+ }, {
84
+ readonly name: "Primary";
85
+ readonly token: "--primary";
86
+ readonly foregroundToken: "--primary-foreground";
87
+ }, {
88
+ readonly name: "Secondary";
89
+ readonly token: "--secondary";
90
+ readonly foregroundToken: "--secondary-foreground";
91
+ }, {
92
+ readonly name: "Muted";
93
+ readonly token: "--muted";
94
+ readonly foregroundToken: "--muted-foreground";
95
+ }, {
96
+ readonly name: "Accent";
97
+ readonly token: "--accent";
98
+ readonly foregroundToken: "--accent-foreground";
99
+ }, {
100
+ readonly name: "Destructive";
101
+ readonly token: "--destructive";
102
+ readonly foregroundToken: "--destructive-foreground";
103
+ }, {
104
+ readonly name: "Border";
105
+ readonly token: "--border";
106
+ }, {
107
+ readonly name: "Input";
108
+ readonly token: "--input";
109
+ }, {
110
+ readonly name: "Ring";
111
+ readonly token: "--ring";
112
+ }];
package/dist/theme.js ADDED
@@ -0,0 +1,41 @@
1
+ export const neaPalette = {
2
+ green: [
3
+ { name: "Green 50", token: "--nea-green-50" },
4
+ { name: "Green 100", token: "--nea-green-100" },
5
+ { name: "Green 200", token: "--nea-green-200" },
6
+ { name: "Green 300", token: "--nea-green-300" },
7
+ { name: "Green 400", token: "--nea-green-400" },
8
+ { name: "Green 500", token: "--nea-green-500" },
9
+ { name: "Green 600", token: "--nea-green-600" },
10
+ { name: "Green 700", token: "--nea-green-700" },
11
+ { name: "Green 800", token: "--nea-green-800" },
12
+ { name: "Green 900", token: "--nea-green-900" },
13
+ ],
14
+ neutral: [
15
+ { name: "Neutral 0", token: "--nea-neutral-0" },
16
+ { name: "Neutral 50", token: "--nea-neutral-50" },
17
+ { name: "Neutral 100", token: "--nea-neutral-100" },
18
+ { name: "Neutral 200", token: "--nea-neutral-200" },
19
+ { name: "Neutral 300", token: "--nea-neutral-300" },
20
+ { name: "Neutral 400", token: "--nea-neutral-400" },
21
+ { name: "Neutral 500", token: "--nea-neutral-500" },
22
+ { name: "Neutral 600", token: "--nea-neutral-600" },
23
+ { name: "Neutral 700", token: "--nea-neutral-700" },
24
+ { name: "Neutral 800", token: "--nea-neutral-800" },
25
+ { name: "Neutral 900", token: "--nea-neutral-900" },
26
+ ],
27
+ };
28
+ export const semanticColorTokens = [
29
+ { name: "Background", token: "--background", foregroundToken: "--foreground" },
30
+ { name: "Foreground", token: "--foreground" },
31
+ { name: "Card", token: "--card", foregroundToken: "--card-foreground" },
32
+ { name: "Popover", token: "--popover", foregroundToken: "--popover-foreground" },
33
+ { name: "Primary", token: "--primary", foregroundToken: "--primary-foreground" },
34
+ { name: "Secondary", token: "--secondary", foregroundToken: "--secondary-foreground" },
35
+ { name: "Muted", token: "--muted", foregroundToken: "--muted-foreground" },
36
+ { name: "Accent", token: "--accent", foregroundToken: "--accent-foreground" },
37
+ { name: "Destructive", token: "--destructive", foregroundToken: "--destructive-foreground" },
38
+ { name: "Border", token: "--border" },
39
+ { name: "Input", token: "--input" },
40
+ { name: "Ring", token: "--ring" },
41
+ ];
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
3
+ declare const TooltipProvider: React.FC<TooltipPrimitive.TooltipProviderProps>;
4
+ declare const Tooltip: React.FC<TooltipPrimitive.TooltipProps>;
5
+ declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
6
+ declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
7
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,11 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
+ import { cn } from "./lib/utils";
6
+ const TooltipProvider = TooltipPrimitive.Provider;
7
+ const Tooltip = TooltipPrimitive.Root;
8
+ const TooltipTrigger = TooltipPrimitive.Trigger;
9
+ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (_jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { ref: ref, sideOffset: sideOffset, className: cn("z-50 overflow-hidden rounded-md bg-[#111827] px-3 py-1.5 text-sm text-white shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className), ...props }) })));
10
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
11
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
package/package.json ADDED
@@ -0,0 +1,95 @@
1
+ {
2
+ "name": "@neasg/design-system",
3
+ "version": "0.1.3",
4
+ "description": "NEA shared design system primitives, theme tokens, and Storybook docs.",
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "sideEffects": [
11
+ "./dist/styles.css"
12
+ ],
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.build.json && node scripts/copy-css.mjs",
19
+ "storybook": "storybook dev -p 6007 -c .storybook",
20
+ "build-storybook": "storybook build -c .storybook",
21
+ "test": "vitest run",
22
+ "prepublishOnly": "npm test && npm run build"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public",
26
+ "registry": "https://registry.npmjs.org/"
27
+ },
28
+ "peerDependencies": {
29
+ "react": "^18.2.0",
30
+ "react-dom": "^18.2.0"
31
+ },
32
+ "dependencies": {
33
+ "@radix-ui/react-slot": "^1.2.4",
34
+ "@radix-ui/react-tooltip": "^1.2.8",
35
+ "class-variance-authority": "^0.7.0",
36
+ "clsx": "^2.1.1",
37
+ "tailwind-merge": "^2.3.0"
38
+ },
39
+ "devDependencies": {
40
+ "@storybook/addon-docs": "10.2.19",
41
+ "@storybook/addon-themes": "10.2.19",
42
+ "@storybook/react": "10.2.19",
43
+ "@storybook/react-vite": "10.2.19",
44
+ "@testing-library/jest-dom": "^6.9.1",
45
+ "@types/node": "^20.10.5",
46
+ "@types/react": "^18.2.45",
47
+ "@types/react-dom": "^18.2.18",
48
+ "@vitejs/plugin-react": "^6.0.1",
49
+ "autoprefixer": "^10.4.16",
50
+ "jsdom": "^29.0.0",
51
+ "postcss": "^8.4.31",
52
+ "react": "^18.2.0",
53
+ "react-dom": "^18.2.0",
54
+ "storybook": "10.2.19",
55
+ "tailwindcss": "^3.4.1",
56
+ "tailwindcss-animate": "^1.0.7",
57
+ "typescript": "^5.3.3",
58
+ "vitest": "^4.1.0"
59
+ },
60
+ "exports": {
61
+ ".": {
62
+ "types": "./dist/index.d.ts",
63
+ "import": "./dist/index.js"
64
+ },
65
+ "./badge": {
66
+ "types": "./dist/badge.d.ts",
67
+ "import": "./dist/badge.js"
68
+ },
69
+ "./button": {
70
+ "types": "./dist/button.d.ts",
71
+ "import": "./dist/button.js"
72
+ },
73
+ "./styles.css": "./dist/styles.css",
74
+ "./table": {
75
+ "types": "./dist/table.d.ts",
76
+ "import": "./dist/table.js"
77
+ },
78
+ "./tabs": {
79
+ "types": "./dist/tabs.d.ts",
80
+ "import": "./dist/tabs.js"
81
+ },
82
+ "./theme": {
83
+ "types": "./dist/theme.d.ts",
84
+ "import": "./dist/theme.js"
85
+ },
86
+ "./tooltip": {
87
+ "types": "./dist/tooltip.d.ts",
88
+ "import": "./dist/tooltip.js"
89
+ },
90
+ "./lib/utils": {
91
+ "types": "./dist/lib/utils.d.ts",
92
+ "import": "./dist/lib/utils.js"
93
+ }
94
+ }
95
+ }