From b17349c0719bb2d174693cb1b5d4e0bac9f3a77a Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Wed, 26 Nov 2025 02:10:18 +1000 Subject: [PATCH] refactor(ui): convert Icon and Badge components to JSX syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Convert Icon component from createElement to JSX (Icon.tsx) - Convert Icon tests to JSX (24 tests passing) - Convert Icon stories to JSX (Icon.stories.tsx) - Convert Badge component from createElement to JSX (Badge.tsx) - Convert Badge tests to JSX (34 tests passing) - Rename files from .ts to .tsx - Remove createElement imports, use native JSX syntax - All tests passing (58/58) Part of broader effort to convert entire codebase from createElement to JSX. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/storybook/stories/Icon.stories.tsx | 62 +++ .../Badge/{Badge.test.ts => Badge.test.tsx} | 376 ++++++------------ packages/ui/src/Badge/{Badge.ts => Badge.tsx} | 35 +- .../src/Icon/{Icon.test.ts => Icon.test.tsx} | 135 ++----- packages/ui/src/Icon/{Icon.ts => Icon.tsx} | 38 +- 5 files changed, 254 insertions(+), 392 deletions(-) create mode 100644 packages/storybook/stories/Icon.stories.tsx rename packages/ui/src/Badge/{Badge.test.ts => Badge.test.tsx} (65%) rename packages/ui/src/Badge/{Badge.ts => Badge.tsx} (55%) rename packages/ui/src/Icon/{Icon.test.ts => Icon.test.tsx} (69%) rename packages/ui/src/Icon/{Icon.ts => Icon.tsx} (55%) diff --git a/packages/storybook/stories/Icon.stories.tsx b/packages/storybook/stories/Icon.stories.tsx new file mode 100644 index 0000000..9b8acfd --- /dev/null +++ b/packages/storybook/stories/Icon.stories.tsx @@ -0,0 +1,62 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Icon } from "@tpmjs/ui/Icon/Icon"; + +const meta = { + title: "Components/Icon", + component: Icon, + tags: ["autodocs"], + parameters: { + layout: "centered", + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const AllIcons: Story = { + render: () => ( +
+ {( + [ + "copy", + "externalLink", + "github", + "check", + "x", + "chevronDown", + "sun", + "moon", + ] as const + ).map((iconName) => ( +
+ + {iconName} +
+ ))} +
+ ), +}; + +export const AllSizes: Story = { + render: () => ( +
+ {(["sm", "md", "lg"] as const).map((size) => ( +
+ + {size} +
+ ))} +
+ ), +}; + +export const WithColors: Story = { + render: () => ( +
+ + + + +
+ ), +}; diff --git a/packages/ui/src/Badge/Badge.test.ts b/packages/ui/src/Badge/Badge.test.tsx similarity index 65% rename from packages/ui/src/Badge/Badge.test.ts rename to packages/ui/src/Badge/Badge.test.tsx index 5c9ad97..8c5d9c6 100644 --- a/packages/ui/src/Badge/Badge.test.ts +++ b/packages/ui/src/Badge/Badge.test.tsx @@ -1,19 +1,18 @@ import { render, screen } from "@testing-library/react"; -import { createElement } from "react"; import { describe, expect, it } from "vitest"; import { Badge } from "./Badge"; describe("Badge", () => { describe("Rendering", () => { it("renders a badge element", () => { - render(createElement(Badge, { "data-testid": "badge" }, "Badge")); + render(Badge); const badge = screen.getByTestId("badge"); expect(badge).toBeInTheDocument(); expect(badge.tagName).toBe("DIV"); }); it("renders children text", () => { - render(createElement(Badge, null, "Active")); + render(Active); expect(screen.getByText("Active")).toBeInTheDocument(); }); }); @@ -21,14 +20,9 @@ describe("Badge", () => { describe("Variants", () => { it("applies default variant classes", () => { render( - createElement( - Badge, - { - variant: "default", - "data-testid": "badge", - }, - "Default", - ), + + Default + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-primary"); @@ -38,14 +32,9 @@ describe("Badge", () => { it("applies secondary variant classes", () => { render( - createElement( - Badge, - { - variant: "secondary", - "data-testid": "badge", - }, - "Secondary", - ), + + Secondary + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-secondary"); @@ -54,14 +43,9 @@ describe("Badge", () => { it("applies outline variant classes", () => { render( - createElement( - Badge, - { - variant: "outline", - "data-testid": "badge", - }, - "Outline", - ), + + Outline + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-transparent"); @@ -71,14 +55,9 @@ describe("Badge", () => { it("applies success variant classes", () => { render( - createElement( - Badge, - { - variant: "success", - "data-testid": "badge", - }, - "Success", - ), + + Success + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-success"); @@ -87,14 +66,9 @@ describe("Badge", () => { it("applies error variant classes", () => { render( - createElement( - Badge, - { - variant: "error", - "data-testid": "badge", - }, - "Error", - ), + + Error + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-error"); @@ -103,14 +77,9 @@ describe("Badge", () => { it("applies warning variant classes", () => { render( - createElement( - Badge, - { - variant: "warning", - "data-testid": "badge", - }, - "Warning", - ), + + Warning + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-warning"); @@ -119,14 +88,9 @@ describe("Badge", () => { it("applies info variant classes", () => { render( - createElement( - Badge, - { - variant: "info", - "data-testid": "badge", - }, - "Info", - ), + + Info + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-info"); @@ -137,14 +101,9 @@ describe("Badge", () => { describe("Sizes", () => { it("applies small size classes", () => { render( - createElement( - Badge, - { - size: "sm", - "data-testid": "badge", - }, - "Small", - ), + + Small + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("px-2"); @@ -154,14 +113,9 @@ describe("Badge", () => { it("applies medium size classes (default)", () => { render( - createElement( - Badge, - { - size: "md", - "data-testid": "badge", - }, - "Medium", - ), + + Medium + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("px-2.5"); @@ -171,14 +125,9 @@ describe("Badge", () => { it("applies large size classes", () => { render( - createElement( - Badge, - { - size: "lg", - "data-testid": "badge", - }, - "Large", - ), + + Large + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("px-3"); @@ -187,15 +136,7 @@ describe("Badge", () => { }); it("uses medium size by default", () => { - render( - createElement( - Badge, - { - "data-testid": "badge", - }, - "Default", - ), - ); + render(Default); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("text-sm"); }); @@ -204,14 +145,9 @@ describe("Badge", () => { describe("HTML Attributes", () => { it("passes through id attribute", () => { render( - createElement( - Badge, - { - id: "badge-id", - "data-testid": "badge", - }, - "Badge", - ), + + Badge + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("id", "badge-id"); @@ -219,14 +155,9 @@ describe("Badge", () => { it("passes through title attribute", () => { render( - createElement( - Badge, - { - title: "Badge tooltip", - "data-testid": "badge", - }, - "Badge", - ), + + Badge + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("title", "Badge tooltip"); @@ -235,16 +166,14 @@ describe("Badge", () => { it("passes through onClick handler", () => { let clicked = false; render( - createElement( - Badge, - { - onClick: () => { - clicked = true; - }, - "data-testid": "badge", - }, - "Clickable", - ), + { + clicked = true; + }} + data-testid="badge" + > + Clickable + , ); const badge = screen.getByTestId("badge"); badge.click(); @@ -253,14 +182,9 @@ describe("Badge", () => { it("passes through role attribute", () => { render( - createElement( - Badge, - { - role: "status", - "data-testid": "badge", - }, - "Status", - ), + + Status + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("role", "status"); @@ -270,14 +194,9 @@ describe("Badge", () => { describe("ARIA Attributes", () => { it("passes through aria-label", () => { render( - createElement( - Badge, - { - "aria-label": "Status badge", - "data-testid": "badge", - }, - "Active", - ), + + Active + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("aria-label", "Status badge"); @@ -285,14 +204,9 @@ describe("Badge", () => { it("passes through aria-describedby", () => { render( - createElement( - Badge, - { - "aria-describedby": "description-id", - "data-testid": "badge", - }, - "Badge", - ), + + Badge + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("aria-describedby", "description-id"); @@ -300,14 +214,9 @@ describe("Badge", () => { it("passes through aria-live for dynamic status", () => { render( - createElement( - Badge, - { - "aria-live": "polite", - "data-testid": "badge", - }, - "Updating", - ), + + Updating + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("aria-live", "polite"); @@ -317,14 +226,9 @@ describe("Badge", () => { describe("Custom className", () => { it("merges custom className with variant classes", () => { render( - createElement( - Badge, - { - className: "custom-badge", - "data-testid": "badge", - }, - "Custom", - ), + + Custom + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("custom-badge"); @@ -337,15 +241,13 @@ describe("Badge", () => { it("forwards ref to badge element", () => { let ref: HTMLDivElement | null = null; render( - createElement( - Badge, - { - ref: (el: HTMLDivElement | null) => { - ref = el; - }, - }, - "Badge", - ), + { + ref = el; + }} + > + Badge + , ); expect(ref).toBeInstanceOf(HTMLDivElement); expect(ref?.tagName).toBe("DIV"); @@ -354,15 +256,7 @@ describe("Badge", () => { describe("Base Classes", () => { it("always includes base classes", () => { - render( - createElement( - Badge, - { - "data-testid": "badge", - }, - "Badge", - ), - ); + render(Badge); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("inline-flex"); expect(badge.className).toContain("items-center"); @@ -372,15 +266,7 @@ describe("Badge", () => { }); it("includes transition classes", () => { - render( - createElement( - Badge, - { - "data-testid": "badge", - }, - "Badge", - ), - ); + render(Badge); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("transition-base"); }); @@ -389,15 +275,9 @@ describe("Badge", () => { describe("Compound Scenarios", () => { it("works correctly with success variant and small size", () => { render( - createElement( - Badge, - { - variant: "success", - size: "sm", - "data-testid": "badge", - }, - "Success", - ), + + Success + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-success"); @@ -406,15 +286,9 @@ describe("Badge", () => { it("works correctly with error variant and large size", () => { render( - createElement( - Badge, - { - variant: "error", - size: "lg", - "data-testid": "badge", - }, - "Error", - ), + + Error + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-error"); @@ -423,15 +297,13 @@ describe("Badge", () => { it("works correctly with outline variant and custom className", () => { render( - createElement( - Badge, - { - variant: "outline", - className: "hover:bg-accent", - "data-testid": "badge", - }, - "Outlined", - ), + + Outlined + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-transparent"); @@ -441,17 +313,15 @@ describe("Badge", () => { it("works correctly with warning variant and onClick", () => { let clicked = false; render( - createElement( - Badge, - { - variant: "warning", - onClick: () => { - clicked = true; - }, - "data-testid": "badge", - }, - "Warning", - ), + { + clicked = true; + }} + data-testid="badge" + > + Warning + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-warning"); @@ -462,23 +332,20 @@ describe("Badge", () => { describe("Content Types", () => { it("renders with text content", () => { - render(createElement(Badge, null, "Text")); + render(Text); expect(screen.getByText("Text")).toBeInTheDocument(); }); it("renders with numeric content", () => { - render(createElement(Badge, null, "42")); + render(42); expect(screen.getByText("42")).toBeInTheDocument(); }); it("renders with multiple children", () => { render( - createElement( - Badge, - null, - "Count: ", - createElement("strong", null, "5"), - ), + + Count: 5 + , ); expect(screen.getByText("Count:")).toBeInTheDocument(); expect(screen.getByText("5")).toBeInTheDocument(); @@ -488,16 +355,14 @@ describe("Badge", () => { describe("Semantic Usage", () => { it("can be used as status indicator with role", () => { render( - createElement( - Badge, - { - variant: "success", - role: "status", - "aria-label": "Online status", - "data-testid": "badge", - }, - "Online", - ), + + Online + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("role", "status"); @@ -507,16 +372,14 @@ describe("Badge", () => { it("can be used as notification count", () => { render( - createElement( - Badge, - { - variant: "error", - size: "sm", - "aria-label": "3 unread messages", - "data-testid": "badge", - }, - "3", - ), + + 3 + , ); const badge = screen.getByTestId("badge"); expect(badge).toHaveAttribute("aria-label", "3 unread messages"); @@ -525,14 +388,9 @@ describe("Badge", () => { it("can be used as tag/label", () => { render( - createElement( - Badge, - { - variant: "outline", - "data-testid": "badge", - }, - "TypeScript", - ), + + TypeScript + , ); const badge = screen.getByTestId("badge"); expect(badge.className).toContain("bg-transparent"); diff --git a/packages/ui/src/Badge/Badge.ts b/packages/ui/src/Badge/Badge.tsx similarity index 55% rename from packages/ui/src/Badge/Badge.ts rename to packages/ui/src/Badge/Badge.tsx index c11a58d..0775d47 100644 --- a/packages/ui/src/Badge/Badge.ts +++ b/packages/ui/src/Badge/Badge.tsx @@ -1,5 +1,5 @@ import { cn } from "@tpmjs/utils/cn"; -import { createElement, forwardRef } from "react"; +import { forwardRef } from "react"; import type { BadgeProps } from "./types"; import { badgeVariants } from "./variants"; @@ -7,34 +7,31 @@ import { badgeVariants } from "./variants"; * Badge component * * A versatile badge component for status indicators, tags, and labels. - * Built with .ts-only React using createElement. * * @example - * ```typescript + * ```tsx * import { Badge } from '@tpmjs/ui/Badge/Badge'; - * import { createElement } from 'react'; * * function MyComponent() { - * return createElement(Badge, { - * variant: 'success', - * children: 'Active', - * }); + * return Active; * } * ``` */ export const Badge = forwardRef( ({ className, variant = "default", size = "md", ...props }, ref) => { - return createElement("div", { - className: cn( - badgeVariants({ - variant, - size, - }), - className, - ), - ref, - ...props, - }); + return ( +
+ ); }, ); diff --git a/packages/ui/src/Icon/Icon.test.ts b/packages/ui/src/Icon/Icon.test.tsx similarity index 69% rename from packages/ui/src/Icon/Icon.test.ts rename to packages/ui/src/Icon/Icon.test.tsx index bd8f7c2..bf43a6c 100644 --- a/packages/ui/src/Icon/Icon.test.ts +++ b/packages/ui/src/Icon/Icon.test.tsx @@ -1,38 +1,37 @@ import { render, screen } from "@testing-library/react"; -import { createElement } from "react"; import { describe, expect, it } from "vitest"; import { Icon } from "./Icon"; describe("Icon", () => { describe("Rendering", () => { it("renders an SVG element", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon).toBeInTheDocument(); expect(icon.tagName).toBe("svg"); }); it("renders with correct viewBox", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("viewBox", "0 0 24 24"); }); it("renders with currentColor fill", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("fill", "currentColor"); }); it("includes path element", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toBeInTheDocument(); }); it("is aria-hidden by default", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("aria-hidden", "true"); }); @@ -40,46 +39,28 @@ describe("Icon", () => { describe("Size Variants", () => { it("applies small size", () => { - render( - createElement(Icon, { - icon: "check", - size: "sm", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-4"); expect(icon.className).toContain("h-4"); }); it("applies medium size", () => { - render( - createElement(Icon, { - icon: "check", - size: "md", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-5"); expect(icon.className).toContain("h-5"); }); it("applies large size", () => { - render( - createElement(Icon, { - icon: "check", - size: "lg", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-6"); expect(icon.className).toContain("h-6"); }); it("uses md size by default", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-5"); expect(icon.className).toContain("h-5"); @@ -88,7 +69,7 @@ describe("Icon", () => { describe("Icon Variants", () => { it("renders copy icon", () => { - render(createElement(Icon, { icon: "copy", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toHaveAttribute( @@ -98,9 +79,7 @@ describe("Icon", () => { }); it("renders externalLink icon", () => { - render( - createElement(Icon, { icon: "externalLink", "data-testid": "icon" }), - ); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toHaveAttribute( @@ -110,14 +89,14 @@ describe("Icon", () => { }); it("renders github icon", () => { - render(createElement(Icon, { icon: "github", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path?.getAttribute("d")).toContain("M12 2C6.477 2 2 6.477 2 12"); }); it("renders check icon", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toHaveAttribute( @@ -127,7 +106,7 @@ describe("Icon", () => { }); it("renders x icon", () => { - render(createElement(Icon, { icon: "x", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toHaveAttribute( @@ -137,9 +116,7 @@ describe("Icon", () => { }); it("renders chevronDown icon", () => { - render( - createElement(Icon, { icon: "chevronDown", "data-testid": "icon" }), - ); + render(); const icon = screen.getByTestId("icon"); const path = icon.querySelector("path"); expect(path).toHaveAttribute( @@ -151,25 +128,13 @@ describe("Icon", () => { describe("SVG Attributes", () => { it("passes through className", () => { - render( - createElement(Icon, { - icon: "check", - className: "custom-class", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("custom-class"); }); it("merges custom className with variant classes", () => { - render( - createElement(Icon, { - icon: "check", - className: "text-red-500", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("text-red-500"); expect(icon.className).toContain("inline-block"); @@ -177,38 +142,26 @@ describe("Icon", () => { }); it("allows custom aria-hidden", () => { - render( - createElement(Icon, { - icon: "check", - "aria-hidden": false, - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("aria-hidden", "false"); }); it("passes through aria-label", () => { render( - createElement(Icon, { - icon: "check", - "aria-label": "Success", - "aria-hidden": false, - "data-testid": "icon", - }), + , ); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("aria-label", "Success"); }); it("passes through id attribute", () => { - render( - createElement(Icon, { - icon: "check", - id: "icon-id", - "data-testid": "icon", - }), - ); + render(); const icon = screen.getByTestId("icon"); expect(icon).toHaveAttribute("id", "icon-id"); }); @@ -218,12 +171,12 @@ describe("Icon", () => { it("forwards ref to SVG element", () => { let ref: SVGSVGElement | null = null; render( - createElement(Icon, { - icon: "check", - ref: (el: SVGSVGElement | null) => { + { ref = el; - }, - }), + }} + />, ); expect(ref).toBeInstanceOf(SVGSVGElement); expect(ref?.tagName).toBe("svg"); @@ -232,7 +185,7 @@ describe("Icon", () => { describe("Base Classes", () => { it("always includes base classes", () => { - render(createElement(Icon, { icon: "check", "data-testid": "icon" })); + render(); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("inline-block"); expect(icon.className).toContain("fill-current"); @@ -242,12 +195,12 @@ describe("Icon", () => { describe("Compound Scenarios", () => { it("works correctly with custom size and className", () => { render( - createElement(Icon, { - icon: "github", - size: "lg", - className: "text-zinc-400 hover:text-zinc-100", - "data-testid": "icon", - }), + , ); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-6"); @@ -258,13 +211,13 @@ describe("Icon", () => { it("works correctly with aria attributes and custom size", () => { render( - createElement(Icon, { - icon: "externalLink", - size: "sm", - "aria-label": "Opens in new tab", - "aria-hidden": false, - "data-testid": "icon", - }), + , ); const icon = screen.getByTestId("icon"); expect(icon.className).toContain("w-4"); diff --git a/packages/ui/src/Icon/Icon.ts b/packages/ui/src/Icon/Icon.tsx similarity index 55% rename from packages/ui/src/Icon/Icon.ts rename to packages/ui/src/Icon/Icon.tsx index 22b60e7..15585b3 100644 --- a/packages/ui/src/Icon/Icon.ts +++ b/packages/ui/src/Icon/Icon.tsx @@ -1,5 +1,5 @@ import { cn } from "@tpmjs/utils/cn"; -import { createElement, forwardRef } from "react"; +import { forwardRef } from "react"; import { type IconName, icons } from "./icons"; import type { IconProps } from "./types"; import { iconVariants } from "./variants"; @@ -11,19 +11,13 @@ export type { IconName }; * * Renders SVG icons with consistent sizing and styling. * Icons inherit text color via currentColor. - * Built with .ts-only React using createElement. * * @example - * ```typescript + * ```tsx * import { Icon } from '@tpmjs/ui/Icon/Icon'; - * import { createElement } from 'react'; * * function MyComponent() { - * return createElement(Icon, { - * icon: 'github', - * size: 'md', - * className: 'text-zinc-400', - * }); + * return ; * } * ``` */ @@ -31,24 +25,22 @@ export const Icon = forwardRef( ({ className, icon, size = "md", ...props }, ref) => { const iconData = icons[icon]; - return createElement( - "svg", - { - className: cn( + return ( + + + ); }, );