mirror of
https://github.com/langgenius/dify.git
synced 2026-04-19 18:27:27 +08:00
refactor: remove base ui i18n dependency
This commit is contained in:
@ -172,13 +172,13 @@ describe('NumberField wrapper', () => {
|
||||
|
||||
// Increment and decrement buttons should preserve accessible naming, icon fallbacks, and spacing variants.
|
||||
describe('Control buttons', () => {
|
||||
it('should provide localized aria labels and default icons when labels are not provided', () => {
|
||||
it('should provide english fallback aria labels and default icons when labels are not provided', () => {
|
||||
renderNumberField({
|
||||
controlsProps: {},
|
||||
})
|
||||
|
||||
const increment = screen.getByRole('button', { name: 'common.operation.increment' })
|
||||
const decrement = screen.getByRole('button', { name: 'common.operation.decrement' })
|
||||
const increment = screen.getByRole('button', { name: 'Increment value' })
|
||||
const decrement = screen.getByRole('button', { name: 'Decrement value' })
|
||||
|
||||
expect(increment.querySelector('.i-ri-arrow-up-s-line')).toBeInTheDocument()
|
||||
expect(decrement.querySelector('.i-ri-arrow-down-s-line')).toBeInTheDocument()
|
||||
@ -217,11 +217,11 @@ describe('NumberField wrapper', () => {
|
||||
},
|
||||
})
|
||||
|
||||
expect(screen.getByRole('button', { name: 'common.operation.increment' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'common.operation.decrement' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'Increment value' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'Decrement value' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should rely on aria-labelledby when provided instead of injecting a translated aria-label', () => {
|
||||
it('should rely on aria-labelledby when provided instead of injecting a fallback aria-label', () => {
|
||||
render(
|
||||
<>
|
||||
<span id="increment-label">Increment from label</span>
|
||||
|
||||
@ -4,7 +4,6 @@ import type { VariantProps } from 'class-variance-authority'
|
||||
import { NumberField as BaseNumberField } from '@base-ui/react/number-field'
|
||||
import { cva } from 'class-variance-authority'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
export const NumberField = BaseNumberField.Root
|
||||
@ -188,18 +187,19 @@ type NumberFieldButtonVariantProps = Omit<
|
||||
|
||||
export type NumberFieldButtonProps = React.ComponentPropsWithoutRef<typeof BaseNumberField.Increment> & NumberFieldButtonVariantProps
|
||||
|
||||
const incrementAriaLabel = 'Increment value'
|
||||
const decrementAriaLabel = 'Decrement value'
|
||||
|
||||
export function NumberFieldIncrement({
|
||||
className,
|
||||
children,
|
||||
size = 'regular',
|
||||
...props
|
||||
}: NumberFieldButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<BaseNumberField.Increment
|
||||
{...props}
|
||||
aria-label={props['aria-label'] ?? (props['aria-labelledby'] ? undefined : t('operation.increment', { ns: 'common' }))}
|
||||
aria-label={props['aria-label'] ?? (props['aria-labelledby'] ? undefined : incrementAriaLabel)}
|
||||
className={cn(numberFieldControlButtonVariants({ size, direction: 'increment' }), className)}
|
||||
>
|
||||
{children ?? <span aria-hidden="true" className="i-ri-arrow-up-s-line size-3" />}
|
||||
@ -213,12 +213,10 @@ export function NumberFieldDecrement({
|
||||
size = 'regular',
|
||||
...props
|
||||
}: NumberFieldButtonProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
<BaseNumberField.Decrement
|
||||
{...props}
|
||||
aria-label={props['aria-label'] ?? (props['aria-labelledby'] ? undefined : t('operation.decrement', { ns: 'common' }))}
|
||||
aria-label={props['aria-label'] ?? (props['aria-labelledby'] ? undefined : decrementAriaLabel)}
|
||||
className={cn(numberFieldControlButtonVariants({ size, direction: 'decrement' }), className)}
|
||||
>
|
||||
{children ?? <span aria-hidden="true" className="i-ri-arrow-down-s-line size-3" />}
|
||||
|
||||
@ -31,13 +31,13 @@ describe('base/ui/toast', () => {
|
||||
|
||||
expect(await screen.findByText('Saved')).toBeInTheDocument()
|
||||
expect(screen.getByText('Your changes are available now.')).toBeInTheDocument()
|
||||
const viewport = screen.getByRole('region', { name: 'common.toast.notifications' })
|
||||
const viewport = screen.getByRole('region', { name: 'Notifications' })
|
||||
expect(viewport).toHaveAttribute('aria-live', 'polite')
|
||||
expect(viewport).toHaveClass('z-1101')
|
||||
expect(viewport.firstElementChild).toHaveClass('top-4')
|
||||
expect(screen.getByRole('dialog')).not.toHaveClass('outline-hidden')
|
||||
expect(document.body.querySelector('[aria-hidden="true"].i-ri-checkbox-circle-fill')).toBeInTheDocument()
|
||||
expect(document.body.querySelector('button[aria-label="common.toast.close"][aria-hidden="true"]')).toBeInTheDocument()
|
||||
expect(document.body.querySelector('button[aria-label="Close notification"][aria-hidden="true"]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
// Collapsed stacks should keep multiple toast roots mounted for smooth stack animation.
|
||||
@ -57,12 +57,12 @@ describe('base/ui/toast', () => {
|
||||
|
||||
expect(await screen.findByText('Third toast')).toBeInTheDocument()
|
||||
expect(screen.getAllByRole('dialog')).toHaveLength(3)
|
||||
expect(document.body.querySelectorAll('button[aria-label="common.toast.close"][aria-hidden="true"]')).toHaveLength(3)
|
||||
expect(document.body.querySelectorAll('button[aria-label="Close notification"][aria-hidden="true"]')).toHaveLength(3)
|
||||
|
||||
fireEvent.mouseEnter(screen.getByRole('region', { name: 'common.toast.notifications' }))
|
||||
fireEvent.mouseEnter(screen.getByRole('region', { name: 'Notifications' }))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(document.body.querySelector('button[aria-label="common.toast.close"][aria-hidden="true"]')).not.toBeInTheDocument()
|
||||
expect(document.body.querySelector('button[aria-label="Close notification"][aria-hidden="true"]')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -126,9 +126,9 @@ describe('base/ui/toast', () => {
|
||||
})
|
||||
})
|
||||
|
||||
fireEvent.mouseEnter(screen.getByRole('region', { name: 'common.toast.notifications' }))
|
||||
fireEvent.mouseEnter(screen.getByRole('region', { name: 'Notifications' }))
|
||||
|
||||
const dismissButton = await screen.findByRole('button', { name: 'common.toast.close' })
|
||||
const dismissButton = await screen.findByRole('button', { name: 'Close notification' })
|
||||
|
||||
act(() => {
|
||||
dismissButton.click()
|
||||
|
||||
@ -7,7 +7,6 @@ import type {
|
||||
} from '@base-ui/react/toast'
|
||||
import type { ReactNode } from 'react'
|
||||
import { Toast as BaseToast } from '@base-ui/react/toast'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type ToastData = Record<string, never>
|
||||
@ -35,6 +34,9 @@ const TOAST_TONE_STYLES = {
|
||||
},
|
||||
} satisfies Record<string, ToastToneStyle>
|
||||
|
||||
const toastCloseLabel = 'Close notification'
|
||||
const toastViewportLabel = 'Notifications'
|
||||
|
||||
type ToastType = keyof typeof TOAST_TONE_STYLES
|
||||
|
||||
type ToastAddOptions = Omit<ToastManagerAddOptions<ToastData>, 'data' | 'positionerProps' | 'type'> & {
|
||||
@ -145,7 +147,6 @@ function ToastCard({
|
||||
}: {
|
||||
toast: ToastObject<ToastData>
|
||||
}) {
|
||||
const { t } = useTranslation('common')
|
||||
const toastType = getToastType(toastItem.type)
|
||||
|
||||
return (
|
||||
@ -200,7 +201,7 @@ function ToastCard({
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center justify-center rounded-md p-0.5">
|
||||
<BaseToast.Close
|
||||
aria-label={t('toast.close')}
|
||||
aria-label={toastCloseLabel}
|
||||
className={cn(
|
||||
'flex h-5 w-5 items-center justify-center rounded-md hover:bg-state-base-hover focus-visible:bg-state-base-hover focus-visible:ring-1 focus-visible:ring-components-input-border-hover focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
|
||||
)}
|
||||
@ -215,12 +216,11 @@ function ToastCard({
|
||||
}
|
||||
|
||||
function ToastViewport() {
|
||||
const { t } = useTranslation('common')
|
||||
const { toasts } = BaseToast.useToastManager<ToastData>()
|
||||
|
||||
return (
|
||||
<BaseToast.Viewport
|
||||
aria-label={t('toast.notifications')}
|
||||
aria-label={toastViewportLabel}
|
||||
className={cn(
|
||||
// During overlay migration, toast must stay above legacy highPriority modals (z-[1100]).
|
||||
'inset-0 group/toast-viewport pointer-events-none fixed z-1101 overflow-visible',
|
||||
|
||||
Reference in New Issue
Block a user