diff --git a/web/app/components/base/portal-to-follow-elem/index.tsx b/web/app/components/base/portal-to-follow-elem/index.tsx
index c57fba9dd0..7d4f6baa9b 100644
--- a/web/app/components/base/portal-to-follow-elem/index.tsx
+++ b/web/app/components/base/portal-to-follow-elem/index.tsx
@@ -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,
diff --git a/web/app/components/base/ui/dialog/index.tsx b/web/app/components/base/ui/dialog/index.tsx
new file mode 100644
index 0000000000..07d1e1f649
--- /dev/null
+++ b/web/app/components/base/ui/dialog/index.tsx
@@ -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 (
+
+
+
+ {children}
+
+
+ )
+}
diff --git a/web/app/components/base/ui/dropdown-menu/index.tsx b/web/app/components/base/ui/dropdown-menu/index.tsx
new file mode 100644
index 0000000000..57519f84fd
--- /dev/null
+++ b/web/app/components/base/ui/dropdown-menu/index.tsx
@@ -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 (
+
+
+
+ {children}
+
+
+
+ )
+}
+
+type DropdownMenuItemProps = React.ComponentPropsWithoutRef & {
+ destructive?: boolean
+}
+
+export function DropdownMenuItem({
+ className,
+ destructive,
+ ...props
+}: DropdownMenuItemProps) {
+ return (
+
+ )
+}
+
+export function DropdownMenuSeparator({
+ className,
+ ...props
+}: React.ComponentPropsWithoutRef) {
+ return (
+
+ )
+}
diff --git a/web/app/components/base/ui/popover/index.tsx b/web/app/components/base/ui/popover/index.tsx
new file mode 100644
index 0000000000..1569a63c7a
--- /dev/null
+++ b/web/app/components/base/ui/popover/index.tsx
@@ -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 (
+
+
+
+ {children}
+
+
+
+ )
+}
diff --git a/web/app/components/base/ui/select/index.tsx b/web/app/components/base/ui/select/index.tsx
new file mode 100644
index 0000000000..f240e5729b
--- /dev/null
+++ b/web/app/components/base/ui/select/index.tsx
@@ -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) {
+ return (
+
+ {children}
+
+
+
+
+ )
+}
+
+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 (
+
+
+
+
+ {children}
+
+
+
+
+ )
+}
+
+export function SelectItem({
+ className,
+ children,
+ ...props
+}: React.ComponentPropsWithoutRef) {
+ return (
+
+
+ {children}
+
+
+
+
+
+ )
+}
diff --git a/web/app/components/base/ui/tooltip/index.tsx b/web/app/components/base/ui/tooltip/index.tsx
new file mode 100644
index 0000000000..ff277892a5
--- /dev/null
+++ b/web/app/components/base/ui/tooltip/index.tsx
@@ -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 (
+
+ {React.isValidElement(children)
+ ?
+ : }>{children}}
+
+
+
+ {popupContent}
+
+
+
+
+ )
+})
+
+Tooltip.displayName = 'Tooltip'
+
+export const TooltipProvider = BaseTooltip.Provider
+export default Tooltip
diff --git a/web/app/layout.tsx b/web/app/layout.tsx
index 64f0e5ac3b..367aa120b8 100644
--- a/web/app/layout.tsx
+++ b/web/app/layout.tsx
@@ -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 ({
- {children}
+
+ {children}
+
diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json
index 3282630fef..1c94fedf07 100644
--- a/web/eslint-suppressions.json
+++ b/web/eslint-suppressions.json
@@ -102,6 +102,11 @@
"count": 3
}
},
+ "app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-button.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/config-popup.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 6
@@ -113,6 +118,9 @@
}
},
"app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -286,6 +294,9 @@
}
},
"app/components/app-sidebar/app-operations.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 4
},
@@ -294,6 +305,9 @@
}
},
"app/components/app-sidebar/app-sidebar-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -304,6 +318,9 @@
}
},
"app/components/app-sidebar/dataset-info/dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -319,6 +336,9 @@
}
},
"app/components/app-sidebar/dataset-sidebar-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -480,6 +500,9 @@
}
},
"app/components/app/app-access-control/add-member-or-group-pop.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 8
}
@@ -500,10 +523,18 @@
}
},
"app/components/app/app-publisher/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 5
}
},
+ "app/components/app/app-publisher/publish-with-multiple-model.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/app/app-publisher/suggested-action.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -565,6 +596,11 @@
"count": 6
}
},
+ "app/components/app/configuration/config-var/config-modal/type-select.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/app/configuration/config-var/config-select/index.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -587,6 +623,9 @@
}
},
"app/components/app/configuration/config-var/select-var-type.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -617,6 +656,11 @@
"count": 1
}
},
+ "app/components/app/configuration/config-vision/param-config.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/app/configuration/config/agent-setting-button.spec.tsx": {
"ts/no-explicit-any": {
"count": 2
@@ -671,6 +715,9 @@
}
},
"app/components/app/configuration/config/assistant-type-picker/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 3
},
@@ -716,6 +763,9 @@
}
},
"app/components/app/configuration/config/automatic/version-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -778,6 +828,9 @@
}
},
"app/components/app/configuration/dataset-config/context-var/var-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 4
}
@@ -1039,6 +1092,9 @@
}
},
"app/components/app/log/model-info.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
},
@@ -1159,6 +1215,9 @@
}
},
"app/components/app/type-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -1856,11 +1915,6 @@
"count": 4
}
},
- "app/components/base/file-uploader/utils.spec.ts": {
- "ts/no-explicit-any": {
- "count": 2
- }
- },
"app/components/base/file-uploader/utils.ts": {
"ts/no-explicit-any": {
"count": 3
@@ -2033,11 +2087,6 @@
"count": 1
}
},
- "app/components/base/input/index.spec.tsx": {
- "ts/no-explicit-any": {
- "count": 1
- }
- },
"app/components/base/input/index.stories.tsx": {
"no-console": {
"count": 2
@@ -2618,11 +2667,6 @@
"count": 4
}
},
- "app/components/base/with-input-validation/index.spec.tsx": {
- "ts/no-explicit-any": {
- "count": 2
- }
- },
"app/components/base/with-input-validation/index.stories.tsx": {
"no-console": {
"count": 1
@@ -2755,11 +2799,17 @@
}
},
"app/components/datasets/common/document-picker/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/datasets/common/document-picker/preview-document-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -3075,6 +3125,11 @@
"count": 1
}
},
+ "app/components/datasets/documents/create-from-pipeline/data-source/base/credential-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/datasets/documents/create-from-pipeline/data-source/base/credential-selector/item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -3121,6 +3176,9 @@
}
},
"app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/dropdown/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -3450,6 +3508,9 @@
}
},
"app/components/datasets/external-api/external-api-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -3509,6 +3570,9 @@
}
},
"app/components/datasets/extra-info/api-access/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -3519,6 +3583,9 @@
}
},
"app/components/datasets/extra-info/service-api/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -3655,6 +3722,9 @@
}
},
"app/components/datasets/metadata/metadata-dataset/create-metadata-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -3672,6 +3742,11 @@
"count": 1
}
},
+ "app/components/datasets/metadata/metadata-dataset/select-metadata-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 1
+ }
+ },
"app/components/datasets/metadata/metadata-dataset/select-metadata.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -3718,6 +3793,11 @@
"count": 7
}
},
+ "app/components/datasets/settings/index-method/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/datasets/settings/index-method/keyword-number.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -3729,6 +3809,9 @@
}
},
"app/components/datasets/settings/permission-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react/no-missing-key": {
"count": 1
},
@@ -3802,6 +3885,9 @@
}
},
"app/components/explore/item-operation/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
}
@@ -3903,6 +3989,11 @@
"count": 2
}
},
+ "app/components/header/account-setting/api-based-extension-page/selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/header/account-setting/data-source-page-new/card.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 4
@@ -3912,6 +4003,9 @@
}
},
"app/components/header/account-setting/data-source-page-new/configure.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -3953,16 +4047,25 @@
}
},
"app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -4000,7 +4103,15 @@
"count": 3
}
},
+ "app/components/header/account-setting/members-page/invite-modal/role-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/header/account-setting/members-page/operation/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 5
}
@@ -4016,6 +4127,9 @@
}
},
"app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 2
}
@@ -4052,6 +4166,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-auth/add-custom-model.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -4067,6 +4184,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-auth/authorized/index.tsx": {
+ "no-restricted-imports": {
+ "count": 4
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -4080,6 +4200,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -4118,6 +4241,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
},
@@ -4144,6 +4270,9 @@
}
},
"app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -4179,6 +4308,11 @@
"count": 1
}
},
+ "app/components/header/account-setting/model-provider-page/model-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -4243,6 +4377,11 @@
"count": 1
}
},
+ "app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/header/account-setting/plugin-page/utils.ts": {
"ts/no-explicit-any": {
"count": 4
@@ -4450,6 +4589,9 @@
}
},
"app/components/plugins/marketplace/search-box/tags-filter.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -4465,6 +4607,9 @@
}
},
"app/components/plugins/marketplace/sort-dropdown/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -4498,6 +4643,9 @@
}
},
"app/components/plugins/plugin-auth/authorized/index.tsx": {
+ "no-restricted-imports": {
+ "count": 4
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -4565,6 +4713,9 @@
}
},
"app/components/plugins/plugin-detail-panel/app-selector/app-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -4575,6 +4726,9 @@
}
},
"app/components/plugins/plugin-detail-panel/app-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -4625,6 +4779,9 @@
}
},
"app/components/plugins/plugin-detail-panel/model-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
@@ -4654,6 +4811,9 @@
}
},
"app/components/plugins/plugin-detail-panel/operation-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -4713,6 +4873,9 @@
}
},
"app/components/plugins/plugin-detail-panel/subscription-list/selector-entry.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -4753,6 +4916,9 @@
}
},
"app/components/plugins/plugin-detail-panel/tool-selector/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -4805,16 +4971,25 @@
}
},
"app/components/plugins/plugin-page/filter-management/category-filter.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
},
"app/components/plugins/plugin-page/filter-management/tag-filter.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
},
"app/components/plugins/plugin-page/install-plugin-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -4827,6 +5002,11 @@
"count": 2
}
},
+ "app/components/plugins/plugin-page/plugin-tasks/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/plugins/provider-card.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -4858,6 +5038,9 @@
}
},
"app/components/plugins/reference-setting-modal/auto-update-setting/strategy-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -4870,6 +5053,11 @@
"count": 1
}
},
+ "app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/plugins/reference-setting-modal/index.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -4896,6 +5084,9 @@
}
},
"app/components/plugins/update-plugin/plugin-version-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -5054,6 +5245,11 @@
"count": 1
}
},
+ "app/components/rag-pipeline/components/rag-pipeline-header/publisher/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/rag-pipeline/components/rag-pipeline-header/publisher/popup.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 8
@@ -5139,6 +5335,9 @@
}
},
"app/components/share/text-generation/menu-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -5238,11 +5437,17 @@
}
},
"app/components/tools/labels/filter.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
},
"app/components/tools/labels/selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -5269,6 +5474,9 @@
}
},
"app/components/tools/mcp/detail/operation-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -5382,6 +5590,9 @@
}
},
"app/components/tools/workflow-tool/method-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -5510,7 +5721,15 @@
"count": 1
}
},
+ "app/components/workflow/block-selector/main.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/block-selector/market-place-plugin/action.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
@@ -5554,6 +5773,11 @@
"count": 1
}
},
+ "app/components/workflow/block-selector/tool-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/block-selector/tool/action-item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -5624,6 +5848,11 @@
"count": 6
}
},
+ "app/components/workflow/header/checklist.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/header/editing-title.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -5656,6 +5885,9 @@
}
},
"app/components/workflow/header/test-run-menu.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-refresh/only-export-components": {
"count": 1
},
@@ -5673,7 +5905,15 @@
"count": 1
}
},
+ "app/components/workflow/header/view-history.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/header/view-workflow-history.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 1
}
@@ -5767,6 +6007,9 @@
}
},
"app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"ts/no-explicit-any": {
"count": 4
}
@@ -5862,6 +6105,9 @@
}
},
"app/components/workflow/nodes/_base/components/error-handle/error-handle-type-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -5979,6 +6225,9 @@
}
},
"app/components/workflow/nodes/_base/components/next-step/operator.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -6004,6 +6253,11 @@
"count": 3
}
},
+ "app/components/workflow/nodes/_base/components/panel-operator/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/_base/components/prompt/editor.tsx": {
"tailwindcss/no-unnecessary-whitespace": {
"count": 2
@@ -6087,6 +6341,9 @@
}
},
"app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
},
@@ -6106,6 +6363,9 @@
}
},
"app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
},
@@ -6113,6 +6373,11 @@
"count": 3
}
},
+ "app/components/workflow/nodes/_base/components/variable/var-type-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/_base/components/variable/variable-label/base/variable-label.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -6248,6 +6513,9 @@
}
},
"app/components/workflow/nodes/assigner/components/operation-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
@@ -6292,6 +6560,11 @@
"count": 1
}
},
+ "app/components/workflow/nodes/code/dependency-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/code/use-config.ts": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
@@ -6433,6 +6706,9 @@
}
},
"app/components/workflow/nodes/human-input/components/button-style-dropdown.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -6453,11 +6729,17 @@
}
},
"app/components/workflow/nodes/human-input/components/delivery-method/method-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 14
}
},
"app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -6477,6 +6759,11 @@
"count": 6
}
},
+ "app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 21
@@ -6543,6 +6830,11 @@
"count": 1
}
},
+ "app/components/workflow/nodes/if-else/components/condition-add.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/if-else/components/condition-files-list-value.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -6561,7 +6853,20 @@
"count": 2
}
},
+ "app/components/workflow/nodes/if-else/components/condition-list/condition-operator.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
+ "app/components/workflow/nodes/if-else/components/condition-list/condition-var-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/if-else/components/condition-number-input.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
@@ -6618,6 +6923,9 @@
}
},
"app/components/workflow/nodes/knowledge-base/components/chunk-structure/selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -6666,11 +6974,17 @@
}
},
"app/components/workflow/nodes/knowledge-retrieval/components/metadata/add-condition.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
},
"app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 4
}
@@ -6688,7 +7002,20 @@
"count": 1
}
},
+ "app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-operator.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
+ "app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-value-method.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-variable-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -6699,6 +7026,9 @@
}
},
"app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-filter/metadata-filter-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -6709,11 +7039,17 @@
}
},
"app/components/workflow/nodes/knowledge-retrieval/components/metadata/metadata-trigger.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
},
"app/components/workflow/nodes/knowledge-retrieval/components/retrieval-config.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 2
}
@@ -6801,6 +7137,9 @@
}
},
"app/components/workflow/nodes/llm/components/json-schema-config-modal/json-importer.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
},
@@ -6817,6 +7156,9 @@
}
},
"app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 2
}
@@ -6860,6 +7202,9 @@
}
},
"app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/type-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -6910,6 +7255,11 @@
"count": 1
}
},
+ "app/components/workflow/nodes/loop/components/condition-add.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/loop/components/condition-files-list-value.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 3
@@ -6928,7 +7278,20 @@
"count": 2
}
},
+ "app/components/workflow/nodes/loop/components/condition-list/condition-operator.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
+ "app/components/workflow/nodes/loop/components/condition-list/condition-var-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/loop/components/condition-number-input.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
@@ -7233,6 +7596,11 @@
"count": 1
}
},
+ "app/components/workflow/nodes/variable-assigner/components/add-variable/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/nodes/variable-assigner/components/node-variable-item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -7268,10 +7636,23 @@
}
},
"app/components/workflow/note-node/note-editor/toolbar/color-picker.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"react-refresh/only-export-components": {
"count": 1
}
},
+ "app/components/workflow/note-node/note-editor/toolbar/font-size-selector.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
+ "app/components/workflow/note-node/note-editor/toolbar/operator.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/note-node/note-editor/utils.ts": {
"regexp/no-useless-quantifier": {
"count": 1
@@ -7288,6 +7669,9 @@
}
},
"app/components/workflow/operator/more-actions.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
}
@@ -7298,6 +7682,9 @@
}
},
"app/components/workflow/operator/zoom-in-out.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -7352,6 +7739,11 @@
"count": 6
}
},
+ "app/components/workflow/panel/chat-variable-panel/components/variable-modal-trigger.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 8
@@ -7364,6 +7756,9 @@
}
},
"app/components/workflow/panel/chat-variable-panel/components/variable-type-select.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 6
},
@@ -7420,6 +7815,11 @@
"count": 1
}
},
+ "app/components/workflow/panel/env-panel/variable-trigger.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/panel/global-variable-panel/index.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 2
@@ -7445,6 +7845,11 @@
"count": 1
}
},
+ "app/components/workflow/panel/version-history-panel/context-menu/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ }
+ },
"app/components/workflow/panel/version-history-panel/context-menu/menu-item.tsx": {
"tailwindcss/enforce-consistent-class-order": {
"count": 1
@@ -7477,6 +7882,9 @@
}
},
"app/components/workflow/panel/version-history-panel/filter/index.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/no-unnecessary-whitespace": {
"count": 1
}
@@ -7523,6 +7931,9 @@
}
},
"app/components/workflow/run/agent-log/agent-log-nav-more.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
}
@@ -7887,6 +8298,9 @@
}
},
"app/components/workflow/workflow-preview/components/zoom-in-out.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 2
}
@@ -7915,6 +8329,9 @@
}
},
"app/education-apply/search-input.tsx": {
+ "no-restricted-imports": {
+ "count": 2
+ },
"tailwindcss/enforce-consistent-class-order": {
"count": 1
},
diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs
index cf7825fc61..4372546f3c 100644
--- a/web/eslint.config.mjs
+++ b/web/eslint.config.mjs
@@ -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.',
+ }],
+ }],
+ },
+ },
)
diff --git a/web/package.json b/web/package.json
index f0d4fdd1fc..9f7c61f40e 100644
--- a/web/package.json
+++ b/web/package.json
@@ -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",
diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml
index a754e0aa7a..4f72ba60c5 100644
--- a/web/pnpm-lock.yaml
+++ b/web/pnpm-lock.yaml
@@ -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: {}
diff --git a/web/tailwind-common-config.ts b/web/tailwind-common-config.ts
index cbd58e2809..e6976c0960 100644
--- a/web/tailwind-common-config.ts
+++ b/web/tailwind-common-config.ts
@@ -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',
},