Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apps/desktop/e2e/quote-companion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ test('the quote layer: settle timing, Escape, immediate hide, and scroll followi
await expect(quoteLayer).toBeHidden();
}
await page.mouse.up();
await expect
.poll(() => page.evaluate(() => window.getSelection()?.toString().trim() ?? ''))
.not.toBe('');
// The synthetic events above exercise the mid-gesture timing contract, but
// can run ahead of Chromium's final native selectionchange. Finalize the
// observed non-empty selection explicitly so this phase does not depend on
// host event scheduling.
await page.evaluate(() => document.dispatchEvent(new Event('selectionchange')));
await expect(quoteLayer).toBeVisible();

// Back to no selection, so the measurement below times a fresh appearance
Expand Down
18 changes: 13 additions & 5 deletions apps/desktop/stories/settings/settings-pages.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -930,15 +930,14 @@ function assertDailyReviewSettingsBounds(
selector: HTMLButtonElement,
): void {
const time = canvasElement.querySelector<HTMLInputElement>('input[type="text"]');
const page = canvasElement.querySelector<HTMLElement>('.settingsPageStack');
// The rows kit (#1972) retired `.settingsFormLayout`. A control now lives in
// its row's capped end slot, so `.settingsRowEnd` is the container this
// contract has always meant: the bound the control must not overflow.
const timeForm = time?.closest<HTMLElement>('.settingsRowEnd');
const selectorForm = selector.closest<HTMLElement>('.settingsRowEnd');
const listbox = document.querySelector<HTMLElement>('[role="listbox"]');
const popover = listbox?.closest<HTMLElement>('[popover]');
if (!time || !page || !timeForm || !selectorForm || !popover) {
if (!time || !timeForm || !selectorForm || !popover) {
throw new Error('Daily Review bounds contract could not resolve its production elements');
}

Expand All @@ -947,7 +946,6 @@ function assertDailyReviewSettingsBounds(
const timeRect = time.getBoundingClientRect();
const selectorRect = selector.getBoundingClientRect();
const popoverRect = popover.getBoundingClientRect();
const pageRect = page.getBoundingClientRect();
const doesNotCoverTrigger =
popoverRect.top >= selectorRect.bottom - 1
|| popoverRect.bottom <= selectorRect.top + 1;
Expand All @@ -956,12 +954,22 @@ function assertDailyReviewSettingsBounds(
&& withinHorizontally(selectorRect, selectorForm.getBoundingClientRect())
&& popoverRect.width > 0
&& popoverRect.height > 0
&& withinHorizontally(popoverRect, pageRect)
// The popover is a top-layer surface and may be wider than its trigger;
// the viewport, rather than the settings content column, is its boundary.
&& popoverRect.left >= -1
&& popoverRect.right <= window.innerWidth + 1
&& doesNotCoverTrigger;
if (!valid) {
throw new Error(`Daily Review controls overflow at ${window.innerWidth}px`);
const rectSummary = (name: string, rect: DOMRect) =>
`${name}=[${rect.left.toFixed(1)},${rect.right.toFixed(1)};${rect.width.toFixed(1)}]`;
throw new Error([
`Daily Review controls overflow at ${window.innerWidth}px`,
rectSummary('time', timeRect),
rectSummary('timeForm', timeForm.getBoundingClientRect()),
rectSummary('selector', selectorRect),
rectSummary('selectorForm', selectorForm.getBoundingClientRect()),
rectSummary('popover', popoverRect),
].join(' '));
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/ui/stories/icons.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ interface IconEntry {
}

const LUCIDE_ICONS: IconEntry[] = Object.entries(Icons)
.filter(([name]) => name !== 'ICON_SIZE')
.map(([name, value]) => ({ name, Comp: value as IconEntry['Comp'] }))
.sort((a, b) => a.name.localeCompare(b.name));

Expand Down
Loading