fix(mobile): setting item popover cannot be closed (#8910)

fix AF-1798
This commit is contained in:
pengx17
2024-11-25 05:54:48 +00:00
parent b369ee0cca
commit f6eb84a8e0
8 changed files with 96 additions and 27 deletions
@@ -78,7 +78,7 @@ const MobileTextValue = ({
}: PropertyValueProps) => { }: PropertyValueProps) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [tempValue, setTempValue] = useState<string>(value); const [tempValue, setTempValue] = useState<string>(value || '');
const handleClick = useCallback((e: React.MouseEvent) => { const handleClick = useCallback((e: React.MouseEvent) => {
e.stopPropagation(); e.stopPropagation();
setOpen(true); setOpen(true);
@@ -111,20 +111,21 @@ const MobileTextValue = ({
}, [onChange, tempValue]); }, [onChange, tempValue]);
const t = useI18n(); const t = useI18n();
useEffect(() => { useEffect(() => {
setTempValue(value); setTempValue(value || '');
}, [value]); }, [value]);
return ( return (
<PropertyValue <>
className={styles.textPropertyValueContainer} <PropertyValue
onClick={handleClick} className={styles.textPropertyValueContainer}
isEmpty={!value} onClick={handleClick}
> isEmpty={!value}
<div className={styles.mobileTextareaPlain} data-empty={!tempValue}> >
{tempValue || <div className={styles.mobileTextareaPlain} data-empty={!tempValue}>
t['com.affine.page-properties.property-value-placeholder']()} {tempValue ||
</div> t['com.affine.page-properties.property-value-placeholder']()}
</div>
</PropertyValue>
<ConfigModal <ConfigModal
open={open} open={open}
onOpenChange={setOpen} onOpenChange={setOpen}
@@ -154,7 +155,7 @@ const MobileTextValue = ({
</div> </div>
</div> </div>
</ConfigModal> </ConfigModal>
</PropertyValue> </>
); );
}; };
@@ -44,9 +44,6 @@ export const ConfigModal = ({
animation="slideBottom" animation="slideBottom"
withoutCloseButton withoutCloseButton
contentOptions={{ contentOptions={{
onClick: e => {
e.stopPropagation();
},
className: className:
variant === 'page' variant === 'page'
? styles.pageModalContent ? styles.pageModalContent
@@ -64,7 +64,11 @@ export const SettingDropdownSelect = <
))} ))}
{...menuOptions} {...menuOptions}
> >
<div className={clsx(styles.root, className)} {...attrs}> <div
data-testid="dropdown-select-trigger"
className={clsx(styles.root, className)}
{...attrs}
>
<span className={styles.label}>{selectedItem?.label ?? ''}</span> <span className={styles.label}>{selectedItem?.label ?? ''}</span>
<ArrowDownSmallIcon className={styles.icon} /> <ArrowDownSmallIcon className={styles.icon} />
@@ -10,7 +10,10 @@ export const RowLayout = ({
href, href,
}: PropsWithChildren<{ label: ReactNode; href?: string }>) => { }: PropsWithChildren<{ label: ReactNode; href?: string }>) => {
const content = ( const content = (
<ConfigModal.Row className={styles.baseSettingItem}> <ConfigModal.Row
data-testid="setting-row"
className={styles.baseSettingItem}
>
<div className={styles.baseSettingItemName}>{label}</div> <div className={styles.baseSettingItemName}>{label}</div>
<div className={styles.baseSettingItemAction}> <div className={styles.baseSettingItemAction}>
{children || {children ||
@@ -75,6 +75,7 @@ export const HomeHeader = () => {
onClick={openSetting} onClick={openSetting}
size={28} size={28}
icon={<SettingsIcon />} icon={<SettingsIcon />}
data-testid="settings-button"
/> />
</SafeArea> </SafeArea>
</> </>
@@ -97,7 +97,8 @@ const MobileRichTextCell = ({
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const name = useLiveData(cell.property.name$); const name = useLiveData(cell.property.name$);
return ( return (
<PropertyValue onClick={() => setOpen(true)}> <>
<PropertyValue onClick={() => setOpen(true)}></PropertyValue>
<ConfigModal <ConfigModal
onBack={() => setOpen(false)} onBack={() => setOpen(false)}
open={open} open={open}
@@ -125,7 +126,7 @@ const MobileRichTextCell = ({
onChange={onChange} onChange={onChange}
rowId={rowId} rowId={rowId}
/> />
</PropertyValue> </>
); );
}; };
+60
View File
@@ -0,0 +1,60 @@
import { test } from '@affine-test/kit/mobile';
import { expect, type Page } from '@playwright/test';
const openSettings = async (page: Page) => {
await page.getByTestId('settings-button').click();
await expect(page.getByRole('dialog')).toBeVisible();
await expect(page.locator('header:has-text("Settings")')).toBeVisible();
};
test('can open settings', async ({ page }) => {
await openSettings(page);
});
test('can change theme', async ({ page }) => {
await openSettings(page);
await page
.getByTestId('setting-row')
.filter({
hasText: 'Color mode',
})
.getByTestId('dropdown-select-trigger')
.click();
await expect(
page.getByRole('dialog').filter({
has: page.getByRole('menuitem', { name: 'Light' }),
})
).toBeVisible();
await page.getByRole('menuitem', { name: 'Dark' }).click();
await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark');
});
test('can close change theme popover by clicking outside', async ({ page }) => {
await openSettings(page);
await page
.getByTestId('setting-row')
.filter({
hasText: 'Color mode',
})
.getByTestId('dropdown-select-trigger')
.click();
const themePopover = page.getByRole('dialog').filter({
has: page.getByRole('menuitem', { name: 'Light' }),
});
await expect(themePopover).toBeVisible();
// get a mouse position that is 10px offset to the top of theme popover
// and click
const mousePosition = await themePopover.boundingBox();
if (!mousePosition) {
throw new Error('theme popover is not visible');
}
await page.mouse.click(mousePosition.x, mousePosition.y - 10);
await expect(themePopover).not.toBeVisible();
});
+9 -7
View File
@@ -10,19 +10,21 @@ const config: PlaywrightTestConfig = {
timeout: process.env.CI ? 60_000 : 30_000, timeout: process.env.CI ? 60_000 : 30_000,
outputDir: testResultDir, outputDir: testResultDir,
projects: [ projects: [
{ process.env.CI
name: 'Mobile Safari', ? {
use: { name: 'Mobile Safari',
...devices['iPhone 14'], use: {
}, ...devices['iPhone 14'],
}, },
}
: undefined,
{ {
name: 'Mobile Chrome', name: 'Mobile Chrome',
use: { use: {
...devices['Pixel 5'], ...devices['Pixel 5'],
}, },
}, },
], ].filter(config => config !== undefined),
expect: { expect: {
timeout: process.env.CI ? 15_000 : 5_000, timeout: process.env.CI ? 15_000 : 5_000,
}, },