Skip to content

Commit

Permalink
fix: handle scroll events in custom scroll contexts
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Dec 18, 2024
1 parent b6b4c22 commit 2d52b8e
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 100 deletions.
1 change: 1 addition & 0 deletions src/elements/autocomplete/autocomplete-base-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ export abstract class SbbAutocompleteBaseElement extends SbbNegativeMixin(
document.addEventListener('scroll', () => this._setOverlayPosition(), {
passive: true,
signal: this._openPanelEventsController.signal,
capture: true,
});
window.addEventListener('resize', () => this._setOverlayPosition(), {
passive: true,
Expand Down
40 changes: 40 additions & 0 deletions src/elements/autocomplete/autocomplete.visual.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { aTimeout } from '@open-wc/testing';
import { sendKeys } from '@web/test-runner-commands';
import { html, nothing, type TemplateResult } from 'lit';
import { styleMap } from 'lit/directives/style-map.js';
Expand Down Expand Up @@ -289,5 +290,44 @@ describe('sbb-autocomplete', () => {
});
});
}

it(
`with scroll context`,
visualDiffDefault.with(async (setup) => {
await setup.withFixture(html`
<div style="overflow: auto; height: 400px;">
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<sbb-form-field>
<input />
<sbb-autocomplete>
<sbb-option>Option 1</sbb-option>
<sbb-option>Option 2</sbb-option>
</sbb-autocomplete>
</sbb-form-field>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
`);
const scrollContext = setup.snapshotElement.querySelector('div')!;
const input = setup.snapshotElement.querySelector('input')!;

setup.withSnapshotElement(scrollContext);

setup.withPostSetupAction(async () => {
input.focus();
scrollContext.scrollTo(0, 100);

// We need to ensure content resizing kicked in
await aTimeout(40);
});
}),
);
});
});
2 changes: 1 addition & 1 deletion src/elements/core/eventing/forward-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Forwards an event to the host element provided.
* This way, an event triggered in the ShadowDOM can cross its boundary and can be listened on the host component.
*/
export function forwardEventToHost(event: Event, host: HTMLElement): void {
export function forwardEventToHost(event: Event, host: HTMLElement | Document): void {
const eventConstructor = Object.getPrototypeOf(event).constructor;
const copiedEvent: Event = new eventConstructor(event.type, event);
host.dispatchEvent(copiedEvent);
Expand Down
4 changes: 3 additions & 1 deletion src/elements/dialog/dialog-content/dialog-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { CSSResultGroup, TemplateResult } from 'lit';
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';

import { forwardEventToHost } from '../../core/eventing.js';

import style from './dialog-content.scss?lit&inline';

/**
Expand All @@ -16,7 +18,7 @@ class SbbDialogContentElement extends LitElement {

protected override render(): TemplateResult {
return html`
<div class="sbb-dialog-content">
<div class="sbb-dialog-content" @scroll=${(e: Event) => forwardEventToHost(e, document)}>
<slot></slot>
</div>
`;
Expand Down
26 changes: 26 additions & 0 deletions src/elements/dialog/dialog/dialog.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import readme from './readme.md?raw';
import '../../button.js';
import '../../link.js';
import '../../form-field.js';
import '../../select.js';
import '../../option.js';
import '../../image.js';
import '../../popover.js';
import '../dialog-content.js';
Expand Down Expand Up @@ -225,6 +227,30 @@ const DefaultTemplate = ({
Dialog content
<sbb-popover-trigger id="popover-trigger"></sbb-popover-trigger>
</p>
<sbb-form-field>
<sbb-select placeholder="Please select value.">
<sbb-option value="Option 1"> Option 1 </sbb-option>
<sbb-option value="Option 2"> Option 2 </sbb-option>
<sbb-option value="Option 3"> Option 3 </sbb-option>
<sbb-option value="Option 4"> Option 4 </sbb-option>
<sbb-option value="Option 5"> Option 5 </sbb-option>
</sbb-select>
</sbb-form-field>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<sbb-popover trigger="popover-trigger">
<p style="margin: 0" class="sbb-text-s">Some content.</p>
</sbb-popover>
Expand Down
2 changes: 1 addition & 1 deletion src/elements/dialog/dialog/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ class SbbDialogElement extends SbbOverlayBaseElement {

private _handleOpening(): void {
this.state = 'opened';
this.didOpen.emit();
this.inertController.activate();
this.attachOpenOverlayEvents();
this.setOverlayFocus();
Expand All @@ -131,6 +130,7 @@ class SbbDialogElement extends SbbOverlayBaseElement {
),
);
this.focusHandler.trap(this);
this.didOpen.emit();
}

public override connectedCallback(): void {
Expand Down
54 changes: 53 additions & 1 deletion src/elements/dialog/dialog/dialog.visual.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { aTimeout } from '@open-wc/testing';
import { html, nothing, type TemplateResult } from 'lit';

import { describeViewports, visualDiffDefault } from '../../core/testing/private.js';
Expand All @@ -6,9 +7,12 @@ import './dialog.js';
import '../dialog-actions.js';
import '../dialog-content.js';
import '../dialog-title.js';
import '../../link/block-link.js';
import '../../button/button.js';
import '../../button/secondary-button.js';
import '../../form-field.js';
import '../../link/block-link.js';
import '../../option.js';
import '../../select.js';

describe(`sbb-dialog`, () => {
const negativeCases = [false, true];
Expand Down Expand Up @@ -112,5 +116,53 @@ describe(`sbb-dialog`, () => {
setup.withPostSetupAction(() => dialog.open());
}),
);

it(
`with scrolled select`,
visualDiffDefault.with(async (setup) => {
await setup.withFixture(html`
<sbb-dialog>
${dialogTitle()}
<sbb-dialog-content>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<sbb-form-field>
<sbb-select>
<sbb-option>Option 1</sbb-option>
<sbb-option>Option 2</sbb-option>
</sbb-select>
</sbb-form-field>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
<p>Content</p>
</sbb-dialog-content>
${dialogFooter()}
</sbb-dialog>
`);
const dialog = setup.snapshotElement.querySelector('sbb-dialog')!;
const select = setup.snapshotElement.querySelector('sbb-select')!;
const scrollContext = setup.snapshotElement
.querySelector('sbb-dialog-content')!
.shadowRoot!.querySelector<HTMLDivElement>('.sbb-dialog-content')!;

setup.withSnapshotElement(dialog);

setup.withPostSetupAction(async () => {
dialog.open();

// We need to wait until the dialog is completely settled.
await aTimeout(40);

select.click();
scrollContext.scrollTo(0, 100);

// We need to ensure content resizing kicked in
await aTimeout(0);
});
}),
);
});
});
28 changes: 2 additions & 26 deletions src/elements/menu/menu/menu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,9 @@ describe(`sbb-menu`, () => {
await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);

await waitForLitRender(element);
await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);

await waitForLitRender(element);
expect(element).to.have.attribute('data-state', 'opened');
});

Expand All @@ -71,12 +69,9 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');

await sendKeys({ press: tabKey });
Expand All @@ -87,11 +82,9 @@ describe(`sbb-menu`, () => {

await willCloseEventSpy.calledOnce();
expect(willCloseEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didCloseEventSpy.calledOnce();
expect(didCloseEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'closed');
});
Expand All @@ -108,11 +101,9 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');
expect(menuAction).not.to.be.null;
Expand All @@ -122,11 +113,8 @@ describe(`sbb-menu`, () => {
await willCloseEventSpy.calledOnce();
expect(willCloseEventSpy.count).to.be.equal(1);

await waitForLitRender(element);
await didCloseEventSpy.calledOnce();
expect(didCloseEventSpy.count).to.be.equal(1);

await waitForLitRender(element);
expect(element).to.have.attribute('data-state', 'closed');
});

Expand All @@ -142,11 +130,9 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');
expect(menuLink).not.to.be.null;
Expand All @@ -156,11 +142,9 @@ describe(`sbb-menu`, () => {

await willCloseEventSpy.calledOnce();
expect(willCloseEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didCloseEventSpy.calledOnce();
expect(didCloseEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'closed');
});
Expand Down Expand Up @@ -201,11 +185,9 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');

Expand Down Expand Up @@ -236,11 +218,9 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');

Expand All @@ -262,15 +242,11 @@ describe(`sbb-menu`, () => {

await willOpenEventSpy.calledOnce();
expect(willOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

await didOpenEventSpy.calledOnce();
expect(didOpenEventSpy.count).to.be.equal(1);
await waitForLitRender(element);

expect(element).to.have.attribute('data-state', 'opened');

await waitForLitRender(element);
expect(document.activeElement!.id).to.be.equal('menu-link');
});

Expand All @@ -292,14 +268,14 @@ describe(`sbb-menu`, () => {
const willCloseEventSpy = new EventSpy(SbbMenuElement.events.willClose, element);

element.open();
await didOpenEventSpy.calledOnce();
await waitForLitRender(element);
await didOpenEventSpy.calledOnce();

element.addEventListener(SbbMenuElement.events.willClose, (ev) => ev.preventDefault());
element.close();

await willCloseEventSpy.calledOnce();
await waitForLitRender(element);
await willCloseEventSpy.calledOnce();

expect(element).to.have.attribute('data-state', 'opened');
});
Expand Down
3 changes: 2 additions & 1 deletion src/elements/menu/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ class SbbMenuElement extends SbbNamedSlotListMixin<

private _handleOpening(): void {
this.state = 'opened';
this.didOpen.emit();
this._inertController.activate();
this._setMenuFocus();
this._focusHandler.trap(this);
this._attachWindowEvents();
this.didOpen.emit();
}

private _handleClosing(): void {
Expand Down Expand Up @@ -319,6 +319,7 @@ class SbbMenuElement extends SbbNamedSlotListMixin<
document.addEventListener('scroll', () => this._setMenuPosition(), {
passive: true,
signal: this._windowEventsController.signal,
capture: true,
});
window.addEventListener('resize', () => this._setMenuPosition(), {
passive: true,
Expand Down
Loading

0 comments on commit 2d52b8e

Please sign in to comment.