diff --git a/docs/app/global.css b/docs/app/global.css index 2a4db71c34..9c4847314d 100644 --- a/docs/app/global.css +++ b/docs/app/global.css @@ -1,4 +1,5 @@ @import "tailwindcss"; +@import "tw-animate-css"; @import "fumadocs-ui/css/vitepress.css"; @import "fumadocs-ui/css/preset.css"; @import "fumadocs-twoslash/twoslash.css"; @@ -6,3 +7,122 @@ @source "."; @source "../components"; @source "../content"; + +/* Code below needed for ShadCN examples, check docs for more info. */ +@source "../node_modules/@blocknote/shadcn"; + +@custom-variant dark (&:is(.dark *)); + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + .bn-shadcn * { + @apply border-border outline-ring/50; + } +} diff --git a/docs/content/docs/getting-started/ariakit.mdx b/docs/content/docs/getting-started/ariakit.mdx index f0502e66a5..26918ea8e0 100644 --- a/docs/content/docs/getting-started/ariakit.mdx +++ b/docs/content/docs/getting-started/ariakit.mdx @@ -6,7 +6,7 @@ imageTitle: BlockNote with Ariakit # Getting Started With Ariakit -[Ariakit](https://ariakit.org/) is an open-source library of unstyled (headless), primitive components with a focus on Accessibility. To use BlockNote with Ariakit, you can import `BlockNoteView` from `@blocknote/ariakit` +[Ariakit](https://ariakit.org/) is an open-source library of unstyled (headless), primitive components with a focus on Accessibility. ```console tab="npm" npm install @blocknote/core @blocknote/react @blocknote/ariakit @@ -20,6 +20,6 @@ pnpm add @blocknote/core @blocknote/react @blocknote/ariakit bun add @blocknote/core @blocknote/react @blocknote/ariakit ``` -You can fully style the components with your own CSS, or import the provided default styles using the CSS file from `@blocknote/ariakit/style.css`. +To use BlockNote with Ariakit, you can import `BlockNoteView` from `@blocknote/ariakit`. You can fully style the components with your own CSS, or import the provided default styles using the `@blocknote/ariakit/style.css` stylesheet. diff --git a/docs/content/docs/getting-started/shadcn.mdx b/docs/content/docs/getting-started/shadcn.mdx index e75dbe62b9..1c9062d243 100644 --- a/docs/content/docs/getting-started/shadcn.mdx +++ b/docs/content/docs/getting-started/shadcn.mdx @@ -6,7 +6,7 @@ imageTitle: ShadCN rich text editor using BlockNote # Getting Started With ShadCN -[shadcn/ui](https://ui.shadcn.com/) is an open-source collection of React components based on [Radix](https://radix-ui.com/) and Tailwind. +[shadcn/ui](https://ui.shadcn.com/) is an open-source collection of React components based on [Radix](https://radix-ui.com/) and [TailwindCSS](https://tailwindcss.com/). ```console tab="npm" npm install @blocknote/core @blocknote/react @blocknote/shadcn @@ -20,10 +20,151 @@ pnpm add @blocknote/core @blocknote/react @blocknote/shadcn bun add @blocknote/core @blocknote/react @blocknote/shadcn ``` -To use BlockNote with shadcn, you can import `BlockNoteView` from `@blocknote/shadcn` and the stylesheet from `@blocknote/shadcn/style.css`. +To use BlockNote with ShadCN, you can import `BlockNoteView` from `@blocknote/shadcn` and the stylesheet from `@blocknote/shadcn/style.css`. This version of `BlockNoteView` is expected to be used in apps that are already using ShadCN/TailwindCSS, so it does not import any of those styles itself. + +To ensure Tailwind generates the necessary CSS for all utility classes used by BlockNote components, make sure to add the `@source` directive to your stylesheet that imports Tailwind: + +```css +@import tailwindcss; +... +/* Path to your installed `@blocknote/shadcn` package. */ +@source "../node_modules/@blocknote/shadcn"; +``` +## Usage with Tailwind Only + +If your app doesn't use ShadCN components and only uses TailwindCSS, you just need to extend your Tailwind theme with ShadCN utility classes to get ecerything working. You can do this by simply copying the styles below into your stylesheet that imports Tailwind. + +```css +@import tailwindcss; +... +@custom-variant dark (&:is(.dark *)); + +/* Light theme ShadCN CSS variables. */ +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +/* Dark theme ShadCN CSS variables. */ +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +/* Extending Tailwind theme with ShadCN utility classes. */ +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +/* Applies some additional necessary border styles within the editor. */ +@layer base { + .bn-shadcn * { + @apply border-border outline-ring/50; + } +} +``` + +The values used are for the Neutral ShadCN color theme (used in demo above), but you can customize them however you'd like. + +This website uses the exact same setup as the one described above, which you can see in [this file](https://github.com/TypeCellOS/BlockNote/blob/main/docs/app/global.css). + ## ShadCN Customization BlockNote comes with default shadcn components. However, it's likely that you have copied and possibly customized your own shadcn components in your project. diff --git a/docs/package.json b/docs/package.json index b67f11730b..ff16589ef7 100644 --- a/docs/package.json +++ b/docs/package.json @@ -134,9 +134,10 @@ "postcss": "^8.5.6", "react-email": "^4.0.16", "react-icons": "^5.5.0", - "tailwindcss": "^4.1.10", + "tailwindcss": "^4.1.12", + "tw-animate-css": "^1.3.7", "typescript": "^5.8.3", "y-partykit": "^0.0.33", "yjs": "^13.6.27" } -} \ No newline at end of file +} diff --git a/docs/postcss.config.mjs b/docs/postcss.config.mjs index a34a3d560d..c2ddf74822 100644 --- a/docs/postcss.config.mjs +++ b/docs/postcss.config.mjs @@ -1,5 +1,5 @@ export default { plugins: { - '@tailwindcss/postcss': {}, + "@tailwindcss/postcss": {}, }, }; diff --git a/packages/shadcn/components.json b/packages/shadcn/components.json index 8ef86c6aeb..eafc961dca 100644 --- a/packages/shadcn/components.json +++ b/packages/shadcn/components.json @@ -4,11 +4,10 @@ "rsc": false, "tsx": true, "tailwind": { - "config": "tailwind.config.js", "css": "src/style.css", "baseColor": "slate", "cssVariables": true, - "prefix": "bn-" + "prefix": "" }, "aliases": { "components": "@/components", diff --git a/packages/shadcn/index.html b/packages/shadcn/index.html index 4b35ce2f18..d3bc80f71c 100644 --- a/packages/shadcn/index.html +++ b/packages/shadcn/index.html @@ -1,4 +1,4 @@ - + diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json index 2a9d29b460..d4c6ef87f7 100644 --- a/packages/shadcn/package.json +++ b/packages/shadcn/package.json @@ -58,26 +58,23 @@ "dependencies": { "@blocknote/core": "0.36.1", "@blocknote/react": "0.36.1", - "@hookform/resolvers": "^3.6.0", + "@hookform/resolvers": "^3.10.0", "@radix-ui/react-avatar": "^1.1.3", - "@radix-ui/react-dropdown-menu": "^2.0.6", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-popover": "^1.0.7", - "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-toggle": "^1.0.3", - "@radix-ui/react-tooltip": "^1.0.7", + "@radix-ui/react-dropdown-menu": "^2.1.6", + "@radix-ui/react-label": "^2.1.2", + "@radix-ui/react-popover": "^1.1.6", + "@radix-ui/react-select": "^2.1.6", + "@radix-ui/react-slot": "^1.1.2", + "@radix-ui/react-tabs": "^1.1.3", + "@radix-ui/react-toggle": "^1.1.2", + "@radix-ui/react-tooltip": "^1.1.8", "autoprefixer": "^10.4.19", - "class-variance-authority": "^0.7.0", + "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.525.0", - "postcss": "^8.4.38", - "react-hook-form": "^7.52.0", + "react-hook-form": "^7.54.2", "tailwind-merge": "^2.3.0", - "tailwindcss": "^3.4.3", - "tailwindcss-animate": "^1.0.7", - "zod": "^3.23.8" + "zod": "^3.24.2" }, "devDependencies": { "@radix-ui/colors": "^3.0.0", @@ -97,7 +94,8 @@ }, "peerDependencies": { "react": "^18.0 || ^19.0 || >= 19.0.0-rc", - "react-dom": "^18.0 || ^19.0 || >= 19.0.0-rc" + "react-dom": "^18.0 || ^19.0 || >= 19.0.0-rc", + "tailwindcss": "^4.1.12" }, "eslintConfig": { "extends": [ diff --git a/packages/shadcn/postcss.config.js b/packages/shadcn/postcss.config.js deleted file mode 100644 index f780382780..0000000000 --- a/packages/shadcn/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -export default { - plugins: { - "tailwindcss/nesting": {}, - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/packages/shadcn/src/BlockNoteView.tsx b/packages/shadcn/src/BlockNoteView.tsx index a83e37a717..53379c258a 100644 --- a/packages/shadcn/src/BlockNoteView.tsx +++ b/packages/shadcn/src/BlockNoteView.tsx @@ -14,6 +14,8 @@ import { ShadCNDefaultComponents, } from "./ShadCNComponentsContext.js"; +import "./style.css"; + export const BlockNoteView = < BSchema extends BlockSchema, ISchema extends InlineContentSchema, diff --git a/packages/shadcn/src/badge/Badge.tsx b/packages/shadcn/src/badge/Badge.tsx index d8333fc2f1..74c1787953 100644 --- a/packages/shadcn/src/badge/Badge.tsx +++ b/packages/shadcn/src/badge/Badge.tsx @@ -30,7 +30,7 @@ export const Badge = forwardRef< variant={isSelected ? "secondary" : "outline"} className={cn( className, - "bn-flex bn-items-center bn-gap-1 bn-rounded-full bn-h-7 bn-px-2.5", + "flex h-7 items-center gap-1 rounded-full px-2.5", )} onClick={onClick} onMouseEnter={onMouseEnter} @@ -51,7 +51,7 @@ export const Badge = forwardRef< {badge} {mainTooltip} {secondaryTooltip && {secondaryTooltip}} @@ -73,10 +73,7 @@ export const BadgeGroup = forwardRef< return (
{children} diff --git a/packages/shadcn/src/comments/Card.tsx b/packages/shadcn/src/comments/Card.tsx index 70cdb17193..75b880b54f 100644 --- a/packages/shadcn/src/comments/Card.tsx +++ b/packages/shadcn/src/comments/Card.tsx @@ -28,8 +28,8 @@ export const Card = forwardRef< {headerText && ( -
- {headerText} -
+
{headerText}
)} {children}
@@ -58,9 +56,9 @@ export const CardSection = forwardRef<
diff --git a/packages/shadcn/src/comments/Comment.tsx b/packages/shadcn/src/comments/Comment.tsx index c493a56642..75caab87bb 100644 --- a/packages/shadcn/src/comments/Comment.tsx +++ b/packages/shadcn/src/comments/Comment.tsx @@ -25,47 +25,33 @@ const AuthorInfo = forwardRef< if (authorInfo === "loading") { return ( -
+
); } return ( -
+
{authorInfo.username[0]} -
- {authorInfo.username} - +
+ {authorInfo.username} + {timeString} {edited && `(${dict.comments.edited})`}
@@ -103,15 +89,12 @@ export const Comment = forwardRef< return (
setHovered(true)} onMouseLeave={() => setHovered(false)} > {doShowActions ? ( -
+
{actions}
) : null} diff --git a/packages/shadcn/src/components.ts b/packages/shadcn/src/components.ts index 8eeb14b9b2..13b33302aa 100644 --- a/packages/shadcn/src/components.ts +++ b/packages/shadcn/src/components.ts @@ -34,7 +34,6 @@ import { Badge, BadgeGroup } from "./badge/Badge.js"; import { PanelButton } from "./panel/PanelButton.js"; import { PanelFileInput } from "./panel/PanelFileInput.js"; -import "./style.css"; import { GridSuggestionMenuItem } from "./suggestionMenu/gridSuggestionMenu/GridSuggestionMenuItem.js"; import { GridSuggestionMenuLoader } from "./suggestionMenu/gridSuggestionMenu/GridSuggestionMenuLoader.js"; diff --git a/packages/shadcn/src/components/ui/avatar.tsx b/packages/shadcn/src/components/ui/avatar.tsx index e2f8200740..1dcdcee406 100644 --- a/packages/shadcn/src/components/ui/avatar.tsx +++ b/packages/shadcn/src/components/ui/avatar.tsx @@ -1,48 +1,53 @@ +"use client"; + import * as React from "react"; import * as AvatarPrimitive from "@radix-ui/react-avatar"; import { cn } from "../../lib/utils"; -const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Avatar.displayName = AvatarPrimitive.Root.displayName; +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarImage.displayName = AvatarPrimitive.Image.displayName; +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} -const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} export { Avatar, AvatarImage, AvatarFallback }; diff --git a/packages/shadcn/src/components/ui/badge.tsx b/packages/shadcn/src/components/ui/badge.tsx index 9c5090c631..b1c2ab1b85 100644 --- a/packages/shadcn/src/components/ui/badge.tsx +++ b/packages/shadcn/src/components/ui/badge.tsx @@ -1,20 +1,22 @@ -import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "../../lib/utils.js"; +import { cn } from "../../lib/utils"; const badgeVariants = cva( - "bn-inline-flex bn-items-center bn-rounded-full bn-border bn-px-2.5 bn-py-0.5 bn-text-xs bn-font-semibold bn-transition-colors focus:bn-outline-none focus:bn-ring-2 focus:bn-ring-ring focus:bn-ring-offset-2", + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", { variants: { variant: { default: - "bn-border-transparent bn-bg-primary bn-text-primary-foreground hover:bn-bg-primary/80", + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", secondary: - "bn-border-transparent bn-bg-secondary bn-text-secondary-foreground hover:bn-bg-secondary/80", + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", destructive: - "bn-border-transparent bn-bg-destructive bn-text-destructive-foreground hover:bn-bg-destructive/80", - outline: "bn-text-foreground", + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", }, }, defaultVariants: { @@ -23,13 +25,21 @@ const badgeVariants = cva( }, ); -export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; -function Badge({ className, variant, ...props }: BadgeProps) { return ( -
+ ); } diff --git a/packages/shadcn/src/components/ui/button.tsx b/packages/shadcn/src/components/ui/button.tsx index 5c58360f48..43ab1151fc 100644 --- a/packages/shadcn/src/components/ui/button.tsx +++ b/packages/shadcn/src/components/ui/button.tsx @@ -1,30 +1,31 @@ +import * as React from "react"; import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; -import * as React from "react"; -import { cn } from "../../lib/utils.js"; +import { cn } from "../../lib/utils"; const buttonVariants = cva( - "bn-inline-flex bn-items-center bn-justify-center bn-whitespace-nowrap bn-rounded-md bn-text-sm bn-font-medium bn-ring-offset-background bn-transition-colors focus-visible:bn-outline-none focus-visible:bn-ring-2 focus-visible:bn-ring-ring focus-visible:bn-ring-offset-2 disabled:bn-pointer-events-none disabled:bn-opacity-50", + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*=size-])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", { variants: { variant: { default: - "bn-bg-primary bn-text-primary-foreground hover:bn-bg-primary/90", + "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", destructive: - "bn-bg-destructive bn-text-destructive-foreground hover:bn-bg-destructive/90", + "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", outline: - "bn-border bn-border-input bn-bg-background hover:bn-bg-accent hover:bn-text-accent-foreground", + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", secondary: - "bn-bg-secondary bn-text-secondary-foreground hover:bn-bg-secondary/80", - ghost: "hover:bn-bg-accent hover:bn-text-accent-foreground", - link: "bn-text-primary bn-underline-offset-4 hover:bn-underline", + "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", }, size: { - default: "bn-h-10 bn-px-4 bn-py-2", - sm: "bn-h-9 bn-rounded-md bn-px-3", - lg: "bn-h-11 bn-rounded-md bn-px-8", - icon: "bn-h-10 bn-w-10", + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", }, }, defaultVariants: { @@ -34,25 +35,25 @@ const buttonVariants = cva( }, ); -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean; -} +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot : "button"; -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; - return ( - - ); - }, -); -Button.displayName = "Button"; + return ( + + ); +} export { Button, buttonVariants }; diff --git a/packages/shadcn/src/components/ui/card.tsx b/packages/shadcn/src/components/ui/card.tsx index eea62ac026..0deef84bed 100644 --- a/packages/shadcn/src/components/ui/card.tsx +++ b/packages/shadcn/src/components/ui/card.tsx @@ -1,86 +1,92 @@ import * as React from "react"; -import { cn } from "../../lib/utils.js"; +import { cn } from "../../lib/utils"; -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -Card.displayName = "Card"; +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -CardHeader.displayName = "CardHeader"; +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} -const CardTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)); -CardTitle.displayName = "CardTitle"; +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)); -CardDescription.displayName = "CardDescription"; +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +

+ ); +} -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -CardContent.displayName = "CardContent"; +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -CardFooter.displayName = "CardFooter"; +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} export { Card, - CardContent, - CardDescription, - CardFooter, CardHeader, + CardFooter, CardTitle, + CardAction, + CardDescription, + CardContent, }; diff --git a/packages/shadcn/src/components/ui/dropdown-menu.tsx b/packages/shadcn/src/components/ui/dropdown-menu.tsx index aa3e83f7af..568aad2a78 100644 --- a/packages/shadcn/src/components/ui/dropdown-menu.tsx +++ b/packages/shadcn/src/components/ui/dropdown-menu.tsx @@ -1,201 +1,255 @@ -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; -import { Check, ChevronRight, Circle } from "lucide-react"; +"use client"; + import * as React from "react"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; + +import { cn } from "../../lib/utils"; -import { cn } from "../../lib/utils.js"; - -const DropdownMenu = DropdownMenuPrimitive.Root; - -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; - -const DropdownMenuGroup = DropdownMenuPrimitive.Group; - -const DropdownMenuPortal = DropdownMenuPrimitive.Portal; - -const DropdownMenuSub = DropdownMenuPrimitive.Sub; - -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; - -const DropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)); -DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName; - -const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName; - -const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - // - - // -)); -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; - -const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; - -const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName; - -const DropdownMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)); -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; - -const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean; - } ->(({ className, inset, ...props }, ref) => ( - -)); -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; - -const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; - -const DropdownMenuShortcut = ({ +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuContent({ className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuGroup({ ...props -}: React.HTMLAttributes) => { +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { return ( ); -}; -DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} export { DropdownMenu, - DropdownMenuCheckboxItem, + DropdownMenuPortal, + DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, - DropdownMenuItem, DropdownMenuLabel, - DropdownMenuPortal, + DropdownMenuItem, + DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, - DropdownMenuSubContent, DropdownMenuSubTrigger, - DropdownMenuTrigger, + DropdownMenuSubContent, }; diff --git a/packages/shadcn/src/components/ui/form.tsx b/packages/shadcn/src/components/ui/form.tsx index 0e9d39720f..733fdf6a62 100644 --- a/packages/shadcn/src/components/ui/form.tsx +++ b/packages/shadcn/src/components/ui/form.tsx @@ -1,17 +1,18 @@ +import * as React from "react"; import * as LabelPrimitive from "@radix-ui/react-label"; import { Slot } from "@radix-ui/react-slot"; -import * as React from "react"; import { Controller, - ControllerProps, - FieldPath, - FieldValues, FormProvider, useFormContext, + useFormState, + type ControllerProps, + type FieldPath, + type FieldValues, } from "react-hook-form"; -import { cn } from "../../lib/utils.js"; -import { Label } from "./label.js"; +import { cn } from "../../lib/utils"; +import { Label } from "./label"; const Form = FormProvider; @@ -42,8 +43,8 @@ const FormField = < const useFormField = () => { const fieldContext = React.useContext(FormFieldContext); const itemContext = React.useContext(FormItemContext); - const { getFieldState, formState } = useFormContext(); - + const { getFieldState } = useFormContext(); + const formState = useFormState({ name: fieldContext.name }); const fieldState = getFieldState(fieldContext.name, formState); if (!fieldContext) { @@ -70,47 +71,44 @@ const FormItemContext = React.createContext( {} as FormItemContextValue, ); -const FormItem = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => { +function FormItem({ className, ...props }: React.ComponentProps<"div">) { const id = React.useId(); return ( -
+
); -}); -FormItem.displayName = "FormItem"; +} -const FormLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { +function FormLabel({ + className, + ...props +}: React.ComponentProps) { const { error, formItemId } = useFormField(); return (