diff --git a/packages/ui/eslint.config.mjs b/packages/ui/eslint.config.mjs index d6a0cd0..5f0534a 100644 --- a/packages/ui/eslint.config.mjs +++ b/packages/ui/eslint.config.mjs @@ -1,28 +1,31 @@ -import reactConfig from '@tpmjs/eslint-config/react.js'; +import reactConfig from "@tpmjs/eslint-config/react.js"; export default [ - { - ignores: ['dist/**', 'node_modules/**', 'eslint.config.mjs'] - }, - ...reactConfig, - { - rules: { - 'import/no-internal-modules': ['error', { - allow: [ - '@tpmjs/ui/*/[!index]*', - '@tpmjs/utils/*', - '@tpmjs/types/*', - '@tpmjs/eslint-config/*', - '@testing-library/**', - 'react/*', - ] - }], - } - }, - { - files: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'], - rules: { - 'jsx-a11y/no-autofocus': 'off', - } - } + { + ignores: ["dist/**", "node_modules/**", "eslint.config.mjs"], + }, + ...reactConfig, + { + rules: { + "import/no-internal-modules": [ + "error", + { + allow: [ + "@tpmjs/ui/*/[!index]*", + "@tpmjs/utils/*", + "@tpmjs/types/*", + "@tpmjs/eslint-config/*", + "@testing-library/**", + "react/*", + ], + }, + ], + }, + }, + { + files: ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"], + rules: { + "jsx-a11y/no-autofocus": "off", + }, + }, ]; diff --git a/packages/ui/src/Badge/Badge.test.tsx b/packages/ui/src/Badge/Badge.test.tsx index 33abfdf..236ca3a 100644 --- a/packages/ui/src/Badge/Badge.test.tsx +++ b/packages/ui/src/Badge/Badge.test.tsx @@ -250,7 +250,7 @@ describe("Badge", () => { , ); expect(ref).toBeInstanceOf(HTMLDivElement); - expect(ref!.tagName).toBe("DIV"); + expect(ref?.tagName).toBe("DIV"); }); }); @@ -297,11 +297,7 @@ describe("Badge", () => { it("works correctly with outline variant and custom className", () => { render( - + Outlined , ); @@ -355,12 +351,7 @@ describe("Badge", () => { describe("Semantic Usage", () => { it("can be used as status indicator with role", () => { render( - + Online , ); @@ -372,12 +363,7 @@ describe("Badge", () => { it("can be used as notification count", () => { render( - + 3 , ); diff --git a/packages/ui/src/Badge/types.ts b/packages/ui/src/Badge/types.ts index 0264f6f..5726667 100644 --- a/packages/ui/src/Badge/types.ts +++ b/packages/ui/src/Badge/types.ts @@ -8,14 +8,7 @@ export interface BadgeProps extends HTMLAttributes { * Visual variant of the badge * @default 'default' */ - variant?: - | "default" - | "secondary" - | "outline" - | "success" - | "error" - | "warning" - | "info"; + variant?: "default" | "secondary" | "outline" | "success" | "error" | "warning" | "info"; /** * Size of the badge diff --git a/packages/ui/src/Badge/variants.ts b/packages/ui/src/Badge/variants.ts index 35dff41..61f6a49 100644 --- a/packages/ui/src/Badge/variants.ts +++ b/packages/ui/src/Badge/variants.ts @@ -19,33 +19,17 @@ export const badgeVariants = createVariants({ variants: { variant: { - default: [ - "bg-primary text-primary-foreground", - "border border-primary", - ].join(" "), + default: ["bg-primary text-primary-foreground", "border border-primary"].join(" "), - secondary: [ - "bg-secondary text-secondary-foreground", - "border border-secondary", - ].join(" "), + secondary: ["bg-secondary text-secondary-foreground", "border border-secondary"].join(" "), - outline: ["bg-transparent text-foreground", "border border-border"].join( - " ", - ), + outline: ["bg-transparent text-foreground", "border border-border"].join(" "), - success: [ - "bg-success text-success-foreground", - "border border-success", - ].join(" "), + success: ["bg-success text-success-foreground", "border border-success"].join(" "), - error: ["bg-error text-error-foreground", "border border-error"].join( - " ", - ), + error: ["bg-error text-error-foreground", "border border-error"].join(" "), - warning: [ - "bg-warning text-warning-foreground", - "border border-warning", - ].join(" "), + warning: ["bg-warning text-warning-foreground", "border border-warning"].join(" "), info: ["bg-info text-info-foreground", "border border-info"].join(" "), }, diff --git a/packages/ui/src/Button/Button.test.tsx b/packages/ui/src/Button/Button.test.tsx index 147832d..897b560 100644 --- a/packages/ui/src/Button/Button.test.tsx +++ b/packages/ui/src/Button/Button.test.tsx @@ -119,9 +119,7 @@ describe("Button", () => { }); it("applies icon size classes", () => { - render( - , ); expect(ref).toBeInstanceOf(HTMLButtonElement); - expect(ref!.tagName).toBe("BUTTON"); + expect(ref?.tagName).toBe("BUTTON"); }); }); describe("HTML Attributes", () => { it("passes through HTML button attributes", () => { render( - , ); diff --git a/packages/ui/src/Button/variants.ts b/packages/ui/src/Button/variants.ts index 3fa6a7e..f3f024f 100644 --- a/packages/ui/src/Button/variants.ts +++ b/packages/ui/src/Button/variants.ts @@ -65,11 +65,9 @@ export const buttonVariants = createVariants({ "active:bg-accent/80", ].join(" "), - link: [ - "text-primary underline-offset-4", - "hover:underline", - "active:text-primary/80", - ].join(" "), + link: ["text-primary underline-offset-4", "hover:underline", "active:text-primary/80"].join( + " ", + ), }, size: { diff --git a/packages/ui/src/Card/Card.test.tsx b/packages/ui/src/Card/Card.test.tsx index 3696eae..3c62ce0 100644 --- a/packages/ui/src/Card/Card.test.tsx +++ b/packages/ui/src/Card/Card.test.tsx @@ -1,13 +1,6 @@ import { render, screen } from "@testing-library/react"; import { describe, expect, it } from "vitest"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "./Card"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./Card"; describe("Card", () => { describe("Rendering", () => { @@ -23,9 +16,7 @@ describe("Card", () => { Title - - Description - + Description Content Footer @@ -236,9 +227,7 @@ describe("Card", () => { render( - - Description text - + Description text , ); @@ -250,9 +239,7 @@ describe("Card", () => { render( - - Description - + Description , ); @@ -417,7 +404,7 @@ describe("Card", () => { , ); expect(ref).toBeInstanceOf(HTMLDivElement); - expect(ref!.tagName).toBe("DIV"); + expect(ref?.tagName).toBe("DIV"); }); it("forwards ref to CardHeader element", () => { @@ -452,7 +439,7 @@ describe("Card", () => { , ); expect(ref).toBeInstanceOf(HTMLHeadingElement); - expect(ref!.tagName).toBe("H3"); + expect(ref?.tagName).toBe("H3"); }); it("forwards ref to CardDescription element", () => { @@ -574,9 +561,7 @@ describe("Card", () => { render( - - Description - + Description , ); @@ -606,9 +591,7 @@ describe("Card", () => { Card Title This is a card description - - Card content goes here - + Card content goes here Footer actions , ); @@ -616,9 +599,7 @@ describe("Card", () => { const card = screen.getByTestId("card"); expect(card).toBeInTheDocument(); expect(screen.getByText("Card Title")).toBeInTheDocument(); - expect( - screen.getByText("This is a card description"), - ).toBeInTheDocument(); + expect(screen.getByText("This is a card description")).toBeInTheDocument(); expect(screen.getByText("Card content goes here")).toBeInTheDocument(); expect(screen.getByText("Footer actions")).toBeInTheDocument(); }); diff --git a/packages/ui/src/Card/Card.tsx b/packages/ui/src/Card/Card.tsx index d458f9f..8b2f644 100644 --- a/packages/ui/src/Card/Card.tsx +++ b/packages/ui/src/Card/Card.tsx @@ -93,13 +93,7 @@ CardHeader.displayName = "CardHeader"; export const CardTitle = forwardRef( ({ className, as = "h3", ...props }, ref) => { const Component = as; - return ( - - ); + return ; }, ); @@ -110,18 +104,11 @@ CardTitle.displayName = "CardTitle"; * * Description text for a card, typically placed below the title. */ -export const CardDescription = forwardRef< - HTMLParagraphElement, - CardDescriptionProps ->(({ className, ...props }, ref) => { - return ( -

- ); -}); +export const CardDescription = forwardRef( + ({ className, ...props }, ref) => { + return

; + }, +); CardDescription.displayName = "CardDescription"; diff --git a/packages/ui/src/Card/variants.ts b/packages/ui/src/Card/variants.ts index 115e98b..3499ef8 100644 --- a/packages/ui/src/Card/variants.ts +++ b/packages/ui/src/Card/variants.ts @@ -28,10 +28,7 @@ export const cardVariants = createVariants({ "shadow-md", ].join(" "), - outline: [ - "border-2 border-dotted border-border", - "bg-transparent text-foreground", - ].join(" "), + outline: ["border-2 border-dotted border-border", "bg-transparent text-foreground"].join(" "), blueprint: [ "border border-dotted border-border", @@ -85,10 +82,7 @@ export const cardHeaderVariants = createVariants({ * CardTitle variant definitions */ export const cardTitleVariants = createVariants({ - base: [ - "text-2xl font-semibold leading-none tracking-tight", - "text-foreground", - ].join(" "), + base: ["text-2xl font-semibold leading-none tracking-tight", "text-foreground"].join(" "), variants: {}, diff --git a/packages/ui/src/CodeBlock/CodeBlock.test.tsx b/packages/ui/src/CodeBlock/CodeBlock.test.tsx index d6297cd..c8407af 100644 --- a/packages/ui/src/CodeBlock/CodeBlock.test.tsx +++ b/packages/ui/src/CodeBlock/CodeBlock.test.tsx @@ -50,13 +50,7 @@ describe("CodeBlock", () => { describe("Language", () => { it("sets data-language attribute", () => { - render( - , - ); + render(); const codeblock = screen.getByTestId("codeblock"); const code = codeblock.querySelector("code"); expect(code).toHaveAttribute("data-language", "javascript"); @@ -77,9 +71,7 @@ describe("CodeBlock", () => { let code = codeblock.querySelector("code"); expect(code).toHaveAttribute("data-language", "python"); - rerender( - , - ); + rerender(); codeblock = screen.getByTestId("codeblock"); code = codeblock.querySelector("code"); expect(code).toHaveAttribute("data-language", "bash"); @@ -223,12 +215,8 @@ describe("CodeBlock", () => { }); it("handles clipboard API errors gracefully", async () => { - const consoleErrorSpy = vi - .spyOn(console, "error") - .mockImplementation(() => {}); - mockClipboard.writeText.mockRejectedValueOnce( - new Error("Clipboard not available"), - ); + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + mockClipboard.writeText.mockRejectedValueOnce(new Error("Clipboard not available")); try { render(); @@ -249,17 +237,13 @@ describe("CodeBlock", () => { describe("HTML Attributes", () => { it("passes through id attribute", () => { - render( - , - ); + render(); const codeblock = screen.getByTestId("codeblock"); expect(codeblock).toHaveAttribute("id", "codeblock-id"); }); it("passes through data attributes", () => { - render( - , - ); + render(); const codeblock = screen.getByTestId("codeblock"); expect(codeblock).toHaveAttribute("data-custom", "test"); }); @@ -267,13 +251,7 @@ describe("CodeBlock", () => { describe("Custom className", () => { it("merges custom className with variant classes", () => { - render( - , - ); + render(); const codeblock = screen.getByTestId("codeblock"); expect(codeblock.className).toContain("custom-class"); expect(codeblock.className).toContain("bg-background"); @@ -293,7 +271,7 @@ describe("CodeBlock", () => { />, ); expect(ref).toBeInstanceOf(HTMLDivElement); - expect(ref!.querySelector("code")).toBeInTheDocument(); + expect(ref?.querySelector("code")).toBeInTheDocument(); }); }); diff --git a/packages/ui/src/CodeBlock/CodeBlock.tsx b/packages/ui/src/CodeBlock/CodeBlock.tsx index 50dc9e8..46585ff 100644 --- a/packages/ui/src/CodeBlock/CodeBlock.tsx +++ b/packages/ui/src/CodeBlock/CodeBlock.tsx @@ -32,17 +32,7 @@ import { * ``` */ export const CodeBlock = forwardRef( - ( - { - className, - code, - language = "text", - size = "md", - showCopy = true, - ...props - }, - ref, - ) => { + ({ className, code, language = "text", size = "md", showCopy = true, ...props }, ref) => { const [copied, setCopied] = useState(false); const handleCopy = async () => { @@ -57,11 +47,7 @@ export const CodeBlock = forwardRef( }; return ( -

+
, "children"> { +export interface CodeBlockProps extends Omit, "children"> { /** * Code content to display */ diff --git a/packages/ui/src/Container/Container.test.tsx b/packages/ui/src/Container/Container.test.tsx index 997bc64..db90bf2 100644 --- a/packages/ui/src/Container/Container.test.tsx +++ b/packages/ui/src/Container/Container.test.tsx @@ -223,7 +223,7 @@ describe("Container", () => { , ); expect(ref).toBeInstanceOf(HTMLDivElement); - expect(ref!.tagName).toBe("DIV"); + expect(ref?.tagName).toBe("DIV"); }); }); diff --git a/packages/ui/src/GridContainer/GridContainer.test.tsx b/packages/ui/src/GridContainer/GridContainer.test.tsx index b863d15..92a5e2d 100644 --- a/packages/ui/src/GridContainer/GridContainer.test.tsx +++ b/packages/ui/src/GridContainer/GridContainer.test.tsx @@ -281,13 +281,7 @@ describe("GridContainer", () => { describe("Compound Scenarios", () => { it("works with multiple variants combined", () => { render( - + Content , ); @@ -300,12 +294,7 @@ describe("GridContainer", () => { it("works with fixed columns and custom className", () => { render( - + Content , ); diff --git a/packages/ui/src/Header/Header.test.tsx b/packages/ui/src/Header/Header.test.tsx index b73fca7..0dd6737 100644 --- a/packages/ui/src/Header/Header.test.tsx +++ b/packages/ui/src/Header/Header.test.tsx @@ -77,11 +77,7 @@ describe("Header", () => { }); it("renders ReactNode as actions", () => { - render( -
Custom Actions
} - />, - ); + render(
Custom Actions
} />); expect(screen.getByTestId("custom-actions")).toBeInTheDocument(); }); }); @@ -255,7 +251,7 @@ describe("Header", () => { />, ); expect(ref).toBeInstanceOf(HTMLElement); - expect(ref!.tagName).toBe("HEADER"); + expect(ref?.tagName).toBe("HEADER"); }); }); @@ -275,15 +271,7 @@ describe("Header", () => { describe("Compound Scenarios", () => { it("works correctly with large size and sticky", () => { - render( -
, - ); + render(
); const header = screen.getByTestId("header"); expect(header.className).toContain("h-20"); expect(header.className).toContain("px-8"); diff --git a/packages/ui/src/Header/Header.tsx b/packages/ui/src/Header/Header.tsx index 3acc0d7..6e620f2 100644 --- a/packages/ui/src/Header/Header.tsx +++ b/packages/ui/src/Header/Header.tsx @@ -1,11 +1,7 @@ import { cn } from "@tpmjs/utils/cn"; import { forwardRef } from "react"; import type { HeaderProps } from "./types"; -import { - headerActionsVariants, - headerTitleVariants, - headerVariants, -} from "./variants"; +import { headerActionsVariants, headerTitleVariants, headerVariants } from "./variants"; /** * Header component @@ -31,18 +27,7 @@ import { * ``` */ export const Header = forwardRef( - ( - { - className, - title, - actions, - size = "md", - sticky = false, - children, - ...props - }, - ref, - ) => { + ({ className, title, actions, size = "md", sticky = false, children, ...props }, ref) => { return (
( )} {children && ( -
+
{children}
)} diff --git a/packages/ui/src/Header/types.ts b/packages/ui/src/Header/types.ts index 7816818..b22848c 100644 --- a/packages/ui/src/Header/types.ts +++ b/packages/ui/src/Header/types.ts @@ -3,8 +3,7 @@ import type { HTMLAttributes, ReactNode } from "react"; /** * Header component props */ -export interface HeaderProps - extends Omit, "title"> { +export interface HeaderProps extends Omit, "title"> { /** * Title/logo content for the left side */ diff --git a/packages/ui/src/Icon/Icon.test.tsx b/packages/ui/src/Icon/Icon.test.tsx index aab4a9b..87c6ee4 100644 --- a/packages/ui/src/Icon/Icon.test.tsx +++ b/packages/ui/src/Icon/Icon.test.tsx @@ -119,10 +119,7 @@ describe("Icon", () => { render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); - expect(path).toHaveAttribute( - "d", - "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z", - ); + expect(path).toHaveAttribute("d", "M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z"); }); }); @@ -148,14 +145,7 @@ describe("Icon", () => { }); it("passes through aria-label", () => { - render( - , - ); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("aria-label", "Success"); }); @@ -179,7 +169,7 @@ describe("Icon", () => { />, ); expect(ref).toBeInstanceOf(SVGSVGElement); - expect(ref!.tagName).toBe("svg"); + expect(ref?.tagName).toBe("svg"); }); }); diff --git a/packages/ui/src/Icon/types.ts b/packages/ui/src/Icon/types.ts index f8007f3..400a112 100644 --- a/packages/ui/src/Icon/types.ts +++ b/packages/ui/src/Icon/types.ts @@ -4,8 +4,7 @@ import type { IconName } from "./icons"; /** * Icon component props */ -export interface IconProps - extends Omit, "children"> { +export interface IconProps extends Omit, "children"> { /** * Icon to display */ diff --git a/packages/ui/src/Input/Input.test.tsx b/packages/ui/src/Input/Input.test.tsx index 9d5ea4d..44e3f6e 100644 --- a/packages/ui/src/Input/Input.test.tsx +++ b/packages/ui/src/Input/Input.test.tsx @@ -196,9 +196,7 @@ describe("Input", () => { describe("Value and onChange", () => { it("renders with initial value", () => { - render( - {}} data-testid="input" />, - ); + render( {}} data-testid="input" />); const input = screen.getByTestId("input") as HTMLInputElement; expect(input.value).toBe("test value"); }); @@ -317,7 +315,7 @@ describe("Input", () => { />, ); expect(ref).toBeInstanceOf(HTMLInputElement); - expect(ref!.tagName).toBe("INPUT"); + expect(ref?.tagName).toBe("INPUT"); }); it("can focus input through ref", () => { @@ -330,7 +328,7 @@ describe("Input", () => { data-testid="input" />, ); - ref!.focus(); + ref?.focus(); expect(screen.getByTestId("input")).toHaveFocus(); }); }); diff --git a/packages/ui/src/Input/types.ts b/packages/ui/src/Input/types.ts index 94b6ac1..f51957d 100644 --- a/packages/ui/src/Input/types.ts +++ b/packages/ui/src/Input/types.ts @@ -3,8 +3,7 @@ import type { InputHTMLAttributes } from "react"; /** * Input component props */ -export interface InputProps - extends Omit, "size"> { +export interface InputProps extends Omit, "size"> { /** * Visual state of the input * @default 'default' diff --git a/packages/ui/src/Label/Label.test.tsx b/packages/ui/src/Label/Label.test.tsx index 8afeefd..93205bb 100644 --- a/packages/ui/src/Label/Label.test.tsx +++ b/packages/ui/src/Label/Label.test.tsx @@ -208,7 +208,7 @@ describe("Label", () => { , ); expect(ref).toBeInstanceOf(HTMLLabelElement); - expect(ref!.tagName).toBe("LABEL"); + expect(ref?.tagName).toBe("LABEL"); }); }); diff --git a/packages/ui/src/Label/Label.tsx b/packages/ui/src/Label/Label.tsx index b8e9420..b4c384a 100644 --- a/packages/ui/src/Label/Label.tsx +++ b/packages/ui/src/Label/Label.tsx @@ -18,17 +18,7 @@ import { labelVariants } from "./variants"; * ``` */ export const Label = forwardRef( - ( - { - className, - size = "md", - required = false, - disabled = false, - children, - ...props - }, - ref, - ) => { + ({ className, size = "md", required = false, disabled = false, children, ...props }, ref) => { return ( // biome-ignore lint/a11y/noLabelWithoutControl: This is a generic label component that can be used with htmlFor or wrap inputs