fix: actions
This commit is contained in:
parent
071778533c
commit
cb941daca9
17 changed files with 277 additions and 65 deletions
|
|
@ -1,9 +1,10 @@
|
|||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { kv } from '@vercel/kv'
|
||||
import { auth } from '@/auth'
|
||||
|
||||
import { auth } from '@/auth'
|
||||
import { type Chat } from '@/lib/types'
|
||||
|
||||
export async function getChats(userId?: string | null) {
|
||||
|
|
@ -32,12 +33,8 @@ export async function getChats(userId?: string | null) {
|
|||
export async function getChat(id: string, userId: string) {
|
||||
const chat = await kv.hgetall<Chat>(`chat:${id}`)
|
||||
|
||||
if (!chat) {
|
||||
throw new Error('Not found')
|
||||
}
|
||||
|
||||
if (userId && chat.userId !== userId) {
|
||||
throw new Error('Unauthorized')
|
||||
if (!chat || (userId && chat.userId !== userId)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return chat
|
||||
|
|
@ -47,41 +44,36 @@ export async function removeChat({ id, path }: { id: string; path: string }) {
|
|||
const session = await auth()
|
||||
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
return {
|
||||
error: 'Unauthorized'
|
||||
}
|
||||
}
|
||||
|
||||
const uid = await kv.hget<string>(`chat:${id}`, 'userId')
|
||||
|
||||
if (uid !== session?.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
return {
|
||||
error: 'Unauthorized'
|
||||
}
|
||||
}
|
||||
|
||||
await kv.del(`chat:${id}`)
|
||||
await kv.zrem(`user:chat:${session.user.id}`, `chat:${id}`)
|
||||
|
||||
revalidatePath('/')
|
||||
revalidatePath(path)
|
||||
return revalidatePath(path)
|
||||
}
|
||||
|
||||
export async function clearChats() {
|
||||
const session = await auth()
|
||||
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
error: 'Unauthorized'
|
||||
}
|
||||
}
|
||||
|
||||
if (!session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const chats: string[] = await kv.zrange(
|
||||
`user:chat:${session.user.id}`,
|
||||
0,
|
||||
-1,
|
||||
{
|
||||
rev: true
|
||||
}
|
||||
)
|
||||
const chats: string[] = await kv.zrange(`user:chat:${session.user.id}`, 0, -1)
|
||||
|
||||
const pipeline = kv.pipeline()
|
||||
|
||||
|
|
@ -93,6 +85,7 @@ export async function clearChats() {
|
|||
await pipeline.exec()
|
||||
|
||||
revalidatePath('/')
|
||||
return redirect('/')
|
||||
}
|
||||
|
||||
export async function getSharedChat(id: string) {
|
||||
|
|
@ -108,16 +101,10 @@ export async function getSharedChat(id: string) {
|
|||
export async function shareChat(chat: Chat) {
|
||||
const session = await auth()
|
||||
|
||||
if (!session) {
|
||||
throw new Error('Unauthorized')
|
||||
if (!session?.user?.id || session.user.id !== chat.userId) {
|
||||
return {
|
||||
error: 'Unauthorized'
|
||||
}
|
||||
|
||||
if (!session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
if (chat.userId !== session.user?.id) {
|
||||
throw new Error('Unauthorized')
|
||||
}
|
||||
|
||||
const payload = {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { kv } from '@vercel/kv'
|
||||
import { OpenAIStream, StreamingTextResponse } from 'ai-connector'
|
||||
import { Configuration, OpenAIApi } from 'openai-edge'
|
||||
import { nanoid } from '@/lib/utils'
|
||||
|
||||
import { auth } from '@/auth'
|
||||
import { nanoid } from '@/lib/utils'
|
||||
|
||||
export const runtime = 'edge'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { type Metadata } from 'next'
|
||||
import { auth } from '@/auth'
|
||||
import { notFound, redirect } from 'next/navigation'
|
||||
|
||||
import { Chat } from '@/components/chat'
|
||||
import { auth } from '@/auth'
|
||||
import { getChat } from '@/app/actions'
|
||||
import { Chat } from '@/components/chat'
|
||||
|
||||
// export const runtime = 'edge'
|
||||
export const preferredRegion = 'home'
|
||||
|
|
@ -16,16 +17,30 @@ export interface ChatPageProps {
|
|||
export async function generateMetadata({
|
||||
params
|
||||
}: ChatPageProps): Promise<Metadata> {
|
||||
const { user } = await auth()
|
||||
const chat = await getChat(params.id, user?.id ?? '')
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const chat = await getChat(params.id, session.user.id)
|
||||
return {
|
||||
title: chat?.title.slice(0, 50) ?? 'Chat'
|
||||
}
|
||||
}
|
||||
|
||||
export default async function ChatPage({ params }: ChatPageProps) {
|
||||
const { user } = await auth()
|
||||
const chat = await getChat(params.id, user?.id ?? '')
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user) {
|
||||
redirect('/sign-in')
|
||||
}
|
||||
|
||||
const chat = await getChat(params.id, session.user.id)
|
||||
|
||||
if (!chat) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return <Chat id={chat.id} initialMessages={chat.messages} />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
'use client'
|
||||
|
||||
import { type Message } from 'ai-connector'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { IconCheck, IconCopy } from '@/components/ui/icons'
|
||||
import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { type Message } from 'ai-connector'
|
||||
|
||||
interface ChatMessageActionsProps extends React.ComponentProps<'div'> {
|
||||
message: Message
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { type UseChatHelpers } from 'ai-connector/react'
|
||||
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { ExternalLink } from '@/components/external-link'
|
||||
import { PromptForm } from '@/components/prompt-form'
|
||||
import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom'
|
||||
import { IconRefresh, IconStop } from '@/components/ui/icons'
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@ import { ChatScrollAnchor } from '@/components/chat-scroll-anchor'
|
|||
|
||||
export interface ChatProps extends React.ComponentProps<'div'> {
|
||||
initialMessages?: Message[]
|
||||
|
||||
id?: string
|
||||
}
|
||||
|
||||
export function Chat({ id, title, initialMessages, className }: ChatProps) {
|
||||
export function Chat({ id, initialMessages, className }: ChatProps) {
|
||||
const { messages, append, reload, stop, isLoading, input, setInput } =
|
||||
useChat({
|
||||
initialMessages,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
import * as React from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { ServerActionResult } from '@/lib/types'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
AlertDialog,
|
||||
|
|
@ -18,7 +20,7 @@ import {
|
|||
import { IconSpinner } from '@/components/ui/icons'
|
||||
|
||||
interface ClearHistoryProps {
|
||||
clearChats: () => Promise<void>
|
||||
clearChats: () => ServerActionResult<void>
|
||||
}
|
||||
|
||||
export function ClearHistory({ clearChats }: ClearHistoryProps) {
|
||||
|
|
@ -49,7 +51,13 @@ export function ClearHistory({ clearChats }: ClearHistoryProps) {
|
|||
onClick={event => {
|
||||
event.preventDefault()
|
||||
startTransition(async () => {
|
||||
await clearChats()
|
||||
const result = await clearChats()
|
||||
|
||||
if (result && 'error' in result) {
|
||||
toast.error(result.error)
|
||||
return
|
||||
}
|
||||
|
||||
setOpen(false)
|
||||
router.push('/')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
|
||||
import { ExternalLink } from '@/components/external-link'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ExternalLink } from '@/components/external-link'
|
||||
|
||||
export function FooterText({ className, ...props }: React.ComponentProps<'p'>) {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
import { Suspense, use } from 'react'
|
||||
import * as React from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import { auth } from '@/auth'
|
||||
import { clearChats } from '@/app/actions'
|
||||
import { buttonVariants } from '@/components/ui/button'
|
||||
import { Sidebar } from '@/components/sidebar'
|
||||
import { SidebarList } from '@/components/sidebar-list'
|
||||
import { IconGitHub, IconSeparator, IconVercel } from '@/components/ui/icons'
|
||||
|
||||
import { SidebarFooter } from '@/components/sidebar-footer'
|
||||
import { ThemeToggle } from '@/components/theme-toggle'
|
||||
import { ClearHistory } from '@/components/clear-history'
|
||||
import { clearChats } from '@/app/actions'
|
||||
import Link from 'next/link'
|
||||
import { auth } from '@/auth'
|
||||
import { UserMenu } from './user-menu'
|
||||
import { LoginButton } from './login-button'
|
||||
import { UserMenu } from '@/components/user-menu'
|
||||
import { LoginButton } from '@/components/login-button'
|
||||
|
||||
export async function Header() {
|
||||
const session = await auth()
|
||||
|
|
@ -22,10 +21,10 @@ export async function Header() {
|
|||
<div className="flex items-center">
|
||||
{session?.user ? (
|
||||
<Sidebar>
|
||||
<Suspense fallback={<div className="flex-1 overflow-auto" />}>
|
||||
<React.Suspense fallback={<div className="flex-1 overflow-auto" />}>
|
||||
{/* @ts-ignore */}
|
||||
<SidebarList userId={session?.user?.id} />
|
||||
</Suspense>
|
||||
</React.Suspense>
|
||||
<SidebarFooter>
|
||||
<ThemeToggle />
|
||||
<ClearHistory clearChats={clearChats} />
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import * as React from 'react'
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
||||
import { ThemeProviderProps } from 'next-themes/dist/types'
|
||||
|
||||
import { TooltipProvider } from '@/components/ui/tooltip'
|
||||
|
||||
export function Providers({ children, ...props }: ThemeProviderProps) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import {
|
|||
|
||||
interface SidebarActionsProps {
|
||||
chat: Chat
|
||||
removeChat: (args: { id: string; path: string }) => Promise<void>
|
||||
removeChat: (args: { id: string; path: string }) => ServerActionResult<void>
|
||||
shareChat: (chat: Chat) => ServerActionResult<Chat>
|
||||
}
|
||||
|
||||
|
|
@ -150,8 +150,8 @@ export function SidebarActions({
|
|||
|
||||
const result = await shareChat(chat)
|
||||
|
||||
if (!('id' in result)) {
|
||||
toast.error(result.message)
|
||||
if (result && 'error' in result) {
|
||||
toast.error(result.error)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -189,10 +189,16 @@ export function SidebarActions({
|
|||
onClick={event => {
|
||||
event.preventDefault()
|
||||
startRemoveTransition(async () => {
|
||||
await removeChat({
|
||||
const result = await removeChat({
|
||||
id: chat.id,
|
||||
path: chat.path
|
||||
})
|
||||
|
||||
if (result && 'error' in result) {
|
||||
toast.error(result.error)
|
||||
return
|
||||
}
|
||||
|
||||
setDeleteDialogOpen(false)
|
||||
router.push('/')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { getChats, removeChat, shareChat } from '@/app/actions'
|
||||
import { SidebarActions } from '@/components/sidebar-actions'
|
||||
|
||||
import { SidebarItem } from '@/components/sidebar-item'
|
||||
|
||||
export interface SidebarListProps {
|
||||
|
|
|
|||
|
|
@ -459,6 +459,23 @@ function IconExternalLink({
|
|||
)
|
||||
}
|
||||
|
||||
function IconChevronUpDown({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<'svg'>) {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor"
|
||||
className={cn('h-4 w-4', className)}
|
||||
viewBox="0 0 256 256"
|
||||
{...props}
|
||||
>
|
||||
<path d="M181.66 170.34a8 8 0 0 1 0 11.32l-48 48a8 8 0 0 1-11.32 0l-48-48a8 8 0 0 1 11.32-11.32L128 212.69l42.34-42.35a8 8 0 0 1 11.32 0Zm-96-84.68L128 43.31l42.34 42.35a8 8 0 0 0 11.32-11.32l-48-48a8 8 0 0 0-11.32 0l-48 48a8 8 0 0 0 11.32 11.32Z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
IconEdit,
|
||||
IconNextChat,
|
||||
|
|
@ -485,5 +502,6 @@ export {
|
|||
IconClose,
|
||||
IconShare,
|
||||
IconUsers,
|
||||
IconExternalLink
|
||||
IconExternalLink,
|
||||
IconChevronUpDown
|
||||
}
|
||||
|
|
|
|||
123
components/ui/select.tsx
Normal file
123
components/ui/select.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
'use client'
|
||||
|
||||
import * as React from 'react'
|
||||
import * as SelectPrimitive from '@radix-ui/react-select'
|
||||
|
||||
import { cn } from '@/lib/utils'
|
||||
import {
|
||||
IconArrowDown,
|
||||
IconCheck,
|
||||
IconChevronUpDown
|
||||
} from '@/components/ui/icons'
|
||||
|
||||
const Select = SelectPrimitive.Root
|
||||
|
||||
const SelectGroup = SelectPrimitive.Group
|
||||
|
||||
const SelectValue = SelectPrimitive.Value
|
||||
|
||||
const SelectTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<IconChevronUpDown className="opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
))
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
|
||||
|
||||
const SelectContent = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = 'popper', ...props }, ref) => (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-80',
|
||||
position === 'popper' && 'translate-y-1',
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
'p-1',
|
||||
position === 'popper' &&
|
||||
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
))
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName
|
||||
|
||||
const SelectLabel = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName
|
||||
|
||||
const SelectItem = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<IconCheck className="h-4 w-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
))
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName
|
||||
|
||||
const SelectSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 my-1 h-px bg-muted', className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectGroup,
|
||||
SelectValue,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectLabel,
|
||||
SelectItem,
|
||||
SelectSeparator
|
||||
}
|
||||
|
|
@ -10,4 +10,9 @@ export interface Chat extends Record<string, any> {
|
|||
sharePath?: string
|
||||
}
|
||||
|
||||
export type ServerActionResult<Result> = Promise<Result | Error>
|
||||
export type ServerActionResult<Result> = Promise<
|
||||
| Result
|
||||
| {
|
||||
error: string
|
||||
}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.5",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-select": "^1.2.2",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
|
|
|
|||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
|
|
@ -20,6 +20,9 @@ dependencies:
|
|||
'@radix-ui/react-label':
|
||||
specifier: ^2.0.2
|
||||
version: 2.0.2(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-select':
|
||||
specifier: ^1.2.2
|
||||
version: 1.2.2(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-separator':
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
|
|
@ -458,6 +461,12 @@ packages:
|
|||
tslib: 2.5.0
|
||||
dev: true
|
||||
|
||||
/@radix-ui/number@1.0.1:
|
||||
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.5
|
||||
dev: false
|
||||
|
||||
/@radix-ui/primitive@1.0.1:
|
||||
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
|
||||
dependencies:
|
||||
|
|
@ -897,6 +906,47 @@ packages:
|
|||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-select@1.2.2(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.5
|
||||
'@radix-ui/number': 1.0.1
|
||||
'@radix-ui/primitive': 1.0.1
|
||||
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-focus-scope': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-id': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-popper': 1.1.2(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-portal': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.6)(react@18.2.0)
|
||||
'@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@types/react': 18.2.6
|
||||
'@types/react-dom': 18.2.4
|
||||
aria-hidden: 1.2.3
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-remove-scroll: 2.5.5(@types/react@18.2.6)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.6)(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
|
||||
peerDependencies:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue