diff --git a/docs/www/.prettierrc b/docs/www/.prettierrc index 2f09b09..5e55e29 100644 --- a/docs/www/.prettierrc +++ b/docs/www/.prettierrc @@ -2,11 +2,11 @@ "semi": false, "singleQuote": true, "printWidth": 120, + "jsxBracketSameLine": false, + "trailingComma": "es5", + "arrowParens": "avoid", "tabWidth": 2, - "trailingComma": "all", "endOfLine": "auto", "bracketSpacing": true, - "jsxBracketSameLine": false, - "arrowParens": "always", "singleAttributePerLine": true } diff --git a/docs/www/__registry__/index.tsx b/docs/www/__registry__/index.tsx index a912804..5e2978c 100644 --- a/docs/www/__registry__/index.tsx +++ b/docs/www/__registry__/index.tsx @@ -8,7 +8,7 @@ export const Index: Record = { "DuckButton": { name: "DuckButton", type: "components:ui", - registryDependencies: undefined, + registryDependencies: ["dialog"], component: React.lazy(() => import("@/registry/default/ui/DuckButton")), source: "", files: ["registry/default/ui/DuckButton.tsx"], @@ -16,6 +16,39 @@ export const Index: Record = { subcategory: "undefined", chunks: [] }, + "DuckBadge": { + name: "DuckBadge", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/DuckBadge")), + source: "", + files: ["registry/default/ui/DuckBadge.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "DuckCommand": { + name: "DuckCommand", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/DuckCommand")), + source: "", + files: ["registry/default/ui/DuckCommand.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, + "DuckTooltip": { + name: "DuckTooltip", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy(() => import("@/registry/default/ui/DuckTooltip")), + source: "", + files: ["registry/default/ui/DuckTooltip.tsx"], + category: "undefined", + subcategory: "undefined", + chunks: [] + }, "DuckButtonMainDemo": { name: "DuckButtonMainDemo", type: "components:example", @@ -49,13 +82,13 @@ export const Index: Record = { subcategory: "undefined", chunks: [] }, - "test": { - name: "test", + "DuckBadgeMainDemo": { + name: "DuckBadgeMainDemo", type: "components:example", - registryDependencies: ["DuckButton"], - component: React.lazy(() => import("@/registry/default/example/test")), + registryDependencies: ["DuckBadge"], + component: React.lazy(() => import("@/registry/default/example/DuckBadgeMainDemo")), source: "", - files: ["registry/default/example/test.tsx"], + files: ["registry/default/example/DuckBadgeMainDemo.tsx"], category: "undefined", subcategory: "undefined", chunks: [] diff --git a/docs/www/components/component-preview.tsx b/docs/www/components/component-preview.tsx index fb9cef6..0f09fc2 100644 --- a/docs/www/components/component-preview.tsx +++ b/docs/www/components/component-preview.tsx @@ -93,17 +93,7 @@ export function ComponentPreview({ className="relative rounded-md border" >
- +
{}}> + { }}> - - - - - setVarieties({ default: { variety: { ...varieties.default.variety, title: currentTarget.value } } }) - } - /> - - setVarieties({ default: { variety: { ...varieties.default.variety, label: currentTarget.value } } }) - } - /> -
- - { + + variant : + + + + {variants.map( + variant => + type === 'DuckBadgeMainDemo' && + !['link', 'ghost'].includes(variant) && ( + + {variant} + + ) + )} + + + ) : null} + + {typesAllowedForVariant.includes(type) && type ? ( + + ) : null} + + {typesAllowedForTitle.includes(type) && type ? ( + + setVarieties({ default: { variety: { ...varieties.default.variety, title: currentTarget.value } } }) + } + /> + ) : null} + + {typesAllowedForLabel.includes(type) && type ? ( + + setVarieties({ default: { variety: { ...varieties.default.variety, label: currentTarget.value } } }) + } /> -
+ ) : null} + + {typesAllowedForCollapse.includes(type) && type ? ( +
+ + { + setVarieties({ + default: { variety: { ...varieties.default.variety, open: !varieties.default.variety?.open } }, + }) + }} + /> +
+ ) : null} + + {typesAllowedForLoading.includes(type) && type ? ( +
+ + { + setVarieties({ + default: { variety: { ...varieties.default.variety, loading: !varieties.default.variety?.loading } }, + }) + }} + /> +
+ ) : null}
) diff --git a/docs/www/config/docs.ts b/docs/www/config/docs.ts index ad89d43..0f4779a 100644 --- a/docs/www/config/docs.ts +++ b/docs/www/config/docs.ts @@ -36,13 +36,12 @@ export const docsConfig: DocsConfig = { { title: 'Button', href: '/docs/components/Button', - items: [ - { - title: 'Overview', - href: '/docs/components/Button', - items: [], - }, - ], + items: [], + }, + { + title: 'Badge', + href: '/docs/components/Badge', + items: [], }, ], }, diff --git a/docs/www/content/docs/components/Badge.mdx b/docs/www/content/docs/components/Badge.mdx new file mode 100644 index 0000000..614e33f --- /dev/null +++ b/docs/www/content/docs/components/Badge.mdx @@ -0,0 +1,108 @@ +--- +title: DuckBadge +description: The DuckBadge component is a customizable badge that supports different variants and sizes, making it versatile for various use cases. +component: true +--- + + + + + +## Features + +- **Customizable Variants**: Easily switch between different visual styles such as `default`, `info`, `warning`, `success`, and `outline`. +- **Resizable**: Adjust the badge size with options like `sm`, `md`, and `lg`. +- **Interactive**: Includes built-in hover effects and focus states for better user interaction. +- **Transition Effects**: Smooth transition effects for hover states. + +## Installation + + + + + CLI + Manual + + + +```bash +npx duck-ui@latest add badge +``` + + + + + + + +Copy and paste the following code into your project. + + + +Update the import paths to match your project setup. + + + + + + + +## Usage + +```tsx +import { DuckBadge } from "@/components/ui" +``` + +```tsx +Duck Badge +``` + +### Link + +You can use the `badgeVariants` helper to create a link that looks like a badge. + +```tsx +import { badgeVariants } from "@/components/ui" +``` + +```tsx +Duck Badge +``` + +### Parameters + +| Parameter | Type | Description | +| ----------- | -------------------------------------- | ------------------------------------------------------------------------------------------------- | +| `variant` | [`Variant`](#variant) (optional) | Defines the visual style of the badge (e.g., `default`, `info`, `warning`, `success`, `outline`). | +| `size` | [`Size`](#size) (optional) | Defines the size of the badge (e.g., `sm`, `md`, `lg`). | +| `className` | `string` (optional) | Additional classes to apply to the badge. | +| `label` | [`LabelType`](#labeltype) (optional) | Label text or tooltip content to display with the Badge. | +| `...props` | `React.HTMLAttributes` | Additional HTML attributes to apply to the badge container. | + +### LabelType + +| Property | Type | Description | +| --------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `children` | `React.ReactNode` (optional) | The content to display inside the tooltip. | +| `className` | `string` (optional) | Additional classes to apply to the tooltip content. | + + + +### Variants + +| Variant | Description | +| ---------- | ------------------------------------------------------------------------------------------------- | +| `default` | The primary style of the badge, with a background color defined by the `duck-primary` class. | +| `info` | A style intended for informational badges, using the `duck-info` color scheme. | +| `warning` | A style designed for warning messages, using the `duck-warning` color scheme. | +| `success` | A style for success messages, using the `duck-success` color scheme. | +| `outline` | A minimal style with just an outline and no background color, suitable for subtle indicators. | + +### Sizes + +| Size | Description | +| ------ | ------------------------------------------------------------------------------- | +| `default` | The default button size. | +| `sm` | A small badge with reduced padding and font size. | +| `md` | The default medium size badge, balanced for most use cases. | +| `lg` | A large badge with increased padding and font size, for emphasis. | diff --git a/docs/www/content/docs/components/Button.mdx b/docs/www/content/docs/components/Button.mdx index de5b31a..45f6340 100644 --- a/docs/www/content/docs/components/Button.mdx +++ b/docs/www/content/docs/components/Button.mdx @@ -18,6 +18,7 @@ component: true - **Tooltip Integration**: Display tooltips with custom delay and content. - **Icon Support**: Include icons alongside text or as standalone elements. - **Collapsible**: Optionally collapse the button to save space. +- **Loading State**: Display a loading spinner or icon while actions are in progress, hiding other content. ## Installation @@ -61,7 +62,7 @@ npm install @radix-ui/react-slot ```tsx import React from 'react' -import { DuckButton } from '@/components/Ui' +import { DuckButton } from '@/components/ui' import { Inbox } from 'lucide-react' ``` @@ -78,7 +79,7 @@ import { Inbox } from 'lucide-react' You can use the `buttonVariants` helper to create a any element like a link that looks like a button. ```tsx -import { buttonVariants } from '@/components/Ui' +import { buttonVariants } from '@/components/ui' ``` ```tsx @@ -113,56 +114,57 @@ Alternatively, you can set the `asChild` parameter and nest the link component. The `DuckButtonProps` interface defines the properties that can be passed to the `DuckButton` component. -### Parameters - -| Parameter | Type | Description | -| --------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------- | -| `asChild` | `boolean` (optional) | Determines if the button should be rendered as a child element, useful for custom wrappers. | -| `isCollapsed` | `boolean` (optional) | Indicates if the button is in a collapsed state, potentially affecting its visibility or content. | -| `icon` | `LucideIcon` (optional) | The icon to display within the button. | -| `label` | `string` (optional) | The text label to display on the button. | -| `command` | [`CommandType`](#commandtype) (optional) | Configuration for keyboard shortcuts, including key, label, and action. | -| `delayDuration` | `number` (optional) | The delay duration (in milliseconds) before executing the button's action or command. | -| `variant` | [`Variant`](#variant) (optional) | Defines the visual style of the button (e.g., `default`, `destructive`, `outline`, etc.). | -| `size` | [`Size`](#size) (optional) | Defines the size of the button (e.g., `default`, `sm`, `lg`, `icon`). | - -## CommandType - -The `CommandType` interface defines the properties for configuring keyboard shortcuts and actions associated with the button. - -### Fields - -| Field | Type | Description | -| -------- | --------------------------------- | ------------------------------------------------------ | -| `label` | `string` | The label to display for the command. | -| `key` | `string` | The keyboard shortcut key associated with the command. | -| `state` | `unknown` (optional) | Optional state data to pass with the command. | -| `action` | `(arg?: T) => void` (optional) | The function to execute when the command is triggered. | +Here's the updated parameters table with the **`loading`** parameter added: -## Variants - -The `variant` property allows you to define the visual style of the button. It is derived from the `buttonVariants` utility. - -### Variant Options - -| Variant | Description | -| ------------- | -------------------------------------------------------------------------- | -| `default` | The default button style. | -| `destructive` | A style used to indicate a destructive action, such as delete or remove. | -| `outline` | A button with an outlined border and transparent background. | -| `secondary` | A secondary style, typically used for less prominent actions. | -| `ghost` | A button with a transparent background, typically used for subtle actions. | -| `link` | A button styled as a hyperlink. | - -## Sizes - -The `size` property allows you to define the size of the button. It is also derived from the `buttonVariants` utility. +### Parameters -### Size Options +| Parameter | Type | Description | +| --------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `asChild` | `boolean` (optional) | Renders the button as a child element, useful for custom wrappers. | +| `isCollapsed` | `boolean` (optional) | Indicates if the button is in a collapsed state, affecting its visibility or content. | +| `icon` | `LucideIcon` (optional) | Icon to display within the button. | +| `label` | [`LabelType`](#labeltype) (optional) | Label text or tooltip content to display with the button. | +| `command` | [`CommandType`](#commandtype) (optional) | Configuration for keyboard shortcuts, including key, label, and action. | +| `delayDuration` | `number` (optional) | Delay in milliseconds before showing the tooltip. | +| `loading` | `boolean` (optional) | Indicates whether to display a loading spinner instead of the button content. | +| `variant` | [`Variant`](#variant) (optional) | Defines the visual style of the button (e.g., `default`, `destructive`, `outline`, etc.). | +| `size` | [`Size`](#size) (optional) | Defines the size of the button (e.g., `default`, `sm`, `lg`, `icon`). | +| `className` | `string` (optional) | Additional classes to apply to the button. | +| `...props` | `React.ButtonHTMLAttributes` | Additional HTML attributes to apply to the button element. | + +### Variants + +| Variant | Description | +| --------------- | ------------------------------------------------------------------------------------------------- | +| `default` | The primary style of the button, with a background color defined by the primary theme. | +| `destructive` | A style intended for actions that might have irreversible effects, using the destructive color scheme. | +| `outline` | A minimal style with just an outline and no background color. | +| `secondary` | A secondary style using the secondary color scheme. | +| `ghost` | A subtle style with no background, only changing on hover. | +| `link` | A style that looks like a hyperlink, often used for inline actions. | + +### Sizes + +| Size | Description | +| --------------- | ------------------------------------------------------------------------------------------------- | +| `default` | The default button size, balanced for most use cases. | +| `sm` | A smaller button with reduced padding and font size. | +| `lg` | A larger button with increased padding and font size, for emphasis. | +| `icon` | A button designed to only contain an icon, with equal height and width. | + +### LabelType + +| Property | Type | Description | +| --------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `children` | `React.ReactNode` (optional) | The content to display inside the tooltip. | +| `className` | `string` (optional) | Additional classes to apply to the tooltip content. | + +### CommandType + +| Property | Type | Description | +| --------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `label` | `string` | The label of the command to display. | +| `key` | `string` | The key combination that triggers the command. | +| `state` | `unknown` (optional) | Optional state information to pass along when the command is triggered. | +| `action` | `(arg?: T) => void` | The action to execute when the command is triggered. | -| Size | Description | -| --------- | ------------------------------------------------------------ | -| `default` | The default button size. | -| `sm` | A small button size, suitable for compact spaces. | -| `lg` | A large button size, suitable for more prominent actions. | -| `icon` | A button size optimized for displaying icons without labels. | diff --git a/docs/www/hooks/use-varieties.ts b/docs/www/hooks/use-varieties.ts index da4c473..ebeb997 100644 --- a/docs/www/hooks/use-varieties.ts +++ b/docs/www/hooks/use-varieties.ts @@ -11,6 +11,7 @@ export type Varieties = { label?: string commandLabel?: string command?: string + loading?: boolean open?: boolean } } @@ -23,6 +24,7 @@ export const duckButtonVarieties = atom({ title: 'Settings', label: '5', commandLabel: 'Ctrl + C', + loading: false, command: 'c', open: true, }, diff --git a/docs/www/next.config.mts b/docs/www/next.config.mts index e092ddc..93478b2 100644 --- a/docs/www/next.config.mts +++ b/docs/www/next.config.mts @@ -20,43 +20,7 @@ const nextConfig = { ], }, redirects() { - return [ - { - source: '/components', - destination: '/docs/components/accordion', - permanent: true, - }, - { - source: '/docs/components', - destination: '/docs/components/accordion', - permanent: true, - }, - { - source: '/examples', - destination: '/examples/mail', - permanent: false, - }, - { - source: '/docs/primitives/:path*', - destination: '/docs/components/:path*', - permanent: true, - }, - { - source: '/figma', - destination: '/docs/figma', - permanent: true, - }, - { - source: '/docs/forms', - destination: '/docs/components/form', - permanent: false, - }, - { - source: '/docs/forms/react-hook-form', - destination: '/docs/components/form', - permanent: false, - }, - ] + return [] }, } diff --git a/docs/www/package.json b/docs/www/package.json index e5583d5..8a0dcc2 100644 --- a/docs/www/package.json +++ b/docs/www/package.json @@ -4,7 +4,7 @@ "private": true, "type": "module", "scripts": { - "dev": "next dev -p 3003", + "dev": "contentlayer2 build && pnpm build:registry && next dev -p 3003", "build": "contentlayer2 build && pnpm build:registry && next build", "build:registry": "tsx --tsconfig ./tsconfig.json ./scripts/build-registry.mts && prettier --log-level silent --write \"registry/**/*.{ts,tsx,mdx}\" --cache", "build:docs": "contentlayer2 build", diff --git a/docs/www/public/registry/index.json b/docs/www/public/registry/index.json index 85938bc..72e49eb 100644 --- a/docs/www/public/registry/index.json +++ b/docs/www/public/registry/index.json @@ -2,11 +2,43 @@ { "name": "DuckButton", "dependencies": [ - "@radix-ui/react-slot" + "@radix-ui/react-slot", + "@radix-ui/react-tooltip", + "@radix-ui/react-dialog", + "cmdk@1.0.0" + ], + "registryDependencies": [ + "dialog" ], "files": [ "ui/DuckButton.tsx" ], "type": "components:ui" + }, + { + "name": "DuckBadge", + "dependencies": [], + "files": [ + "ui/DuckBadge.tsx" + ], + "type": "components:ui" + }, + { + "name": "DuckCommand", + "dependencies": [], + "files": [ + "ui/DuckCommand.tsx" + ], + "type": "components:ui" + }, + { + "name": "DuckTooltip", + "dependencies": [ + "@radix-ui/react-tooltip" + ], + "files": [ + "ui/DuckTooltip.tsx" + ], + "type": "components:ui" } ] \ No newline at end of file diff --git a/docs/www/public/registry/styles/default/DuckBadge.json b/docs/www/public/registry/styles/default/DuckBadge.json new file mode 100644 index 0000000..df20b77 --- /dev/null +++ b/docs/www/public/registry/styles/default/DuckBadge.json @@ -0,0 +1,11 @@ +{ + "name": "DuckBadge", + "dependencies": [], + "files": [ + { + "name": "DuckBadge.tsx", + "content": "import * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\n\nimport { cn } from '@/lib/utils'\nimport { DuckTooltip, DuckTooltipContent, DuckTooltipTrigger } from './DuckTooltip'\nimport { LabelType } from './DuckButton'\n\nconst badgeVariants = cva(\n 'inline-flex items-center rounded-full border text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',\n {\n variants: {\n variant: {\n default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',\n secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',\n destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',\n outline: 'text-foreground',\n },\n size: {\n default: 'px-2.5 py-0.5 text-sm',\n sm: 'px-1.5 py-0.5 text-[.7rem]',\n lg: 'px-3.5 py-0.9 text-lg',\n icon: 'size-[28px] text-sm rounded-full justify-center items-center [&_*]:size-[.9rem]',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n)\n\nexport interface DuckBadgeProps extends React.HTMLAttributes, VariantProps {\n label?: LabelType\n}\n\nfunction DuckBadge({ className, variant, size, label, ...props }: DuckBadgeProps) {\n return (\n \n \n \n \n {label && size === 'icon' && (\n {label.children as unknown as React.ReactNode}\n )}\n \n )\n}\n\nexport { DuckBadge, badgeVariants }\n" + } + ], + "type": "components:ui" +} \ No newline at end of file diff --git a/docs/www/public/registry/styles/default/DuckButton.json b/docs/www/public/registry/styles/default/DuckButton.json index f61ce5f..b612098 100644 --- a/docs/www/public/registry/styles/default/DuckButton.json +++ b/docs/www/public/registry/styles/default/DuckButton.json @@ -1,12 +1,18 @@ { "name": "DuckButton", "dependencies": [ - "@radix-ui/react-slot" + "@radix-ui/react-slot", + "@radix-ui/react-tooltip", + "@radix-ui/react-dialog", + "cmdk@1.0.0" + ], + "registryDependencies": [ + "dialog" ], "files": [ { "name": "DuckButton.tsx", - "content": "import React from 'react'\nimport { cn } from '@/lib'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva } from 'class-variance-authority'\nimport { VariantProps } from 'class-variance-authority'\nimport { LucideIcon } from 'lucide-react'\nimport { Badge, CommandShortcut, Tooltip, TooltipContent, TooltipTrigger } from '@/registry/default/ui'\n\nexport interface DuckButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n isCollapsed?: boolean\n icon?: LucideIcon\n label?: string\n command?: CommandType\n delayDuration?: number\n}\n\nexport type CommandType = {\n label: string\n key: string\n state?: unknown\n action?: (arg?: T) => void\n}\n\nconst buttonVariants = cva(\n '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:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nconst DuckButton = React.forwardRef(\n (\n {\n asChild,\n isCollapsed = false,\n size = 'default',\n variant = 'default',\n title,\n className,\n label,\n children,\n icon: Icon,\n delayDuration = 0,\n command,\n ...props\n }: DuckButtonProps,\n ref: React.ForwardedRef | undefined,\n ) => {\n const Component = asChild ? Slot : 'button'\n\n // Handle keyboard shortcuts\n React.useEffect(() => {\n if (command?.key) {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === command.key && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n command.action && command.action()\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }\n }, [command])\n\n console.log(size)\n\n return (\n \n \n \n {!!Icon && }\n {!isCollapsed && (children || title) && {children || title}}\n {!isCollapsed && command && {command.label}}\n {!isCollapsed && label && {label}}\n \n \n {isCollapsed && (title || label) && (\n \n {title}\n {command && (\n \n {command.label}\n \n )}\n {label && {label}}\n \n )}\n \n )\n },\n)\nDuckButton.displayName = 'DuckButton'\n\nexport { DuckButton, buttonVariants }\n" + "content": "import React from 'react'\nimport { cn } from '@/lib'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva } from 'class-variance-authority'\nimport { VariantProps } from 'class-variance-authority'\nimport { Loader, LucideIcon } from 'lucide-react'\nimport { DuckTooltipContent, DuckTooltipTrigger } from './DuckTooltip'\nimport { DuckBadge } from './DuckBadge'\nimport { DuckCommandShortcut } from './DuckCommand'\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip'\n\nexport interface DuckButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n isCollapsed?: boolean\n icon?: LucideIcon\n label?: LabelType\n command?: CommandType\n delayDuration?: number\n loading?: boolean\n}\n\nconst DuckTooltip = TooltipPrimitive.Root\nexport interface LabelType extends Partial> { }\n\nexport type CommandType = {\n label: string\n key: string\n state?: unknown\n action?: (arg?: T) => void\n}\n\nconst buttonVariants = cva(\n '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:pointer-events-none disabled:opacity-50',\n {\n variants: {\n variant: {\n default: 'bg-primary text-primary-foreground hover:bg-primary/90',\n destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',\n outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-10 px-4 py-2',\n sm: 'h-9 rounded-md px-3',\n lg: 'h-11 rounded-md px-8',\n icon: 'h-10 w-10',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n }\n)\n\nconst DuckButton = React.forwardRef(\n (\n {\n asChild,\n isCollapsed = false,\n size = 'default',\n variant = 'default',\n title,\n className,\n label,\n children,\n icon: Icon,\n delayDuration = 0,\n loading = false,\n command,\n ...props\n }: DuckButtonProps,\n ref: React.ForwardedRef | undefined\n ) => {\n const DuckComponent = asChild ? Slot : 'button'\n\n // Handle keyboard shortcuts\n React.useEffect(() => {\n if (command?.key) {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === command.key && (e.metaKey || e.ctrlKey)) {\n e.preventDefault()\n command.action && command.action()\n }\n }\n\n document.addEventListener('keydown', handleKeyDown)\n return () => document.removeEventListener('keydown', handleKeyDown)\n }\n }, [command])\n\n return (\n \n \n \n {!loading ? (\n <>{!!Icon && !loading && }\n ) : (\n \n )}\n {!isCollapsed && (children || title) && {children || title}}\n {!isCollapsed && command && (\n {command.label}\n )}\n {!isCollapsed && label && (\n {label.children as unknown as React.ReactNode}\n )}\n \n \n {isCollapsed && (title || label) && (\n \n {title}\n {command && (\n \n {command.label}\n \n )}\n {label && (\n \n {label.children as unknown as React.ReactNode}\n \n )}\n \n )}\n \n )\n }\n)\nDuckButton.displayName = 'DuckButton'\n\nexport { DuckButton, buttonVariants }\n" } ], "type": "components:ui" diff --git a/docs/www/public/registry/styles/default/DuckCommand.json b/docs/www/public/registry/styles/default/DuckCommand.json new file mode 100644 index 0000000..7300398 --- /dev/null +++ b/docs/www/public/registry/styles/default/DuckCommand.json @@ -0,0 +1,11 @@ +{ + "name": "DuckCommand", + "dependencies": [], + "files": [ + { + "name": "DuckCommand.tsx", + "content": "'use client'\n\nimport * as React from 'react'\nimport { type DialogProps } from '@radix-ui/react-dialog'\nimport { Command as CommandPrimitive } from 'cmdk'\nimport { Search } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\nimport { Dialog, DialogContent } from '@/registry/default/ui/'\n\nconst DuckCommand = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n))\nDuckCommand.displayName = CommandPrimitive.displayName\n\ninterface DuckCommandDialogProps extends DialogProps {}\n\nconst DuckCommandDialog = ({ children, ...props }: DuckCommandDialogProps) => {\n return (\n \n \n \n {children}\n \n \n \n )\n}\n\nconst DuckCommandInput = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n
\n))\n\nDuckCommandInput.displayName = CommandPrimitive.Input.displayName\n\nconst DuckCommandList = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n))\n\nDuckCommandList.displayName = CommandPrimitive.List.displayName\n\nconst DuckCommandEmpty = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>((props, ref) => (\n \n))\n\nDuckCommandEmpty.displayName = CommandPrimitive.Empty.displayName\n\nconst DuckCommandGroup = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n))\n\nDuckCommandGroup.displayName = CommandPrimitive.Group.displayName\n\nconst DuckCommandSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n))\nDuckCommandSeparator.displayName = CommandPrimitive.Separator.displayName\n\nconst DuckCommandItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n))\n\nDuckCommandItem.displayName = CommandPrimitive.Item.displayName\n\nconst DuckCommandShortcut = ({ className, ...props }: React.HTMLAttributes) => {\n return (\n \n )\n}\nDuckCommandShortcut.displayName = 'CommandShortcut'\n\nexport {\n DuckCommand,\n DuckCommandDialog,\n DuckCommandInput,\n DuckCommandList,\n DuckCommandEmpty,\n DuckCommandGroup,\n DuckCommandItem,\n DuckCommandShortcut,\n DuckCommandSeparator,\n}\n" + } + ], + "type": "components:ui" +} \ No newline at end of file diff --git a/docs/www/public/registry/styles/default/DuckTooltip.json b/docs/www/public/registry/styles/default/DuckTooltip.json new file mode 100644 index 0000000..597adb6 --- /dev/null +++ b/docs/www/public/registry/styles/default/DuckTooltip.json @@ -0,0 +1,13 @@ +{ + "name": "DuckTooltip", + "dependencies": [ + "@radix-ui/react-tooltip" + ], + "files": [ + { + "name": "DuckTooltip.tsx", + "content": "'use client'\n\nimport * as React from 'react'\nimport * as TooltipPrimitive from '@radix-ui/react-tooltip'\n\nimport { cn } from '@/lib/utils'\n\nconst DuckTooltipProvider = TooltipPrimitive.Provider\n\nconst DuckTooltip = TooltipPrimitive.Root\n\nconst DuckTooltipTrigger = TooltipPrimitive.Trigger\n\nconst DuckTooltipContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, sideOffset = 4, ...props }, ref) => (\n \n))\nDuckTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport { DuckTooltip, DuckTooltipTrigger, DuckTooltipContent, DuckTooltipProvider }\n" + } + ], + "type": "components:ui" +} \ No newline at end of file diff --git a/docs/www/registry/default/example/DuckBadgeMainDemo.tsx b/docs/www/registry/default/example/DuckBadgeMainDemo.tsx new file mode 100644 index 0000000..7fe2a92 --- /dev/null +++ b/docs/www/registry/default/example/DuckBadgeMainDemo.tsx @@ -0,0 +1,23 @@ +import { duckButtonVarieties } from '@/hooks/use-varieties' +import { DuckBadge } from '@/registry/default/ui' +import { useAtom } from 'jotai' +import { CircleAlert } from 'lucide-react' + +export default function BadgeMainDemo() { + //NOTE: that's a state in the example + const [variety] = useAtom(duckButtonVarieties) + //NOTE: you will use your own variables not this state in the example + const { variant, size, title } = variety.default.variety! + + return ( + } + size={size} + label={{ + children: title as unknown as HTMLCollection, + }} + > + {size == 'icon' ? : title} + + ) +} diff --git a/docs/www/registry/default/example/DuckButtonAdvancedDemo.tsx b/docs/www/registry/default/example/DuckButtonAdvancedDemo.tsx index ff5c084..d4d1c79 100644 --- a/docs/www/registry/default/example/DuckButtonAdvancedDemo.tsx +++ b/docs/www/registry/default/example/DuckButtonAdvancedDemo.tsx @@ -8,8 +8,8 @@ import { duckButtonVarieties } from '@/hooks/use-varieties' export default function ButtonAdvancedDemo() { //NOTE: that's a state in the example const [variety] = useAtom(duckButtonVarieties) - //NOTE: you will use your own variables not this satate in the example - const { size, open, label, variant, title, commandLabel, command } = variety.default.variety! + //NOTE: you will use your own variables not this state in the example + const { size, open, label, variant, title, commandLabel, command, loading } = variety.default.variety! return ( <> @@ -17,7 +17,6 @@ export default function ButtonAdvancedDemo() { isCollapsed={open} icon={Inbox} title={title} - label={label} variant={variant} size={size} role="button" @@ -26,6 +25,10 @@ export default function ButtonAdvancedDemo() { aria-expanded={open} aria-pressed={open} tabIndex={0} + loading={loading} + label={{ + children: label as unknown as HTMLCollection, + }} command={{ label: commandLabel as string, key: command as string, diff --git a/docs/www/registry/default/example/DuckButtonMainDemo.tsx b/docs/www/registry/default/example/DuckButtonMainDemo.tsx index 0f70a21..adfdda1 100644 --- a/docs/www/registry/default/example/DuckButtonMainDemo.tsx +++ b/docs/www/registry/default/example/DuckButtonMainDemo.tsx @@ -7,8 +7,8 @@ import { useAtom } from 'jotai' export default function ButtonMainDemo() { //NOTE: that's a state in the example const [variety] = useAtom(duckButtonVarieties) - //NOTE: you will use your own variables not this satate in the example - const { size, open, label, variant, title } = variety.default.variety! + //NOTE: you will use your own variables not this state in the example + const { size, open, label, variant, title, loading } = variety.default.variety! return ( <> @@ -16,9 +16,12 @@ export default function ButtonMainDemo() { isCollapsed={open} icon={Inbox} title={title} - label={label} variant={variant} size={size} + loading={loading} + label={{ + children: label as unknown as HTMLCollection, + }} /> ) diff --git a/docs/www/registry/default/example/DuckButtonSimpleDemo.tsx b/docs/www/registry/default/example/DuckButtonSimpleDemo.tsx index d9b155e..ab298c8 100644 --- a/docs/www/registry/default/example/DuckButtonSimpleDemo.tsx +++ b/docs/www/registry/default/example/DuckButtonSimpleDemo.tsx @@ -7,8 +7,8 @@ import { duckButtonVarieties } from '@/hooks/use-varieties' export default function ButtonSimpleDemo() { //NOTE: that's a state in the example const [variety] = useAtom(duckButtonVarieties) - //NOTE: you will use your own variables not this satate in the example - const { size, open, label, variant, title } = variety.default.variety! + //NOTE: you will use your own variables not this state in the example + const { size, open, label, variant, title, loading } = variety.default.variety! return ( <> @@ -16,9 +16,12 @@ export default function ButtonSimpleDemo() { isCollapsed={open} icon={Inbox} title={title} - label={label} variant={variant} size={size} + loading={loading} + label={{ + children: label as unknown as HTMLCollection, + }} /> ) diff --git a/docs/www/registry/default/example/cards/activity-goal.tsx b/docs/www/registry/default/example/cards/activity-goal.tsx index 1f6bc0b..43a5a8e 100644 --- a/docs/www/registry/default/example/cards/activity-goal.tsx +++ b/docs/www/registry/default/example/cards/activity-goal.tsx @@ -56,7 +56,7 @@ export function CardsActivityGoal() { const { theme: mode } = useTheme() const [config] = useConfig() - const theme = themes.find((theme) => theme.name === config.theme) + const theme = themes.find(theme => theme.name === config.theme) const [goal, setGoal] = React.useState(350) function onClick(adjustment: number) { diff --git a/docs/www/registry/default/example/cards/chat.tsx b/docs/www/registry/default/example/cards/chat.tsx index eb79514..f6c23b4 100644 --- a/docs/www/registry/default/example/cards/chat.tsx +++ b/docs/www/registry/default/example/cards/chat.tsx @@ -113,7 +113,7 @@ export function CardsChat() { key={index} className={cn( 'flex w-max max-w-[75%] flex-col gap-2 rounded-lg px-3 py-2 text-sm', - message.role === 'user' ? 'ml-auto bg-primary text-primary-foreground' : 'bg-muted', + message.role === 'user' ? 'ml-auto bg-primary text-primary-foreground' : 'bg-muted' )} > {message.content} @@ -123,7 +123,7 @@ export function CardsChat() {
{ + onSubmit={event => { event.preventDefault() if (inputLength === 0) return setMessages([ @@ -143,7 +143,7 @@ export function CardsChat() { className="flex-1" autoComplete="off" value={input} - onChange={(event) => setInput(event.target.value)} + onChange={event => setInput(event.target.value)} />