diff --git a/e2e/activity-lifecycle.spec.ts b/e2e/activity-lifecycle.spec.ts index a1c7892..4f89f48 100644 --- a/e2e/activity-lifecycle.spec.ts +++ b/e2e/activity-lifecycle.spec.ts @@ -273,6 +273,55 @@ test('centers the create activity dialog on mobile and completes the flow', asyn await expect(page.getByRole('heading', { name: 'Centered weekend' })).toBeVisible() }) +test('keeps share and add expense together in the mobile action row', async ({ page }) => { + await page.setViewportSize({ width: 390, height: 844 }) + await page.goto('./') + await page.getByLabel('Display name').fill('Mobile Sharer') + await page.getByRole('button', { name: 'Continue' }).click() + await page.getByRole('button', { name: 'Create an activity' }).click() + await page.getByLabel('Activity name').fill('Aligned weekend') + await page.getByRole('button', { name: 'Create activity' }).click() + + await page.getByRole('button', { name: 'Add expense' }).click() + await page.getByLabel('Description').fill('Lunch') + await page.getByRole('spinbutton', { name: 'Amount' }).fill('24') + await page.getByRole('button', { name: 'Save expense' }).click() + + const actionRow = page.locator('.group-primary-actions') + await expect(actionRow.getByRole('button', { name: 'Add expense' })).toBeVisible() + await expect(actionRow.getByRole('button', { name: 'Share', exact: true })).toBeVisible() + + const layout = await actionRow.evaluate(element => { + const buttons = Array.from(element.querySelectorAll('button')).map(button => { + const bounds = button.getBoundingClientRect() + return { + label: button.textContent?.trim(), + top: bounds.top, + right: bounds.right, + bottom: bounds.bottom, + left: bounds.left, + width: bounds.width, + } + }) + return { + addExpense: buttons.find(button => button.label === 'Add expense'), + share: buttons.find(button => button.label === 'Share'), + viewportWidth: window.innerWidth, + } + }) + + expect(layout.addExpense).toBeDefined() + expect(layout.share).toBeDefined() + expect(Math.abs(layout.addExpense!.top - layout.share!.top)).toBeLessThanOrEqual(1) + expect(Math.abs(layout.addExpense!.bottom - layout.share!.bottom)).toBeLessThanOrEqual(1) + expect(layout.addExpense!.left).toBeGreaterThanOrEqual(20) + expect(layout.share!.right).toBeLessThanOrEqual(layout.viewportWidth - 20) + expect(layout.addExpense!.width).toBeGreaterThan(layout.share!.width) + + await actionRow.getByRole('button', { name: 'Share', exact: true }).click() + await expect(page.getByRole('dialog', { name: 'Share activity' })).toBeVisible() +}) + test('centers compact mobile dialogs and keeps long forms as sheets', async ({ page }) => { await page.setViewportSize({ width: 390, height: 667 }) await page.goto('./') diff --git a/src/styles.css b/src/styles.css index 430ac57..7efb394 100644 --- a/src/styles.css +++ b/src/styles.css @@ -502,10 +502,12 @@ button:focus-visible, input:focus-visible, select:focus-visible { outline: 3px s .activity-currency--localized { width: 166px; } .currency-menu { right: auto; left: 0; } .group-share { width: 100%; align-items: flex-start; } - .group-actions { width: 100%; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-start; } - .group-context-actions, .group-primary-actions { display: contents; } - .group-actions .share-button { margin-left: auto; } - .group-primary-actions .confirm-button { flex: 1 0 100%; } + .group-actions { width: 100%; display: grid; gap: 12px; } + .group-context-actions { width: 100%; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-start; gap: 9px; } + .group-primary-actions { width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: stretch; gap: 9px; } + .group-primary-actions:empty { display: none; } + .group-actions .share-button { grid-column: 2; grid-row: 1; margin: 0; } + .group-primary-actions .confirm-button { grid-column: 1; grid-row: 1; width: 100%; } .activity-feedback { text-align: left; } .activity-empty { min-height: 330px; padding-block: 34px; } .shared-preview { margin: 14px 18px 0; align-items: stretch; flex-direction: column; } @@ -542,7 +544,6 @@ button:focus-visible, input:focus-visible, select:focus-visible { outline: 3px s .settlement-row .row-copy { min-width: calc(100% - 96px); } .settlement-action { width: 100%; justify-content: flex-end; } .form-grid { grid-template-columns: 1fr; } - .group-actions { display: flex; } .shared-preview > div:last-child { grid-template-columns: 1fr; } .live-status-actions { grid-template-columns: 1fr; } .live-status-actions button:only-child { grid-column: auto; }