mirror of
https://github.com/dream-num/univer.git
synced 2026-08-28 23:01:30 +08:00
fix(ui): align dropdowns correctly in RTL layouts (#7522)
This commit is contained in:
@@ -295,7 +295,6 @@ export function DefinedName({ disable }: { disable: boolean }) {
|
||||
univer-box-border univer-size-full univer-appearance-none univer-bg-transparent univer-pl-1.5
|
||||
univer-pr-5 univer-text-gray-900
|
||||
focus:univer-outline-none
|
||||
rtl:univer-pl-5 rtl:univer-pr-1.5
|
||||
dark:!univer-border-r-gray-700 dark:!univer-text-gray-0
|
||||
`, borderRightClassName, {
|
||||
'univer-cursor-not-allowed': disable,
|
||||
@@ -323,7 +322,6 @@ export function DefinedName({ disable }: { disable: boolean }) {
|
||||
univer-absolute univer-right-0 univer-top-0 univer-flex univer-h-full univer-cursor-pointer
|
||||
univer-items-center univer-justify-center univer-px-1 univer-transition-colors univer-duration-200
|
||||
hover:univer-bg-gray-100
|
||||
rtl:univer-left-0 rtl:univer-right-auto
|
||||
dark:!univer-text-gray-0
|
||||
dark:hover:!univer-bg-gray-800
|
||||
`, {
|
||||
|
||||
@@ -328,11 +328,26 @@ describe('FormulaBar', () => {
|
||||
|
||||
it('keeps its toolbar layout LTR when the sheet host is RTL', () => {
|
||||
currentBed = createFormulaBarTestBed();
|
||||
const rendered = renderWithDependencies(<FormulaBar disableDefinedName />, currentBed.injector);
|
||||
const rendered = renderWithDependencies(
|
||||
<div dir="rtl">
|
||||
<FormulaBar disableDefinedName />
|
||||
</div>,
|
||||
currentBed.injector
|
||||
);
|
||||
root = rendered.root;
|
||||
container = rendered.container;
|
||||
|
||||
expect(rendered.container.querySelector('[data-u-comp="formula-bar"]')?.getAttribute('dir')).toBe('ltr');
|
||||
const formulaBar = rendered.container.querySelector('[data-u-comp="formula-bar"]');
|
||||
const definedName = formulaBar?.querySelector('[data-u-comp="defined-name"]');
|
||||
const input = definedName?.querySelector('input');
|
||||
const dropdownTrigger = definedName?.querySelector('a');
|
||||
|
||||
expect(formulaBar?.getAttribute('dir')).toBe('ltr');
|
||||
expect(input?.classList).toContain('univer-pl-1.5');
|
||||
expect(input?.classList).toContain('univer-pr-5');
|
||||
expect(input?.className).not.toContain('rtl:');
|
||||
expect(dropdownTrigger?.classList).toContain('univer-right-0');
|
||||
expect(dropdownTrigger?.className).not.toContain('rtl:');
|
||||
});
|
||||
|
||||
it('closes editing through the command service when cancel is clicked', async () => {
|
||||
|
||||
@@ -19,6 +19,7 @@ import type { ReactNode } from 'react';
|
||||
import type { IMenuItem, IValueOption } from '../../../services/menu/menu';
|
||||
import {
|
||||
clsx,
|
||||
ConfigContext,
|
||||
Dropdown,
|
||||
DropdownMenu,
|
||||
Tooltip,
|
||||
@@ -149,7 +150,8 @@ export const TooltipWrapper = forwardRef<ITooltipWrapperRef, ITooltipProps & { d
|
||||
});
|
||||
|
||||
export function DropdownWrapper(props: Omit<Partial<IDropdownProps>, 'overlay'> & { overlay: ReactNode; align?: 'start' | 'end' | 'center' }) {
|
||||
const { children, overlay, disabled, align = 'start' } = props;
|
||||
const { children, overlay, disabled, align } = props;
|
||||
const { direction } = useContext(ConfigContext);
|
||||
const { dropdownVisible, setDropdownVisible } = useContext(TooltipWrapperContext);
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
const overlayRef = useRef<HTMLDivElement>(null);
|
||||
@@ -181,7 +183,7 @@ export function DropdownWrapper(props: Omit<Partial<IDropdownProps>, 'overlay'>
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
align={align}
|
||||
align={align ?? (direction === 'rtl' ? 'end' : 'start')}
|
||||
overlay={(
|
||||
<div ref={overlayRef} className="univer-grid univer-gap-2">
|
||||
{overlay}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
import type { ComponentType, ReactElement } from 'react';
|
||||
import { cleanup, fireEvent, render } from '@testing-library/react';
|
||||
import { ILogService, Injector, LocaleService } from '@univerjs/core';
|
||||
import { ConfigProvider } from '@univerjs/design';
|
||||
import { of } from 'rxjs';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
@@ -134,6 +135,25 @@ describe('DropdownMenuLabel', () => {
|
||||
});
|
||||
|
||||
describe('DropdownWrapper', () => {
|
||||
it('opens toward the left in RTL layouts', async () => {
|
||||
const { findByText, getByRole } = render(
|
||||
<ConfigProvider direction="rtl" mountContainer={document.body}>
|
||||
<ToolbarDropdownProvider>
|
||||
<TooltipWrapper dropdownKey="test-dropdown">
|
||||
<DropdownWrapper overlay={<div>Dropdown content</div>}>
|
||||
<button type="button">Open dropdown</button>
|
||||
</DropdownWrapper>
|
||||
</TooltipWrapper>
|
||||
</ToolbarDropdownProvider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
fireEvent.click(getByRole('button', { name: 'Open dropdown' }));
|
||||
const content = (await findByText('Dropdown content')).closest('[data-slot="popover-content"]');
|
||||
|
||||
expect(content?.getAttribute('data-align')).toBe('end');
|
||||
});
|
||||
|
||||
it('closes on an outside pointerdown even when no click follows', async () => {
|
||||
const { findByText, getByRole, queryByText } = render(
|
||||
<ToolbarDropdownProvider>
|
||||
|
||||
Reference in New Issue
Block a user