diff --git a/page/api.ts b/page/api.ts index 69d59a2..45f98d1 100644 --- a/page/api.ts +++ b/page/api.ts @@ -117,6 +117,7 @@ const arrowBack = common.replace('{}', '0 0 24 24').replace('{}', 'M16.62 2.99a1 const arrowForward = common.replace('{}', '0 0 24 24').replace('{}', 'M7.38 21.01c.49.49 1.28.49 1.77 0l8.31-8.31a.996.996 0 0 0 0-1.41L9.15 2.98c-.49-.49-1.28-.49-1.77 0s-.49 1.28 0 1.77L14.62 12l-7.25 7.25c-.48.48-.48 1.28.01 1.76z') function setCandidates(cands: Candidate[], highlighted: number, markText: string, pageable: boolean, hasPrev: boolean, hasNext: boolean, scrollState: SCROLL_STATE, scrollStart: boolean, scrollEnd: boolean) { + const isVertical = hoverables.classList.contains('fcitx-vertical') resetMouseMoveState() hideContextmenu() setScrollState(scrollState) @@ -158,7 +159,7 @@ function setCandidates(cands: Candidate[], highlighted: number, markText: string const candidateInner = div('fcitx-candidate-inner', 'fcitx-hoverable-inner') // Render placeholder for vertical/scroll non-highlighted candidates - if (hoverables.classList.contains('fcitx-vertical') || hoverables.classList.contains('fcitx-horizontal-scroll') || i === highlighted) { + if (isVertical || hoverables.classList.contains('fcitx-horizontal-scroll') || i === highlighted) { const mark = div('fcitx-mark') if (markText === '') { mark.classList.add('fcitx-no-text') @@ -194,12 +195,9 @@ function setCandidates(cands: Candidate[], highlighted: number, markText: string candidate.append(candidateInner) hoverables.append(candidate) - // No divider after last element in non-scroll mode, - // but for scroll mode it needs to fill the row when - // candidates are not enough. - if (scrollState === SCROLLING || i !== cands.length - 1) { - hoverables.append(divider()) - } + // For horizontal/scroll mode it needs to fill the row when candidates are not enough. + // For vertical mode, this last divider is hidden. + hoverables.append(divider()) } setActions(cands.map(c => c.actions)) diff --git a/page/common.scss b/page/common.scss index 64dcb1d..c865221 100644 --- a/page/common.scss +++ b/page/common.scss @@ -374,6 +374,11 @@ $color-transition: var(--color-transition, background-color 500ms ease, color 50 border-end-end-radius: calc($candidate-height / 2 + $border-width); } + .fcitx-panel:has(.fcitx-horizontal-scroll) { + /* Apply to panel to restrict both candidates and preedit width. */ + inline-size: calc($cell-width * var(--max-column, 6) + 10px /* 2px redundance + 8px scrollbar making default 400px */); + } + .fcitx-candidate-inner, .fcitx-preedit, .fcitx-aux-down, .fcitx-menu-item { /* Make sure 🦦 takes equal width when vertical+vertical-rl. */ min-block-size: $text-content-size; @@ -485,7 +490,6 @@ $color-transition: var(--color-transition, background-color 500ms ease, color 50 .fcitx-horizontal-scroll { max-block-size: calc(var(--max-row, 6) * $candidate-height); /* If block-size, 2 rows will have 90px each. */ - inline-size: calc($cell-width * var(--max-column, 6) + 10px /* 2px redundance + 8px scrollbar making default 400px */); transition: var(--scroll-animation, max-block-size 300ms); .fcitx-candidate { diff --git a/page/generic.scss b/page/generic.scss index dec81b8..51b3ba7 100644 --- a/page/generic.scss +++ b/page/generic.scss @@ -82,6 +82,10 @@ .fcitx-divider { flex-direction: row; + + &:last-child, &:has(+ .fcitx-divider-paging) { + display: none; + } } } @@ -95,7 +99,8 @@ display: flex; } - .fcitx-divider { + /* stylelint-disable-next-line no-descending-specificity */ + .fcitx-divider { flex-direction: column; /* If the last row (either temporary with more candidates to come, or final when scroll ends) @@ -103,6 +108,18 @@ &:last-child { flex-grow: 1; } + + &:has(+ .fcitx-divider-paging) { + flex-grow: 1; + + .fcitx-divider-middle { + block-size: 0; + } + + .fcitx-divider-side { + flex-grow: 1; + } + } } } diff --git a/page/macos.scss b/page/macos.scss index 239d212..c37e3e1 100644 --- a/page/macos.scss +++ b/page/macos.scss @@ -48,15 +48,19 @@ inline-size: 100%; } + .fcitx-hoverables.fcitx-horizontal-scroll .fcitx-divider-middle { + block-size: 100%; + } + .fcitx-hoverables.fcitx-horizontal .fcitx-divider { inline-size: 0; &.fcitx-divider-paging { inline-size: 1px; - } - .fcitx-divider-middle { - block-size: 100%; + .fcitx-divider-middle { + block-size: 100%; + } } } diff --git a/tests/customize/test-color.spec.ts b/tests/customize/test-color.spec.ts index 2c8ba57..8fdb6db 100644 --- a/tests/customize/test-color.spec.ts +++ b/tests/customize/test-color.spec.ts @@ -15,7 +15,7 @@ test('Indicator', async ({ page }) => { DarkMode: { OverrideDefault: 'True', AuxColor: '#FF0000' }, LightMode: { OverrideDefault: 'True', AuxColor: '#00FF00' }, }) - await updateInputPanel(page, '', 'en', '') + await updateInputPanel(page, '', 'en') await expect(auxUp).toHaveCSS('color', 'rgb(255, 0, 0)') await page.evaluate(() => window.fcitx.setTheme(1)) @@ -31,7 +31,7 @@ test('Preedit text', async ({ page }) => { DarkMode: { OverrideDefault: 'True', PreeditColorPreCaret: '#FF0000', PreeditColorPostCaret: '#00FF00' }, LightMode: { OverrideDefault: 'True', PreeditColorPreCaret: '#0000FF', PreeditColorPostCaret: '#FFFF00' }, }) - await updateInputPanel(page, PRE_CARET + CARET + POST_CARET, '', '') + await updateInputPanel(page, PRE_CARET + CARET + POST_CARET) await expect(preCaret).toHaveCSS('color', 'rgb(255, 0, 0)') await expect(postCaret).toHaveCSS('color', 'rgb(0, 255, 0)') @@ -49,7 +49,7 @@ test('Preedit caret', async ({ page }) => { LightMode: { OverrideDefault: 'True', PreeditColorCaret: '#00FF00' }, } await setStyle(page, colorStyle) - await updateInputPanel(page, PRE_CARET + CARET + POST_CARET, '', '') + await updateInputPanel(page, PRE_CARET + CARET + POST_CARET) await expect(caret).toHaveCSS('background-color', 'rgb(255, 0, 0)') await page.evaluate(() => window.fcitx.setTheme(1)) @@ -58,7 +58,7 @@ test('Preedit caret', async ({ page }) => { await setStyle(page, { ...colorStyle, Caret: { Style: 'Text', } }) - await updateInputPanel(page, PRE_CARET + CARET_TEXT + POST_CARET, '', '') + await updateInputPanel(page, PRE_CARET + CARET_TEXT + POST_CARET) await expect(caret).toHaveCSS('color', 'rgb(0, 255, 0)') await page.evaluate(() => window.fcitx.setTheme(2)) diff --git a/tests/test-corner-case.spec.ts b/tests/test-corner-case.spec.ts index b6310f5..f2e4cfe 100644 --- a/tests/test-corner-case.spec.ts +++ b/tests/test-corner-case.spec.ts @@ -1,6 +1,6 @@ import type { Page } from '@playwright/test' import test, { expect } from '@playwright/test' -import { candidate, followHostTheme, getBox, hover, init, panel, setCandidates, setStyle, transparent } from './util' +import { candidate, followHostTheme, getBox, hover, init, panel, scrollExpand, setCandidates, setStyle, transparent, updateInputPanel } from './util' test('Horizontal multi-line candidate', async ({ page }) => { await init(page) @@ -109,3 +109,43 @@ test.describe('Ghost stripe override zero margin', () => { }) } }) + +const shortPreedit = '短' +const longPreedit = '长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长' + +test('Extremely long preedit horizontal', async ({ page }) => { + await init(page) + + const lastDivider = page.locator('.fcitx-divider').nth(-2) + const pagingDivider = page.locator('.fcitx-divider').nth(-1) + await updateInputPanel(page, shortPreedit) + await setCandidates(page, [{ text: '1' }], 0, '', true) + await expect(pagingDivider).toHaveCSS('width', '1px') + await expect(lastDivider, 'Last divider is hidden by default').toHaveCSS('width', '0px') + + await updateInputPanel(page, longPreedit) + await expect(pagingDivider).toHaveCSS('width', '1px') + const box = await getBox(lastDivider) + expect(box.width, 'Last divider has width if preedit is too long').toBeGreaterThan(400) + await expect(lastDivider.locator('.fcitx-divider-middle'), 'Middle part that has divider color is hidden').toHaveCSS('height', '0px') + const upperSide = lastDivider.locator('.fcitx-divider-side').first() + const lowerSide = lastDivider.locator('.fcitx-divider-side').last() + await expect(upperSide, 'Side parts split divider evenly').toHaveCSS('height', '14px') + await expect(lowerSide).toHaveCSS('height', '14px') + await expect(upperSide, 'Divider has panel color').toHaveCSS('background-color', 'rgba(40, 40, 40, 0.71)') + await expect(lowerSide).toHaveCSS('background-color', 'rgba(40, 40, 40, 0.71)') +}) + +test('Extremely long preedit scroll', async ({ page }) => { + await init(page) + + const header = page.locator('.fcitx-header') + await updateInputPanel(page, '短') + await scrollExpand(page, ['1']) + await expect(header).toHaveCSS('width', '400px') + await expect(header).toHaveCSS('height', '28px') + + await updateInputPanel(page, longPreedit) + await expect(header).toHaveCSS('width', '400px') + await expect(header, 'Width is restricted so text is wrapped').toHaveCSS('height', '36px') +}) diff --git a/tests/test-generic.spec.ts b/tests/test-generic.spec.ts index afbfc15..0db5b7d 100644 --- a/tests/test-generic.spec.ts +++ b/tests/test-generic.spec.ts @@ -58,6 +58,11 @@ test('HTML structure', async ({ page }) => {
测试
+
+
+
+
+
diff --git a/tests/test-header.spec.ts b/tests/test-header.spec.ts index 515cf06..7437c27 100644 --- a/tests/test-header.spec.ts +++ b/tests/test-header.spec.ts @@ -7,13 +7,13 @@ test('Square when single character auxUp for macOS 15', async ({ page }) => { const pane = panel(page) const side = 32 - await updateInputPanel(page, '', 'A', '') + await updateInputPanel(page, '', 'A') await expect(pane).toHaveText('A') let box = await getBox(pane) expect(box.width).toEqual(side) expect(box.height).toEqual(side) - await updateInputPanel(page, '', '拼', '') + await updateInputPanel(page, '', '拼') await expect(pane).toHaveText('拼') box = await getBox(pane) expect(box.width).toEqual(side) @@ -24,9 +24,9 @@ test('No text shift when preedit grows', async ({ page }) => { await init(page) const preedit = panel(page).locator('.fcitx-preedit') - await updateInputPanel(page, 'c', '', '') + await updateInputPanel(page, 'c') const cBox = await getTextBox(preedit, 0) - await updateInputPanel(page, 'ce', '', '') + await updateInputPanel(page, 'ce') const ceBox = await getTextBox(preedit, 0) expect(ceBox).toEqual(cBox) }) diff --git a/tests/util.ts b/tests/util.ts index 67b14e3..c4492ef 100644 --- a/tests/util.ts +++ b/tests/util.ts @@ -48,14 +48,14 @@ export async function followHostTheme(page: Page, system: string, version: numbe return setStyle(page, { Size: { OverrideDefault: 'False' } }) } -export function updateInputPanel(page: Page, preedit: string, auxUp: string, auxDown: string) { +export function updateInputPanel(page: Page, preedit: string, auxUp: string = '', auxDown: string = '') { return page.evaluate(({ preedit, auxUp, auxDown }) => window.fcitx.updateInputPanel(preedit, auxUp, auxDown), { preedit, auxUp, auxDown }) } -export function setCandidates(page: Page, cands: Partial[], highlighted: number, markText = '') { - return page.evaluate(({ cands, highlighted, markText }) => - window.fcitx.setCandidates(cands.map(cand => ({ text: 'text', label: '1', comment: 'comment', actions: [], ...cand })), highlighted, markText, false, false, false, 0, false, false), { cands, highlighted, markText }) +export function setCandidates(page: Page, cands: Partial[], highlighted: number, markText = '', pageable = false) { + return page.evaluate(({ cands, highlighted, markText, pageable }) => + window.fcitx.setCandidates(cands.map(cand => ({ text: 'text', label: '1', comment: 'comment', actions: [], ...cand })), highlighted, markText, pageable, false, false, 0, false, false), { cands, highlighted, markText, pageable }) } export async function scrollExpand(page: Page, texts: string[]) {