mirror of
https://github.com/langgenius/dify.git
synced 2026-04-29 06:58:05 +08:00
feat(web): complete Phase 0 guardrails and add Base UI overlay primitives
- Install @base-ui/react 1.2.0 - Define semantic z-index layer tokens (dropdown/popover/modal/toast/tooltip) - Add TooltipProvider to root layout with global timing config - Mark portal-to-follow-elem as deprecated with migration guide - Enforce no-restricted-imports as error with suppression baseline - Add ESLint rule to block new portal-to-follow-elem usage in business code - Scaffold Phase 1 semantic primitives: Tooltip, DropdownMenu, Popover, Dialog Part of #32767
This commit is contained in:
@ -1,4 +1,16 @@
|
||||
'use client'
|
||||
/**
|
||||
* @deprecated Use semantic overlay primitives from `@/app/components/base/ui/` instead.
|
||||
* This component will be removed after migration is complete.
|
||||
* See: https://github.com/langgenius/dify/issues/32767
|
||||
*
|
||||
* Migration guide:
|
||||
* - Tooltip → `@/app/components/base/ui/tooltip`
|
||||
* - Menu/Dropdown → `@/app/components/base/ui/dropdown-menu`
|
||||
* - Popover → `@/app/components/base/ui/popover`
|
||||
* - Dialog/Modal → `@/app/components/base/ui/dialog`
|
||||
* - Select → `@/app/components/base/ui/select`
|
||||
*/
|
||||
import type { OffsetOptions, Placement } from '@floating-ui/react'
|
||||
import {
|
||||
autoUpdate,
|
||||
@ -33,6 +45,7 @@ export type PortalToFollowElemOptions = {
|
||||
triggerPopupSameWidth?: boolean
|
||||
}
|
||||
|
||||
/** @deprecated Use semantic overlay primitives instead. See #32767. */
|
||||
export function usePortalToFollowElem({
|
||||
placement = 'bottom',
|
||||
open: controlledOpen,
|
||||
@ -110,6 +123,7 @@ export function usePortalToFollowElemContext() {
|
||||
return context
|
||||
}
|
||||
|
||||
/** @deprecated Use semantic overlay primitives instead. See #32767. */
|
||||
export function PortalToFollowElem({
|
||||
children,
|
||||
...options
|
||||
@ -124,6 +138,7 @@ export function PortalToFollowElem({
|
||||
)
|
||||
}
|
||||
|
||||
/** @deprecated Use semantic overlay primitives instead. See #32767. */
|
||||
export const PortalToFollowElemTrigger = (
|
||||
{
|
||||
ref: propRef,
|
||||
@ -164,6 +179,7 @@ export const PortalToFollowElemTrigger = (
|
||||
}
|
||||
PortalToFollowElemTrigger.displayName = 'PortalToFollowElemTrigger'
|
||||
|
||||
/** @deprecated Use semantic overlay primitives instead. See #32767. */
|
||||
export const PortalToFollowElemContent = (
|
||||
{
|
||||
ref: propRef,
|
||||
|
||||
44
web/app/components/base/ui/dialog/index.tsx
Normal file
44
web/app/components/base/ui/dialog/index.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
'use client'
|
||||
|
||||
import { Dialog as BaseDialog } from '@base-ui/react/dialog'
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
export const Dialog = BaseDialog.Root
|
||||
export const DialogTrigger = BaseDialog.Trigger
|
||||
export const DialogTitle = BaseDialog.Title
|
||||
export const DialogDescription = BaseDialog.Description
|
||||
export const DialogClose = BaseDialog.Close
|
||||
|
||||
type DialogContentProps = {
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
overlayClassName?: string
|
||||
}
|
||||
|
||||
export function DialogContent({
|
||||
children,
|
||||
className,
|
||||
overlayClassName,
|
||||
}: DialogContentProps) {
|
||||
return (
|
||||
<BaseDialog.Portal>
|
||||
<BaseDialog.Backdrop
|
||||
className={cn(
|
||||
'fixed inset-0 z-modal bg-background-overlay',
|
||||
'transition-opacity duration-150 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',
|
||||
overlayClassName,
|
||||
)}
|
||||
/>
|
||||
<BaseDialog.Popup
|
||||
className={cn(
|
||||
'fixed left-1/2 top-1/2 z-modal max-h-[80dvh] w-[480px] max-w-[calc(100vw-2rem)] -translate-x-1/2 -translate-y-1/2 rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg p-6 shadow-xl',
|
||||
'transition-all duration-150 data-[ending-style]:scale-95 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</BaseDialog.Popup>
|
||||
</BaseDialog.Portal>
|
||||
)
|
||||
}
|
||||
100
web/app/components/base/ui/dropdown-menu/index.tsx
Normal file
100
web/app/components/base/ui/dropdown-menu/index.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
'use client'
|
||||
|
||||
import type { Placement } from '@floating-ui/react'
|
||||
import { Menu } from '@base-ui/react/menu'
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
function parsePlacement(placement: Placement) {
|
||||
const [side, align] = placement.split('-') as [
|
||||
'top' | 'bottom' | 'left' | 'right',
|
||||
'start' | 'center' | 'end' | undefined,
|
||||
]
|
||||
return { side, align: align ?? 'center' as const }
|
||||
}
|
||||
|
||||
export const DropdownMenu = Menu.Root
|
||||
export const DropdownMenuTrigger = Menu.Trigger
|
||||
export const DropdownMenuGroup = Menu.Group
|
||||
export const DropdownMenuGroupLabel = Menu.GroupLabel
|
||||
export const DropdownMenuRadioGroup = Menu.RadioGroup
|
||||
export const DropdownMenuRadioItem = Menu.RadioItem
|
||||
export const DropdownMenuRadioItemIndicator = Menu.RadioItemIndicator
|
||||
export const DropdownMenuCheckboxItem = Menu.CheckboxItem
|
||||
export const DropdownMenuCheckboxItemIndicator = Menu.CheckboxItemIndicator
|
||||
|
||||
type DropdownMenuContentProps = {
|
||||
children: React.ReactNode
|
||||
placement?: Placement
|
||||
sideOffset?: number
|
||||
alignOffset?: number
|
||||
className?: string
|
||||
popupClassName?: string
|
||||
}
|
||||
|
||||
export function DropdownMenuContent({
|
||||
children,
|
||||
placement = 'bottom-end',
|
||||
sideOffset = 4,
|
||||
alignOffset = 0,
|
||||
className,
|
||||
popupClassName,
|
||||
}: DropdownMenuContentProps) {
|
||||
const { side, align } = parsePlacement(placement)
|
||||
|
||||
return (
|
||||
<Menu.Portal>
|
||||
<Menu.Positioner
|
||||
side={side}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
alignOffset={alignOffset}
|
||||
className={cn('z-dropdown outline-none', className)}
|
||||
>
|
||||
<Menu.Popup
|
||||
className={cn(
|
||||
'rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg py-1 text-sm text-text-secondary shadow-lg',
|
||||
'origin-[var(--transform-origin)] transition-[transform,scale,opacity] data-[ending-style]:scale-95 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',
|
||||
popupClassName,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Menu.Popup>
|
||||
</Menu.Positioner>
|
||||
</Menu.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
type DropdownMenuItemProps = React.ComponentPropsWithoutRef<typeof Menu.Item> & {
|
||||
destructive?: boolean
|
||||
}
|
||||
|
||||
export function DropdownMenuItem({
|
||||
className,
|
||||
destructive,
|
||||
...props
|
||||
}: DropdownMenuItemProps) {
|
||||
return (
|
||||
<Menu.Item
|
||||
className={cn(
|
||||
'mx-1 flex h-8 cursor-pointer select-none items-center rounded-lg px-3 outline-none',
|
||||
'data-[highlighted]:bg-components-panel-on-panel-item-bg-hover',
|
||||
destructive && 'text-text-destructive',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export function DropdownMenuSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof Menu.Separator>) {
|
||||
return (
|
||||
<Menu.Separator
|
||||
className={cn('my-1 h-px bg-divider-regular', className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
62
web/app/components/base/ui/popover/index.tsx
Normal file
62
web/app/components/base/ui/popover/index.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
'use client'
|
||||
|
||||
import type { Placement } from '@floating-ui/react'
|
||||
import { Popover as BasePopover } from '@base-ui/react/popover'
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
function parsePlacement(placement: Placement) {
|
||||
const [side, align] = placement.split('-') as [
|
||||
'top' | 'bottom' | 'left' | 'right',
|
||||
'start' | 'center' | 'end' | undefined,
|
||||
]
|
||||
return { side, align: align ?? 'center' as const }
|
||||
}
|
||||
|
||||
export const Popover = BasePopover.Root
|
||||
export const PopoverTrigger = BasePopover.Trigger
|
||||
export const PopoverClose = BasePopover.Close
|
||||
export const PopoverTitle = BasePopover.Title
|
||||
export const PopoverDescription = BasePopover.Description
|
||||
|
||||
type PopoverContentProps = {
|
||||
children: React.ReactNode
|
||||
placement?: Placement
|
||||
sideOffset?: number
|
||||
alignOffset?: number
|
||||
className?: string
|
||||
popupClassName?: string
|
||||
}
|
||||
|
||||
export function PopoverContent({
|
||||
children,
|
||||
placement = 'bottom',
|
||||
sideOffset = 8,
|
||||
alignOffset = 0,
|
||||
className,
|
||||
popupClassName,
|
||||
}: PopoverContentProps) {
|
||||
const { side, align } = parsePlacement(placement)
|
||||
|
||||
return (
|
||||
<BasePopover.Portal>
|
||||
<BasePopover.Positioner
|
||||
side={side}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
alignOffset={alignOffset}
|
||||
className={cn('z-popover outline-none', className)}
|
||||
>
|
||||
<BasePopover.Popup
|
||||
className={cn(
|
||||
'rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg',
|
||||
'origin-[var(--transform-origin)] transition-[transform,scale,opacity] data-[ending-style]:scale-95 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',
|
||||
popupClassName,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</BasePopover.Popup>
|
||||
</BasePopover.Positioner>
|
||||
</BasePopover.Portal>
|
||||
)
|
||||
}
|
||||
112
web/app/components/base/ui/select/index.tsx
Normal file
112
web/app/components/base/ui/select/index.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
'use client'
|
||||
|
||||
import type { Placement } from '@floating-ui/react'
|
||||
import { Select as BaseSelect } from '@base-ui/react/select'
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
function parsePlacement(placement: Placement) {
|
||||
const [side, align] = placement.split('-') as [
|
||||
'top' | 'bottom' | 'left' | 'right',
|
||||
'start' | 'center' | 'end' | undefined,
|
||||
]
|
||||
return { side, align: align ?? 'center' as const }
|
||||
}
|
||||
|
||||
export const Select = BaseSelect.Root
|
||||
export const SelectValue = BaseSelect.Value
|
||||
export const SelectGroup = BaseSelect.Group
|
||||
export const SelectGroupLabel = BaseSelect.GroupLabel
|
||||
export const SelectSeparator = BaseSelect.Separator
|
||||
|
||||
export function SelectTrigger({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof BaseSelect.Trigger>) {
|
||||
return (
|
||||
<BaseSelect.Trigger
|
||||
className={cn(
|
||||
'group relative flex h-8 w-full items-center rounded-lg border-0 bg-components-input-bg-normal px-2 text-left text-components-input-text-filled outline-none',
|
||||
'hover:bg-state-base-hover-alt focus-visible:bg-state-base-hover-alt disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<BaseSelect.Icon className="ml-1 shrink-0 text-text-quaternary transition-colors group-hover:text-text-secondary data-[open]:text-text-secondary">
|
||||
<span className="i-ri-arrow-down-s-line h-4 w-4" />
|
||||
</BaseSelect.Icon>
|
||||
</BaseSelect.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
type SelectContentProps = {
|
||||
children: React.ReactNode
|
||||
placement?: Placement
|
||||
sideOffset?: number
|
||||
alignOffset?: number
|
||||
className?: string
|
||||
popupClassName?: string
|
||||
listClassName?: string
|
||||
}
|
||||
|
||||
export function SelectContent({
|
||||
children,
|
||||
placement = 'bottom-start',
|
||||
sideOffset = 4,
|
||||
alignOffset = 0,
|
||||
className,
|
||||
popupClassName,
|
||||
listClassName,
|
||||
}: SelectContentProps) {
|
||||
const { side, align } = parsePlacement(placement)
|
||||
|
||||
return (
|
||||
<BaseSelect.Portal>
|
||||
<BaseSelect.Positioner
|
||||
side={side}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
alignOffset={alignOffset}
|
||||
className={cn('z-dropdown outline-none', className)}
|
||||
>
|
||||
<BaseSelect.Popup
|
||||
className={cn(
|
||||
'rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg',
|
||||
'origin-[var(--transform-origin)] transition-[transform,scale,opacity] data-[ending-style]:scale-95 data-[starting-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0',
|
||||
popupClassName,
|
||||
)}
|
||||
>
|
||||
<BaseSelect.List className={cn('max-h-80 min-w-[10rem] overflow-auto p-1 outline-none', listClassName)}>
|
||||
{children}
|
||||
</BaseSelect.List>
|
||||
</BaseSelect.Popup>
|
||||
</BaseSelect.Positioner>
|
||||
</BaseSelect.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof BaseSelect.Item>) {
|
||||
return (
|
||||
<BaseSelect.Item
|
||||
className={cn(
|
||||
'flex h-8 cursor-pointer items-center rounded-lg px-2 text-text-secondary outline-none system-sm-medium',
|
||||
'data-[disabled]:cursor-not-allowed data-[highlighted]:bg-state-base-hover data-[disabled]:opacity-50',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<BaseSelect.ItemText className="mr-1 grow truncate px-1">
|
||||
{children}
|
||||
</BaseSelect.ItemText>
|
||||
<BaseSelect.ItemIndicator className="flex shrink-0 items-center text-text-accent">
|
||||
<span className="i-ri-check-line h-4 w-4" />
|
||||
</BaseSelect.ItemIndicator>
|
||||
</BaseSelect.Item>
|
||||
)
|
||||
}
|
||||
69
web/app/components/base/ui/tooltip/index.tsx
Normal file
69
web/app/components/base/ui/tooltip/index.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
|
||||
import type { Placement } from '@floating-ui/react'
|
||||
import { Tooltip as BaseTooltip } from '@base-ui/react/tooltip'
|
||||
import * as React from 'react'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
function parsePlacement(placement: Placement) {
|
||||
const [side, align] = placement.split('-') as [
|
||||
'top' | 'bottom' | 'left' | 'right',
|
||||
'start' | 'center' | 'end' | undefined,
|
||||
]
|
||||
return { side, align: align ?? 'center' as const }
|
||||
}
|
||||
|
||||
export type TooltipProps = {
|
||||
position?: Placement
|
||||
disabled?: boolean
|
||||
popupContent?: React.ReactNode
|
||||
children?: React.ReactNode
|
||||
popupClassName?: string
|
||||
noDecoration?: boolean
|
||||
offset?: number
|
||||
}
|
||||
|
||||
const Tooltip = React.memo(({
|
||||
position = 'top',
|
||||
disabled = false,
|
||||
popupContent,
|
||||
children,
|
||||
popupClassName,
|
||||
noDecoration,
|
||||
offset = 8,
|
||||
}: TooltipProps) => {
|
||||
const { side, align } = parsePlacement(position)
|
||||
|
||||
if (!popupContent || disabled)
|
||||
return <>{children}</>
|
||||
|
||||
return (
|
||||
<BaseTooltip.Root>
|
||||
{React.isValidElement(children)
|
||||
? <BaseTooltip.Trigger render={children} />
|
||||
: <BaseTooltip.Trigger render={<span className="inline-flex" />}>{children}</BaseTooltip.Trigger>}
|
||||
<BaseTooltip.Portal>
|
||||
<BaseTooltip.Positioner
|
||||
side={side}
|
||||
align={align}
|
||||
sideOffset={offset}
|
||||
className="z-tooltip outline-none"
|
||||
>
|
||||
<BaseTooltip.Popup
|
||||
className={cn(
|
||||
!noDecoration && 'max-w-[300px] break-words rounded-md bg-components-panel-bg px-3 py-2 text-left text-text-tertiary shadow-lg system-xs-regular',
|
||||
popupClassName,
|
||||
)}
|
||||
>
|
||||
{popupContent}
|
||||
</BaseTooltip.Popup>
|
||||
</BaseTooltip.Positioner>
|
||||
</BaseTooltip.Portal>
|
||||
</BaseTooltip.Root>
|
||||
)
|
||||
})
|
||||
|
||||
Tooltip.displayName = 'Tooltip'
|
||||
|
||||
export const TooltipProvider = BaseTooltip.Provider
|
||||
export default Tooltip
|
||||
@ -9,6 +9,7 @@ import { getDatasetMap } from '@/env'
|
||||
import { getLocaleOnServer } from '@/i18n-config/server'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import { ToastProvider } from './components/base/toast'
|
||||
import { TooltipProvider } from './components/base/ui/tooltip'
|
||||
import BrowserInitializer from './components/browser-initializer'
|
||||
import { ReactScanLoader } from './components/devtools/react-scan/loader'
|
||||
import { I18nServerProvider } from './components/provider/i18n-server'
|
||||
@ -78,7 +79,9 @@ const LocaleLayout = async ({
|
||||
<I18nServerProvider>
|
||||
<ToastProvider>
|
||||
<GlobalPublicStoreProvider>
|
||||
{children}
|
||||
<TooltipProvider delay={300} closeDelay={200}>
|
||||
{children}
|
||||
</TooltipProvider>
|
||||
</GlobalPublicStoreProvider>
|
||||
</ToastProvider>
|
||||
</I18nServerProvider>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -145,4 +145,34 @@ export default antfu(
|
||||
'hyoban/no-dependency-version-prefix': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dify/base-ui-primitives',
|
||||
files: ['app/components/base/ui/**/*.ts', 'app/components/base/ui/**/*.tsx'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dify/overlay-migration',
|
||||
files: [GLOB_TS, GLOB_TSX],
|
||||
ignores: [
|
||||
'app/components/base/**',
|
||||
...GLOB_TESTS,
|
||||
],
|
||||
rules: {
|
||||
'no-restricted-imports': ['error', {
|
||||
paths: [{
|
||||
name: '@/app/components/base/portal-to-follow-elem',
|
||||
message: 'Deprecated: use semantic overlay primitives from @/app/components/base/ui/ instead. See issue #32767.',
|
||||
}],
|
||||
patterns: [{
|
||||
group: [
|
||||
'**/portal-to-follow-elem',
|
||||
'**/portal-to-follow-elem/index',
|
||||
],
|
||||
message: 'Deprecated: use semantic overlay primitives from @/app/components/base/ui/ instead. See issue #32767.',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
@ -63,6 +63,7 @@
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "2.33.1",
|
||||
"@amplitude/plugin-session-replay-browser": "1.23.6",
|
||||
"@base-ui/react": "1.2.0",
|
||||
"@emoji-mart/data": "1.2.1",
|
||||
"@floating-ui/react": "0.26.28",
|
||||
"@formatjs/intl-localematcher": "0.5.10",
|
||||
|
||||
53
web/pnpm-lock.yaml
generated
53
web/pnpm-lock.yaml
generated
@ -60,6 +60,9 @@ importers:
|
||||
'@amplitude/plugin-session-replay-browser':
|
||||
specifier: 1.23.6
|
||||
version: 1.23.6(@amplitude/rrweb@2.0.0-alpha.35)(rollup@4.56.0)
|
||||
'@base-ui/react':
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0(@types/react@19.2.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@emoji-mart/data':
|
||||
specifier: 1.2.1
|
||||
version: 1.2.1
|
||||
@ -900,6 +903,27 @@ packages:
|
||||
resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@base-ui/react@1.2.0':
|
||||
resolution: {integrity: sha512-O6aEQHcm+QyGTFY28xuwRD3SEJGZOBDpyjN2WvpfWYFVhg+3zfXPysAILqtM0C1kWC82MccOE/v1j+GHXE4qIw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
react: ^17 || ^18 || ^19
|
||||
react-dom: ^17 || ^18 || ^19
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@base-ui/utils@0.2.5':
|
||||
resolution: {integrity: sha512-oYC7w0gp76RI5MxprlGLV0wze0SErZaRl3AAkeP3OnNB/UBMb6RqNf6ZSIlxOc9Qp68Ab3C2VOcJQyRs7Xc7Vw==}
|
||||
peerDependencies:
|
||||
'@types/react': ^17 || ^18 || ^19
|
||||
react: ^17 || ^18 || ^19
|
||||
react-dom: ^17 || ^18 || ^19
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2':
|
||||
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
|
||||
engines: {node: '>=18'}
|
||||
@ -6838,6 +6862,9 @@ packages:
|
||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
reselect@5.1.1:
|
||||
resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
|
||||
|
||||
reserved-identifiers@1.2.0:
|
||||
resolution: {integrity: sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -8336,6 +8363,30 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
||||
'@base-ui/react@1.2.0(@types/react@19.2.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.6
|
||||
'@base-ui/utils': 0.2.5(@types/react@19.2.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@floating-ui/react-dom': 2.1.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@floating-ui/utils': 0.2.10
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
tabbable: 6.4.0
|
||||
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.9
|
||||
|
||||
'@base-ui/utils@0.2.5(@types/react@19.2.9)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.6
|
||||
'@floating-ui/utils': 0.2.10
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
reselect: 5.1.1
|
||||
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.9
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@braintree/sanitize-url@7.1.1': {}
|
||||
@ -15158,6 +15209,8 @@ snapshots:
|
||||
|
||||
require-from-string@2.0.2: {}
|
||||
|
||||
reselect@5.1.1: {}
|
||||
|
||||
reserved-identifiers@1.2.0: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
@ -161,6 +161,13 @@ const config = {
|
||||
'progress-bar-indeterminate-stripe': 'var(--color-progress-bar-indeterminate-stripe)',
|
||||
'chat-answer-human-input-form-divider-bg': 'var(--color-chat-answer-human-input-form-divider-bg)',
|
||||
},
|
||||
zIndex: {
|
||||
dropdown: '1000',
|
||||
popover: '1100',
|
||||
modal: '1200',
|
||||
toast: '1300',
|
||||
tooltip: '1400',
|
||||
},
|
||||
animation: {
|
||||
'spin-slow': 'spin 2s linear infinite',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user