mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-22 20:25:44 +00:00
Compare commits
10 Commits
shadcn@2.1
...
shadcn@2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70c684c224 | ||
|
|
4ff64ba818 | ||
|
|
500a353816 | ||
|
|
c830780d62 | ||
|
|
debd51a854 | ||
|
|
78426dd862 | ||
|
|
6e47a94a8f | ||
|
|
ab6a856930 | ||
|
|
b33d3868e9 | ||
|
|
9e0a86122a |
@@ -10,8 +10,8 @@ import {
|
|||||||
PageHeaderDescription,
|
PageHeaderDescription,
|
||||||
PageHeaderHeading,
|
PageHeaderHeading,
|
||||||
} from "@/components/page-header"
|
} from "@/components/page-header"
|
||||||
|
import CardsNewYork from "@/registry/new-york/example/cards"
|
||||||
import { Button } from "@/registry/new-york/ui/button"
|
import { Button } from "@/registry/new-york/ui/button"
|
||||||
import MailPage from "@/app/(app)/examples/mail/page"
|
|
||||||
|
|
||||||
export default function IndexPage() {
|
export default function IndexPage() {
|
||||||
return (
|
return (
|
||||||
@@ -41,24 +41,22 @@ export default function IndexPage() {
|
|||||||
<ExamplesNav className="[&>a:first-child]:text-primary" />
|
<ExamplesNav className="[&>a:first-child]:text-primary" />
|
||||||
<section className="overflow-hidden rounded-lg border bg-background shadow-md md:hidden md:shadow-xl">
|
<section className="overflow-hidden rounded-lg border bg-background shadow-md md:hidden md:shadow-xl">
|
||||||
<Image
|
<Image
|
||||||
src="/examples/mail-dark.png"
|
src="/examples/cards-light.png"
|
||||||
width={1280}
|
width={1280}
|
||||||
height={727}
|
height={1214}
|
||||||
alt="Mail"
|
alt="Cards"
|
||||||
className="hidden dark:block"
|
|
||||||
/>
|
|
||||||
<Image
|
|
||||||
src="/examples/mail-light.png"
|
|
||||||
width={1280}
|
|
||||||
height={727}
|
|
||||||
alt="Mail"
|
|
||||||
className="block dark:hidden"
|
className="block dark:hidden"
|
||||||
/>
|
/>
|
||||||
|
<Image
|
||||||
|
src="/examples/cards-dark.png"
|
||||||
|
width={1280}
|
||||||
|
height={1214}
|
||||||
|
alt="Cards"
|
||||||
|
className="hidden dark:block"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
<section className="hidden md:block">
|
<section className="hidden md:block [&>div]:p-0">
|
||||||
<div className="overflow-hidden rounded-lg border bg-background shadow">
|
<CardsNewYork />
|
||||||
<MailPage />
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ import { cn } from "@/lib/utils"
|
|||||||
import { ScrollArea, ScrollBar } from "@/registry/new-york/ui/scroll-area"
|
import { ScrollArea, ScrollBar } from "@/registry/new-york/ui/scroll-area"
|
||||||
|
|
||||||
const examples = [
|
const examples = [
|
||||||
|
{
|
||||||
|
name: "Examples",
|
||||||
|
href: "/",
|
||||||
|
code: "https://github.com/shadcn/ui/tree/main/apps/www/app/(app)/examples/mail",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Mail",
|
name: "Mail",
|
||||||
href: "/examples/mail",
|
href: "/examples/mail",
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ description: Beautiful charts. Built using Recharts. Copy and paste into your ap
|
|||||||
component: true
|
component: true
|
||||||
---
|
---
|
||||||
|
|
||||||
<Callout className="mb-6">
|
|
||||||
|
|
||||||
**Note:** If you are using charts with **React 19** or the **Next.js 15**, see the note [here](/docs/react-19#recharts).
|
|
||||||
|
|
||||||
</Callout>
|
|
||||||
|
|
||||||
<ComponentPreview
|
<ComponentPreview
|
||||||
name="chart-bar-interactive"
|
name="chart-bar-interactive"
|
||||||
className="-mt-4 [&_.preview]:p-0 [&_.preview]:border-t [&_.preview>div]:shadow-none [&_.preview>div]:border-none [&_.preview>div]:w-full [&_.preview]:lg:min-h-[404px]"
|
className="-mt-4 [&_.preview]:p-0 [&_.preview]:border-t [&_.preview>div]:shadow-none [&_.preview>div]:border-none [&_.preview>div]:w-full [&_.preview]:lg:min-h-[404px]"
|
||||||
@@ -51,12 +45,6 @@ We do not wrap Recharts. This means you're not locked into an abstraction. When
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
<Callout className="mt-4">
|
|
||||||
|
|
||||||
**Note:** If you are using charts with **React 19** or the **Next.js 15**, see the note [here](/docs/react-19#recharts).
|
|
||||||
|
|
||||||
</Callout>
|
|
||||||
|
|
||||||
<Tabs defaultValue="cli">
|
<Tabs defaultValue="cli">
|
||||||
|
|
||||||
<TabsList>
|
<TabsList>
|
||||||
@@ -95,6 +83,27 @@ npx shadcn@latest add chart
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<Step>
|
||||||
|
To use recharts with React 19 and Next.js 15, you will need to override the
|
||||||
|
`react-is` dependency.{" "}
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
Add the following to your `package.json`
|
||||||
|
|
||||||
|
```json title="package.json"
|
||||||
|
"overrides": {
|
||||||
|
"react-is": "^19.0.0-rc-69d4b800-20241021"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: the `react-is` version needs to match the version of React 19 you are using. The above is an example.
|
||||||
|
|
||||||
|
<Step>Run `npm install`</Step>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
@@ -135,6 +144,27 @@ npm install recharts
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<Step>
|
||||||
|
To use recharts with React 19 and Next.js 15, you will need to override the
|
||||||
|
`react-is` dependency.{" "}
|
||||||
|
</Step>
|
||||||
|
|
||||||
|
Add the following to your `package.json`
|
||||||
|
|
||||||
|
```json title="package.json"
|
||||||
|
"overrides": {
|
||||||
|
"react-is": "^19.0.0-rc-69d4b800-20241021"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: the `react-is` version needs to match the version of React 19 you are using. The above is an example.
|
||||||
|
|
||||||
|
<Step>Run `npm install`</Step>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|||||||
@@ -406,6 +406,40 @@ You can change the keyboard shortcut by updating the `SIDEBAR_KEYBOARD_SHORTCUT`
|
|||||||
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Persisted State
|
||||||
|
|
||||||
|
The `SidebarProvider` supports persisting the sidebar state across page reloads and server-side rendering. It uses cookies to store the current state of the sidebar. When the sidebar state changes, a default cookie named `sidebar:state` is set with the current open/closed state. This cookie is then read on subsequent page loads to restore the sidebar state.
|
||||||
|
|
||||||
|
To persist sidebar state in Next.js, set up your `SidebarProvider` in `app/layout.tsx` like this:
|
||||||
|
|
||||||
|
```tsx showLineNumbers title="app/layout.tsx"
|
||||||
|
import { cookies } from "next/headers"
|
||||||
|
|
||||||
|
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
|
||||||
|
import { AppSidebar } from "@/components/app-sidebar"
|
||||||
|
|
||||||
|
export async function Layout({ children }: { children: React.ReactNode }) {
|
||||||
|
const cookieStore = await cookies()
|
||||||
|
const defaultOpen = cookieStore.get("sidebar:state")?.value === "true"
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarProvider defaultOpen={defaultOpen}>
|
||||||
|
<AppSidebar />
|
||||||
|
<main>
|
||||||
|
<SidebarTrigger />
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</SidebarProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can change the name of the cookie by updating the `SIDEBAR_COOKIE_NAME` variable in `sidebar.tsx`.
|
||||||
|
|
||||||
|
```tsx showLineNumbers title="components/ui/sidebar.tsx"
|
||||||
|
const SIDEBAR_COOKIE_NAME = "sidebar:state"
|
||||||
|
```
|
||||||
|
|
||||||
## Sidebar
|
## Sidebar
|
||||||
|
|
||||||
The main `Sidebar` component used to render a collapsible sidebar.
|
The main `Sidebar` component used to render a collapsible sidebar.
|
||||||
@@ -1323,7 +1357,30 @@ You can find more tips on using states for styling in this [Twitter thread](http
|
|||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### 2024-10-21
|
### 2024-10-30 Cookie handling in setOpen
|
||||||
|
|
||||||
|
- [#5593](https://github.com/shadcn-ui/ui/pull/5593) - Improved setOpen callback logic in `<SidebarProvider>`.
|
||||||
|
|
||||||
|
Update the `setOpen` callback in `<SidebarProvider>` as follows:
|
||||||
|
|
||||||
|
```tsx showLineNumbers
|
||||||
|
const setOpen = React.useCallback(
|
||||||
|
(value: boolean | ((value: boolean) => boolean)) => {
|
||||||
|
const openState = typeof value === "function" ? value(open) : value
|
||||||
|
if (setOpenProp) {
|
||||||
|
setOpenProp(openState)
|
||||||
|
} else {
|
||||||
|
_setOpen(openState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This sets the cookie to keep the sidebar state.
|
||||||
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
||||||
|
},
|
||||||
|
[setOpenProp, open]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2024-10-21 Fixed `text-sidebar-foreground`
|
||||||
|
|
||||||
- [#5491](https://github.com/shadcn-ui/ui/pull/5491) - Moved `text-sidebar-foreground` from `<SidebarProvider>` to `<Sidebar>` component.
|
- [#5491](https://github.com/shadcn-ui/ui/pull/5491) - Moved `text-sidebar-foreground` from `<SidebarProvider>` to `<Sidebar>` component.
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description: Install and configure Next.js.
|
|||||||
|
|
||||||
<Callout>
|
<Callout>
|
||||||
|
|
||||||
**If you're using Next.js 15, see the [Next.js 15 + React 19](/docs/installation/react-19) guide.**
|
**If you're using Next.js 15, see the [Next.js 15 + React 19](/docs/react-19) guide.**
|
||||||
|
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,29 @@ npm install -D tailwindcss postcss autoprefixer
|
|||||||
npx tailwindcss init -p
|
npx tailwindcss init -p
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Add this import header in your main css file, `src/index.css` in our case:
|
||||||
|
|
||||||
|
```css {1-3} showLineNumbers
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
/* ... */
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure the tailwind template paths in `tailwind.config.js`:
|
||||||
|
|
||||||
|
```js {3}
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Edit tsconfig.json file
|
### Edit tsconfig.json file
|
||||||
|
|
||||||
The current version of Vite splits TypeScript configuration into three files, two of which need to be edited.
|
The current version of Vite splits TypeScript configuration into three files, two of which need to be edited.
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ title: Next.js 15 + React 19
|
|||||||
description: Using shadcn/ui with Next.js 15 and React 19.
|
description: Using shadcn/ui with Next.js 15 and React 19.
|
||||||
---
|
---
|
||||||
|
|
||||||
<Callout>
|
**shadcn/ui is now fully compatible with React 19!**
|
||||||
|
|
||||||
|
<Callout className="mt-6">
|
||||||
**The following guide applies to any framework that supports React 19**. I
|
**The following guide applies to any framework that supports React 19**. I
|
||||||
titled this page "Next.js 15 + React 19" to help people upgrading to Next.js
|
titled this page "Next.js 15 + React 19" to help people upgrading to Next.js
|
||||||
15 find it. We are working with package maintainers to help upgrade to React
|
15 find it. We are working with package maintainers to help upgrade to React
|
||||||
@@ -22,9 +24,11 @@ React 19 is now [rc](https://www.npmjs.com/package/react?activeTab=versions) and
|
|||||||
|
|
||||||
To support React 19, package maintainers will need to test and update their packages to include React 19 as a peer dependency. This is [already](https://github.com/radix-ui/primitives/pull/2952) [in](https://github.com/pacocoursey/cmdk/pull/318) [progress](https://github.com/emilkowalski/vaul/pull/498).
|
To support React 19, package maintainers will need to test and update their packages to include React 19 as a peer dependency. This is [already](https://github.com/radix-ui/primitives/pull/2952) [in](https://github.com/pacocoursey/cmdk/pull/318) [progress](https://github.com/emilkowalski/vaul/pull/498).
|
||||||
|
|
||||||
```diff /^19.0.0/
|
```diff /^19.0/
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0",
|
- "react": "^16.8 || ^17.0 || ^18.0",
|
||||||
|
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0",
|
||||||
|
- "react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||||
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0"
|
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0"
|
||||||
},
|
},
|
||||||
```
|
```
|
||||||
@@ -140,8 +144,8 @@ To make it easy for you track the progress of the upgrade, I've created a table
|
|||||||
| [react-day-picker](https://www.npmjs.com/package/react-day-picker) | ✅ | Works with flag for npm. Work to upgrade to v9 in progress. |
|
| [react-day-picker](https://www.npmjs.com/package/react-day-picker) | ✅ | Works with flag for npm. Work to upgrade to v9 in progress. |
|
||||||
| [input-otp](https://www.npmjs.com/package/input-otp) | ✅ | |
|
| [input-otp](https://www.npmjs.com/package/input-otp) | ✅ | |
|
||||||
| [vaul](https://www.npmjs.com/package/vaul) | ✅ | |
|
| [vaul](https://www.npmjs.com/package/vaul) | ✅ | |
|
||||||
| [@radix-ui/react-icons](https://www.npmjs.com/package/@radix-ui/react-icons) | 🚧 | See [PR #184](https://github.com/radix-ui/icons/pull/184) |
|
| [@radix-ui/react-icons](https://www.npmjs.com/package/@radix-ui/react-icons) | ✅ | |
|
||||||
| [cmdk](https://www.npmjs.com/package/cmdk) | 🚧 | See [PR #318](https://github.com/pacocoursey/cmdk/pull/318) |
|
| [cmdk](https://www.npmjs.com/package/cmdk) | ✅ | |
|
||||||
|
|
||||||
If you have any questions, please [open an issue](https://github.com/shadcn/ui/issues) on GitHub.
|
If you have any questions, please [open an issue](https://github.com/shadcn/ui/issues) on GitHub.
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -76,16 +76,15 @@ const SidebarProvider = React.forwardRef<
|
|||||||
const open = openProp ?? _open
|
const open = openProp ?? _open
|
||||||
const setOpen = React.useCallback(
|
const setOpen = React.useCallback(
|
||||||
(value: boolean | ((value: boolean) => boolean)) => {
|
(value: boolean | ((value: boolean) => boolean)) => {
|
||||||
|
const openState = typeof value === "function" ? value(open) : value
|
||||||
if (setOpenProp) {
|
if (setOpenProp) {
|
||||||
return setOpenProp?.(
|
setOpenProp(openState)
|
||||||
typeof value === "function" ? value(open) : value
|
} else {
|
||||||
)
|
_setOpen(openState)
|
||||||
}
|
}
|
||||||
|
|
||||||
_setOpen(value)
|
|
||||||
|
|
||||||
// This sets the cookie to keep the sidebar state.
|
// This sets the cookie to keep the sidebar state.
|
||||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
||||||
},
|
},
|
||||||
[setOpenProp, open]
|
[setOpenProp, open]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { CheckIcon, PaperPlaneIcon, PlusIcon } from "@radix-ui/react-icons"
|
import { CheckIcon, PaperPlaneIcon, PlusIcon } from "@radix-ui/react-icons"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
import { useTheme } from "next-themes"
|
import { useTheme } from "next-themes"
|
||||||
import { Line, LineChart, ResponsiveContainer, Tooltip } from "recharts"
|
import { Line, LineChart, ResponsiveContainer, Tooltip } from "recharts"
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
import { useTheme } from "next-themes"
|
import { useTheme } from "next-themes"
|
||||||
import { Bar, BarChart, Line, LineChart, ResponsiveContainer } from "recharts"
|
import { Bar, BarChart, Line, LineChart, ResponsiveContainer } from "recharts"
|
||||||
|
|
||||||
|
|||||||
@@ -76,16 +76,15 @@ const SidebarProvider = React.forwardRef<
|
|||||||
const open = openProp ?? _open
|
const open = openProp ?? _open
|
||||||
const setOpen = React.useCallback(
|
const setOpen = React.useCallback(
|
||||||
(value: boolean | ((value: boolean) => boolean)) => {
|
(value: boolean | ((value: boolean) => boolean)) => {
|
||||||
|
const openState = typeof value === "function" ? value(open) : value
|
||||||
if (setOpenProp) {
|
if (setOpenProp) {
|
||||||
return setOpenProp?.(
|
setOpenProp(openState)
|
||||||
typeof value === "function" ? value(open) : value
|
} else {
|
||||||
)
|
_setOpen(openState)
|
||||||
}
|
}
|
||||||
|
|
||||||
_setOpen(value)
|
|
||||||
|
|
||||||
// This sets the cookie to keep the sidebar state.
|
// This sets the cookie to keep the sidebar state.
|
||||||
document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
|
||||||
},
|
},
|
||||||
[setOpenProp, open]
|
[setOpenProp, open]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @shadcn/ui
|
# @shadcn/ui
|
||||||
|
|
||||||
|
## 2.1.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- [#5686](https://github.com/shadcn-ui/ui/pull/5686) [`4ff64ba`](https://github.com/shadcn-ui/ui/commit/4ff64ba818d15a094547f845ea294c2e1ab208d4) Thanks [@shadcn](https://github.com/shadcn)! - remove flag for npm
|
||||||
|
|
||||||
## 2.1.3
|
## 2.1.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "shadcn",
|
"name": "shadcn",
|
||||||
"version": "2.1.3",
|
"version": "2.1.4",
|
||||||
"description": "Add components to your apps.",
|
"description": "Add components to your apps.",
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import { Config } from "@/src/utils/get-config"
|
import { Config } from "@/src/utils/get-config"
|
||||||
import { getPackageInfo } from "@/src/utils/get-package-info"
|
|
||||||
import { getPackageManager } from "@/src/utils/get-package-manager"
|
import { getPackageManager } from "@/src/utils/get-package-manager"
|
||||||
import { logger } from "@/src/utils/logger"
|
|
||||||
import { RegistryItem } from "@/src/utils/registry/schema"
|
import { RegistryItem } from "@/src/utils/registry/schema"
|
||||||
import { spinner } from "@/src/utils/spinner"
|
import { spinner } from "@/src/utils/spinner"
|
||||||
import { execa } from "execa"
|
import { execa } from "execa"
|
||||||
import prompts from "prompts"
|
|
||||||
|
|
||||||
export async function updateDependencies(
|
export async function updateDependencies(
|
||||||
dependencies: RegistryItem["dependencies"],
|
dependencies: RegistryItem["dependencies"],
|
||||||
@@ -29,52 +26,12 @@ export async function updateDependencies(
|
|||||||
})?.start()
|
})?.start()
|
||||||
const packageManager = await getPackageManager(config.resolvedPaths.cwd)
|
const packageManager = await getPackageManager(config.resolvedPaths.cwd)
|
||||||
|
|
||||||
// Offer to use --force or --legacy-peer-deps if using React 19 with npm.
|
|
||||||
let flag = ""
|
|
||||||
if (isUsingReact19(config) && packageManager === "npm") {
|
|
||||||
dependenciesSpinner.stopAndPersist()
|
|
||||||
logger.warn(
|
|
||||||
"\nIt looks like you are using React 19. \nSome packages may fail to install due to peer dependency issues (see https://ui.shadcn.com/react-19).\n"
|
|
||||||
)
|
|
||||||
const confirmation = await prompts([
|
|
||||||
{
|
|
||||||
type: "select",
|
|
||||||
name: "flag",
|
|
||||||
message: "How would you like to proceed?",
|
|
||||||
choices: [
|
|
||||||
{ title: "Use --force", value: "force" },
|
|
||||||
{ title: "Use --legacy-peer-deps", value: "legacy-peer-deps" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
if (confirmation) {
|
|
||||||
flag = confirmation.flag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependenciesSpinner?.start()
|
|
||||||
|
|
||||||
await execa(
|
await execa(
|
||||||
packageManager,
|
packageManager,
|
||||||
[
|
[packageManager === "npm" ? "install" : "add", ...dependencies],
|
||||||
packageManager === "npm" ? "install" : "add",
|
|
||||||
...(packageManager === "npm" && flag ? [`--${flag}`] : []),
|
|
||||||
...dependencies,
|
|
||||||
],
|
|
||||||
{
|
{
|
||||||
cwd: config.resolvedPaths.cwd,
|
cwd: config.resolvedPaths.cwd,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
dependenciesSpinner?.succeed()
|
dependenciesSpinner?.succeed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUsingReact19(config: Config) {
|
|
||||||
const packageInfo = getPackageInfo(config.resolvedPaths.cwd)
|
|
||||||
|
|
||||||
if (!packageInfo?.dependencies?.react) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return /^(?:\^|~)?19(?:\.\d+)*(?:-.*)?$/.test(packageInfo.dependencies.react)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user