Implement theme system: - Add next-themes for theme management with light mode as default - Swap CSS variable definitions in globals.css (light in :root, dark in .dark class) - Create ThemeProvider component wrapping next-themes - Create ThemeToggle component with sun/moon icons - Update root layout with ThemeProvider Build full homepage: - Add Header component with navigation and theme toggle - Create hero section with gradient background and search - Add Featured Tools section with 6 tool cards (icons, badges, usage stats) - Add Browse by Category section with 12 colored category tiles - Add Platform Statistics section with 4 metric cards - Add footer with copyright and links - Create homePageData.ts with comprehensive mock data Add Storybook stories: - Icon.stories.ts (AllIcons, AllSizes, WithColors) - Badge.stories.ts (Default, AllVariants, AllSizes, WithLongText) - Input.stories.ts (Default, WithLabel, AllStates, AllSizes, PasswordInput) - ProgressBar.stories.ts (Default, AllVariants, AllSizes, WithLabel, edge cases) - CodeBlock.stories.ts (Default, multiple languages, LongCode) - Tabs.stories.ts (Default, AllSizes, WithCounts, ManyTabs) Fix production build issues: - Export IconName type from Icon.ts - Add sun and moon icons to icons.ts - Fix Icon prop naming (icon not name) - Fix Icon size constraints (remove xl, use lg) - Update ThemeProvider types using ComponentProps - Add explicit return types where needed - Remove unused imports - Replace forEach with for...of in variants system - Fix template literals in storybook stories 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
74 lines
1.6 KiB
TypeScript
74 lines
1.6 KiB
TypeScript
import { cn } from "@tpmjs/utils/cn";
|
|
import { createElement, forwardRef } from "react";
|
|
import type { ButtonProps } from "./types";
|
|
import { buttonVariants } from "./variants";
|
|
|
|
/**
|
|
* Button component
|
|
*
|
|
* A versatile button component with multiple variants, sizes, and states.
|
|
* Built with .ts-only React using createElement.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* import { Button } from '@tpmjs/ui/Button/Button';
|
|
* import { createElement } from 'react';
|
|
*
|
|
* function MyComponent() {
|
|
* return createElement(Button, {
|
|
* variant: 'outline',
|
|
* size: 'lg',
|
|
* onClick: () => console.log('clicked'),
|
|
* children: 'Click me',
|
|
* });
|
|
* }
|
|
* ```
|
|
*/
|
|
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
(
|
|
{
|
|
className,
|
|
variant = "default",
|
|
size = "md",
|
|
loading = false,
|
|
disabled = false,
|
|
children,
|
|
...props
|
|
},
|
|
ref,
|
|
) => {
|
|
return createElement(
|
|
"button",
|
|
{
|
|
type: "button",
|
|
className: cn(
|
|
buttonVariants({
|
|
variant,
|
|
size,
|
|
loading: loading ? "true" : "false",
|
|
}),
|
|
className,
|
|
),
|
|
ref,
|
|
disabled: disabled || loading,
|
|
"aria-disabled": disabled || loading ? "true" : undefined,
|
|
"aria-busy": loading ? "true" : undefined,
|
|
...props,
|
|
},
|
|
loading
|
|
? createElement(
|
|
"span",
|
|
{ className: "flex items-center gap-2" },
|
|
createElement("span", {
|
|
className:
|
|
"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent",
|
|
"aria-hidden": "true",
|
|
}),
|
|
createElement("span", null, children),
|
|
)
|
|
: children,
|
|
);
|
|
},
|
|
);
|
|
|
|
Button.displayName = "Button";
|