diff --git a/packages/dify-ui/src/combobox/index.stories.tsx b/packages/dify-ui/src/combobox/index.stories.tsx index 69e06ab3b13..7b93bff4fe8 100644 --- a/packages/dify-ui/src/combobox/index.stories.tsx +++ b/packages/dify-ui/src/combobox/index.stories.tsx @@ -403,7 +403,7 @@ const VirtualizedModelList = ({ }, [virtualizer, virtualizerRef]) return ( - + { { title="Release notes" description="Highlights from the latest workspace update." /> - + diff --git a/packages/dify-ui/src/drawer/index.stories.tsx b/packages/dify-ui/src/drawer/index.stories.tsx index 8ddcc1ddf16..f485c987f0e 100644 --- a/packages/dify-ui/src/drawer/index.stories.tsx +++ b/packages/dify-ui/src/drawer/index.stories.tsx @@ -728,7 +728,7 @@ export const MobileNavigation: Story = { className="h-full transition-transform duration-600 ease-[cubic-bezier(0.45,1.005,0,1.005)] group-data-ending-style:pointer-events-none group-data-starting-style:translate-y-[100dvh] motion-reduce:transition-none" > diff --git a/packages/dify-ui/src/scroll-area/__tests__/index.spec.tsx b/packages/dify-ui/src/scroll-area/__tests__/index.spec.tsx index 0e351c13437..4d2c84371a4 100644 --- a/packages/dify-ui/src/scroll-area/__tests__/index.spec.tsx +++ b/packages/dify-ui/src/scroll-area/__tests__/index.spec.tsx @@ -86,6 +86,12 @@ describe('scroll area', () => { await expect.element(screen.getByTestId('scroll-area-root')).toBeInTheDocument() await expect.element(screen.getByTestId('scroll-area-viewport')).toBeInTheDocument() + await expect + .element(screen.getByTestId('scroll-area-root')) + .toHaveAttribute('data-dify-scroll-area') + await expect + .element(screen.getByTestId('scroll-area-viewport')) + .toHaveAttribute('data-dify-scroll-area-viewport') await expect .element(screen.getByTestId('scroll-area-content')) .toHaveTextContent('Scrollable content') @@ -192,7 +198,7 @@ describe('scroll area', () => { .toHaveAttribute('data-orientation', 'vertical') await expect .element(screen.getByTestId('scroll-area-vertical-scrollbar')) - .toHaveAttribute('data-dify-scrollbar') + .toHaveAttribute('data-dify-scroll-area-scrollbar') await expect .element(screen.getByTestId('scroll-area-vertical-thumb')) .toHaveAttribute('data-orientation', 'vertical') @@ -206,7 +212,7 @@ describe('scroll area', () => { .toHaveAttribute('data-orientation', 'horizontal') await expect .element(screen.getByTestId('scroll-area-horizontal-scrollbar')) - .toHaveAttribute('data-dify-scrollbar') + .toHaveAttribute('data-dify-scroll-area-scrollbar') await expect .element(screen.getByTestId('scroll-area-horizontal-thumb')) .toHaveAttribute('data-orientation', 'horizontal') diff --git a/packages/dify-ui/src/scroll-area/index.stories.tsx b/packages/dify-ui/src/scroll-area/index.stories.tsx index 18a12ea8122..d4531cd4f5f 100644 --- a/packages/dify-ui/src/scroll-area/index.stories.tsx +++ b/packages/dify-ui/src/scroll-area/index.stories.tsx @@ -18,7 +18,7 @@ const meta = { docs: { description: { component: - 'Compound scroll container built on Base UI Scroll Area. ScrollArea is the structural root; ScrollAreaViewport is the actual scroll and focus owner, so place scroll refs, events, role, accessible-name attributes, and overscroll behavior on the viewport. Add role="region" only when the content is important enough to be a landmark, preferring aria-labelledby when a visible heading exists. Base UI sets Viewport overflow and Content min-width inline: use style={{ overflowX: "hidden" }} for an axis override and style={{ minWidth: 0 }} for vertical content that should truncate; regular overflow-x-hidden and min-w-0 utilities cannot override those inline defaults. This is a targeted override contract for those Base UI defaults, not a general preference for inline styles over className.', + 'Compound scroll container built on Base UI Scroll Area. ScrollAreaViewport is the actual scroll and focus owner, while ScrollArea reflects its focus-visible state as a root-owned overlay border above the isolated viewport contents. Place scroll refs, events, role, accessible-name attributes, and overscroll behavior on the viewport. Add role="region" only when the content is important enough to be a landmark, preferring aria-labelledby when a visible heading exists. Base UI sets Viewport overflow and Content min-width inline: use style={{ overflowX: "hidden" }} for an axis override and style={{ minWidth: 0 }} for vertical content that should truncate; regular overflow-x-hidden and min-w-0 utilities cannot override those inline defaults. This is a targeted override contract for those Base UI defaults, not a general preference for inline styles over className.', }, }, }, @@ -109,11 +109,11 @@ export const Anatomy: Story = { titleId="scroll-area-anatomy-title" description="The baseline story uses ScrollArea as the structural root, with Viewport, Content, Scrollbar, and Thumb composed explicitly. Keyboard focus and accessible naming belong to the viewport." > - + {articleParagraphs.map((paragraph) => ( @@ -134,13 +134,13 @@ export const Vertical: Story = { - +
@@ -169,11 +169,11 @@ export const VerticalTruncation: Story = { title="Constrained content width" description="Pass style={{ minWidth: 0 }} to ScrollAreaContent when a vertical-only list should truncate long labels instead of creating horizontal scroll. A regular min-w-0 utility cannot override Base UI's inline fit-content default." > - + {fileRows.map((file) => ( @@ -202,19 +202,14 @@ export const ScrollFade: Story = { - _:first-child:focus-visible]:outline-2 has-[>_:first-child:focus-visible]:outline-offset-0 has-[>_:first-child:focus-visible]:outline-state-accent-solid', - )} - > + @@ -239,14 +234,14 @@ export const Horizontal: Story = { - +
@@ -276,11 +271,11 @@ export const BothAxes: Story = { title="Numbered grid" description="This follows the official two-axis example: both scrollbars are rendered and Corner reserves the intersection." > - +
diff --git a/packages/dify-ui/src/scroll-area/index.tsx b/packages/dify-ui/src/scroll-area/index.tsx index be5a124acc8..934e4e0f890 100644 --- a/packages/dify-ui/src/scroll-area/index.tsx +++ b/packages/dify-ui/src/scroll-area/index.tsx @@ -3,8 +3,15 @@ import { ScrollArea as BaseScrollArea } from '@base-ui/react/scroll-area' import { cn } from '../cn' -const ScrollArea = BaseScrollArea.Root -type ScrollAreaProps = BaseScrollArea.Root.Props +type ScrollAreaProps = Omit & { + className?: string +} + +function ScrollArea({ className, ...props }: ScrollAreaProps) { + return ( + + ) +} const ScrollAreaContent = BaseScrollArea.Content type ScrollAreaContentProps = BaseScrollArea.Content.Props @@ -26,20 +33,17 @@ const scrollAreaThumbClassName = cn( 'active:bg-state-base-handle-hover', ) -const scrollAreaViewportClassName = cn( - 'size-full min-h-0 min-w-0', - 'focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-state-accent-solid focus-visible:outline-solid', -) - -const scrollAreaCornerClassName = 'bg-transparent' - type ScrollAreaViewportProps = Omit & { className?: string } function ScrollAreaViewport({ className, ...props }: ScrollAreaViewportProps) { return ( - + ) } @@ -50,9 +54,9 @@ type ScrollAreaScrollbarProps = Omit ) } @@ -70,7 +74,7 @@ type ScrollAreaCornerProps = Omit & { } function ScrollAreaCorner({ className, ...props }: ScrollAreaCornerProps) { - return + return } export { diff --git a/packages/dify-ui/src/styles/components.css b/packages/dify-ui/src/styles/components.css index ab02be97fbb..06547b66320 100644 --- a/packages/dify-ui/src/styles/components.css +++ b/packages/dify-ui/src/styles/components.css @@ -1,5 +1,20 @@ -[data-dify-scrollbar]::before, -[data-dify-scrollbar]::after { +[data-dify-scroll-area]::after { + content: ''; + position: absolute; + inset: 0; + z-index: 1; + border: 0 solid transparent; + border-radius: inherit; + pointer-events: none; +} + +[data-dify-scroll-area]:has(> [data-dify-scroll-area-viewport]:focus-visible)::after { + border-width: 2px; + border-color: var(--color-state-accent-solid); +} + +[data-dify-scroll-area-scrollbar]::before, +[data-dify-scroll-area-scrollbar]::after { content: ''; position: absolute; z-index: 1; @@ -9,7 +24,7 @@ transition: opacity 150ms ease; } -[data-dify-scrollbar][data-orientation='vertical']::before { +[data-dify-scroll-area-scrollbar][data-orientation='vertical']::before { left: 50%; top: 4px; width: 4px; @@ -18,7 +33,7 @@ background: linear-gradient(to bottom, var(--color-components-panel-bg), transparent); } -[data-dify-scrollbar][data-orientation='vertical']::after { +[data-dify-scroll-area-scrollbar][data-orientation='vertical']::after { left: 50%; bottom: 4px; width: 4px; @@ -27,7 +42,7 @@ background: linear-gradient(to top, var(--color-components-panel-bg), transparent); } -[data-dify-scrollbar][data-orientation='horizontal']::before { +[data-dify-scroll-area-scrollbar][data-orientation='horizontal']::before { top: 50%; left: 4px; width: 12px; @@ -36,7 +51,7 @@ background: linear-gradient(to right, var(--color-components-panel-bg), transparent); } -[data-dify-scrollbar][data-orientation='horizontal']::after { +[data-dify-scroll-area-scrollbar][data-orientation='horizontal']::after { top: 50%; right: 4px; width: 12px; @@ -45,25 +60,29 @@ background: linear-gradient(to left, var(--color-components-panel-bg), transparent); } -[data-dify-scrollbar][data-orientation='vertical']:not([data-overflow-y-start])::before { +[data-dify-scroll-area-scrollbar][data-orientation='vertical']:not( + [data-overflow-y-start] + )::before { opacity: 1; } -[data-dify-scrollbar][data-orientation='vertical']:not([data-overflow-y-end])::after { +[data-dify-scroll-area-scrollbar][data-orientation='vertical']:not([data-overflow-y-end])::after { opacity: 1; } -[data-dify-scrollbar][data-orientation='horizontal']:not([data-overflow-x-start])::before { +[data-dify-scroll-area-scrollbar][data-orientation='horizontal']:not( + [data-overflow-x-start] + )::before { opacity: 1; } -[data-dify-scrollbar][data-orientation='horizontal']:not([data-overflow-x-end])::after { +[data-dify-scroll-area-scrollbar][data-orientation='horizontal']:not([data-overflow-x-end])::after { opacity: 1; } @media (prefers-reduced-motion: reduce) { - [data-dify-scrollbar]::before, - [data-dify-scrollbar]::after { + [data-dify-scroll-area-scrollbar]::before, + [data-dify-scroll-area-scrollbar]::after { transition: none; } } diff --git a/web/app/components/app/app-access-control/add-member-or-group-pop/index.tsx b/web/app/components/app/app-access-control/add-member-or-group-pop/index.tsx index 4b0c3dae2ed..12451b890aa 100644 --- a/web/app/components/app/app-access-control/add-member-or-group-pop/index.tsx +++ b/web/app/components/app/app-access-control/add-member-or-group-pop/index.tsx @@ -140,7 +140,7 @@ export default function AddMemberOrGroupDialog({ className="relative flex max-h-[400px] w-[400px] flex-col overflow-hidden bg-components-panel-bg-blur p-0 backdrop-blur-[5px]" > {searchLabel} - + = ({
)} {/* form body */} - - - + + + {/* name & icon */}
diff --git a/web/app/components/apps/list.tsx b/web/app/components/apps/list.tsx index 781c428987e..c09ad1de941 100644 --- a/web/app/components/apps/list.tsx +++ b/web/app/components/apps/list.tsx @@ -160,7 +160,7 @@ export function List({ onCreateLearnDify, onTryLearnDify }: Props) { style={{ overflowX: 'hidden' }} > = {} -vi.mock('../header', () => ({ - default: ({ onClose }: { onClose: () => void }) => ( - - ), -})) - vi.mock('../plan-switcher', () => ({ default: () =>
plan-switcher
, })) @@ -76,7 +68,7 @@ describe('Pricing dialog lifecycle', () => { const { wrapper } = createConsoleQueryWrapper() render(, { wrapper }) - await user.click(screen.getByRole('button', { name: 'close' })) + await user.click(screen.getByRole('button', { name: 'common.operation.close' })) expect(onCancel).toHaveBeenCalledTimes(1) }) diff --git a/web/app/components/billing/pricing/header.tsx b/web/app/components/billing/pricing/header.tsx index cc8b29aceb0..64db8687753 100644 --- a/web/app/components/billing/pricing/header.tsx +++ b/web/app/components/billing/pricing/header.tsx @@ -1,16 +1,11 @@ import { cn } from '@langgenius/dify-ui/cn' import { DialogDescription, DialogTitle } from '@langgenius/dify-ui/dialog' -import { IconButton } from '@langgenius/dify-ui/icon-button' import * as React from 'react' import { useTranslation } from 'react-i18next' import { DifyLogo } from '../../base/logo/dify-logo' import styles from './header.module.css' -type HeaderProps = { - onClose: () => void -} - -const Header = ({ onClose }: HeaderProps) => { +const Header = () => { const { t } = useTranslation() return ( @@ -32,15 +27,6 @@ const Header = ({ onClose }: HeaderProps) => { {t(($) => $['plansCommon.title.description'], { ns: 'billing' })} - $['operation.close'], { ns: 'common' })} - onClick={onClose} - > -
) diff --git a/web/app/components/billing/pricing/index.tsx b/web/app/components/billing/pricing/index.tsx index 096df9d69c1..450e07e3482 100644 --- a/web/app/components/billing/pricing/index.tsx +++ b/web/app/components/billing/pricing/index.tsx @@ -1,7 +1,8 @@ 'use client' import type { FC } from 'react' import type { Category } from './types' -import { Dialog, DialogContent } from '@langgenius/dify-ui/dialog' +import { Dialog, DialogClose, DialogContent } from '@langgenius/dify-ui/dialog' +import { IconButton } from '@langgenius/dify-ui/icon-button' import { ScrollArea, ScrollAreaContent, @@ -14,6 +15,7 @@ import { useQuery } from '@tanstack/react-query' import { useAtomValue } from 'jotai' import * as React from 'react' import { useState } from 'react' +import { useTranslation } from 'react-i18next' import { useGetPricingPageLanguage } from '@/context/i18n' import { useProviderContext } from '@/context/provider-context' import { isCurrentWorkspaceManagerAtom } from '@/context/workspace-state' @@ -31,6 +33,7 @@ type PricingProps = { } const Pricing: FC = ({ onCancel }) => { + const { t } = useTranslation() const { plan, enableEducationPlan } = useProviderContext() const { data: isEducationAccount = false } = useQuery( consoleQuery.account.education.get.queryOptions({ @@ -59,14 +62,26 @@ const Pricing: FC = ({ onCancel }) => { }} > - + $['operation.close'], { ns: 'common' })} + > +
- + $['agentDetail.logs.title'])} role="region" diff --git a/web/features/agent-v2/roster/page.tsx b/web/features/agent-v2/roster/page.tsx index 2f843cce0f4..57ab5fd8ce3 100644 --- a/web/features/agent-v2/roster/page.tsx +++ b/web/features/agent-v2/roster/page.tsx @@ -108,7 +108,7 @@ export default function RosterPage() {
- +
- +
- +