Skip to content

Commit

Permalink
fix: next steps
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Oct 18, 2023
1 parent 4c1c926 commit bfba1cd
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 64 deletions.
35 changes: 21 additions & 14 deletions src/components/sbb-dialog/sbb-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,12 @@ export class SbbDialog implements ComponentInterface {
this._lastFocusedElement = document.activeElement as HTMLElement;
this.willOpen.emit();
this._state = 'opening';

const firstFocusable = this._element.shadowRoot.querySelector(
IS_FOCUSABLE_QUERY,
) as HTMLElement;
setModalityOnNextFocus(firstFocusable);

this._dialog.show();
// Add this dialog to the global collection
dialogRefs.push(this._element as HTMLSbbDialogElement);
Expand Down Expand Up @@ -310,11 +316,11 @@ export class SbbDialog implements ComponentInterface {
// Wait for dialog transition to complete.
// In rare cases it can be that the animationEnd event is triggered twice.
// To avoid entering a corrupt state, exit when state is not expected.
private _onDialogAnimationEnd(event: AnimationEvent): void {
private async _onDialogAnimationEnd(event: AnimationEvent): Promise<void> {
if (event.animationName === 'open' && this._state === 'opening') {
this._state = 'opened';
this.didOpen.emit();
this._setDialogFocus();
await this._setDialogFocus();
this._focusTrap.trap(this._element);
this._dialogContentResizeObserver.observe(this._dialogContentElement);
this._attachWindowEvents();
Expand All @@ -336,24 +342,25 @@ export class SbbDialog implements ComponentInterface {
}

// Set focus on the first focusable element.
private _setDialogFocus(): void {
private async _setDialogFocus(): Promise<void> {
const firstFocusable = this._element.shadowRoot.querySelector(
IS_FOCUSABLE_QUERY,
) as HTMLElement;

// Focusing sbb-dialog__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._dialogWrapperElement.tabIndex = 0;
this._dialogWrapperElement.focus();

this._dialogWrapperElement.addEventListener(
'blur',
() => this._dialogWrapperElement.removeAttribute('tabindex'),
{ once: true },
);

if (sbbInputModalityDetector.mostRecentModality === 'keyboard') {
await new Promise((resolve) => setTimeout(resolve, 0));
firstFocusable.focus();
} else {
// Focusing sbb-dialog__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._dialogWrapperElement.tabIndex = 0;
this._dialogWrapperElement.focus();

this._dialogWrapperElement.addEventListener(
'blur',
() => this._dialogWrapperElement.removeAttribute('tabindex'),
{ once: true },
);
}
}

Expand Down
26 changes: 14 additions & 12 deletions src/components/sbb-navigation-section/sbb-navigation-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,23 +266,25 @@ export class SbbNavigationSection implements ComponentInterface {
}

// Set focus on the first focusable element.
private _setNavigationSectionFocus(): void {
private async _setNavigationSectionFocus(): Promise<void> {
// Focusing sbb-navigation__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._navigationSectionContainerElement.tabIndex = 0;
this._navigationSectionContainerElement.focus();

this._navigationSectionContainerElement.addEventListener(
'blur',
() => this._navigationSectionContainerElement.removeAttribute('tabindex'),
{ once: true },
);

if (sbbInputModalityDetector.mostRecentModality === 'keyboard') {
await new Promise((resolve) => setTimeout(resolve, 1000));

getFirstFocusableElement(
Array.from(this._element.children).filter(
(e): e is HTMLElement => e instanceof window.HTMLElement,
),
)?.focus();
} else {
// Focusing sbb-navigation__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._navigationSectionContainerElement.tabIndex = 0;
this._navigationSectionContainerElement.focus();

this._navigationSectionContainerElement.addEventListener(
'blur',
() => this._navigationSectionContainerElement.removeAttribute('tabindex'),
{ once: true },
);
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/components/sbb-navigation/sbb-navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -280,24 +280,25 @@ export class SbbNavigation implements ComponentInterface {
}

// Set focus on the first focusable element.
private _setNavigationFocus(): void {
private async _setNavigationFocus(): Promise<void> {
const firstFocusable = this._element.shadowRoot.querySelector(
IS_FOCUSABLE_QUERY,
) as HTMLElement;

// Focusing sbb-navigation__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._navigationContainerElement.tabIndex = 0;
this._navigationContainerElement.focus();

this._navigationContainerElement.addEventListener(
'blur',
() => this._navigationContainerElement.removeAttribute('tabindex'),
{ once: true },
);

if (sbbInputModalityDetector.mostRecentModality === 'keyboard') {
await new Promise((resolve) => setTimeout(resolve, 0));
firstFocusable.focus();
} else {
// Focusing sbb-navigation__wrapper in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._navigationContainerElement.tabIndex = 0;
this._navigationContainerElement.focus();

this._navigationContainerElement.addEventListener(
'blur',
() => this._navigationContainerElement.removeAttribute('tabindex'),
{ once: true },
);
}
}

Expand Down
4 changes: 0 additions & 4 deletions src/components/sbb-tooltip/sbb-tooltip.scss
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,23 @@

@keyframes open {
from {
visibility: hidden;
opacity: 0;
transform: var(--sbb-tooltip-transform);
}

to {
visibility: visible;
opacity: 1;
transform: translateY(0);
}
}

@keyframes close {
from {
visibility: visible;
opacity: 1;
transform: translateY(0);
}

to {
visibility: hidden;
opacity: 0;
transform: var(--sbb-tooltip-transform);
}
Expand Down
56 changes: 34 additions & 22 deletions src/components/sbb-tooltip/sbb-tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ export class SbbTooltip implements ComponentInterface {
this.willOpen.emit();
this._state = 'opening';
this._setTooltipPosition();

const firstFocusable = getFirstFocusableElement(
Array.from(this._element.children).filter(
(e): e is HTMLElement => e instanceof window.HTMLElement,
),
);

// TODO: not working because not visible

setModalityOnNextFocus(firstFocusable);
this._dialog.show();
this._triggerElement?.setAttribute('aria-expanded', 'true');
this._nextFocusedElement = undefined;
Expand Down Expand Up @@ -397,11 +407,11 @@ export class SbbTooltip implements ComponentInterface {
// viewport from overflowing. And set the focus to the first focusable element once the tooltip is open.
// In rare cases it can be that the animationEnd event is triggered twice.
// To avoid entering a corrupt state, exit when state is not expected.
private _onTooltipAnimationEnd(event: AnimationEvent): void {
private async _onTooltipAnimationEnd(event: AnimationEvent): Promise<void> {
if (event.animationName === 'open' && this._state === 'opening') {
this._state = 'opened';
this.didOpen.emit();
this._setTooltipFocus();
await this._setTooltipFocus();
this._focusTrap.trap(this._element);
this._attachWindowEvents();
} else if (event.animationName === 'close' && this._state === 'closing') {
Expand All @@ -421,29 +431,31 @@ export class SbbTooltip implements ComponentInterface {
}

// Set focus on the first focusable element.
private _setTooltipFocus(): void {
private async _setTooltipFocus(): Promise<void> {
const firstFocusable =
(this._element.shadowRoot.querySelector('[sbb-tooltip-close]') as HTMLElement) ||
getFirstFocusableElement(
Array.from(this._element.children).filter(
(e): e is HTMLElement => e instanceof window.HTMLElement,
),
);

// Focusing sbb-tooltip__content in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._tooltipContentElement.tabIndex = 0;
this._tooltipContentElement.focus();
this._element.addEventListener(
'blur',
() => this._tooltipContentElement.removeAttribute('tabindex'),
{
once: true,
},
);

if (sbbInputModalityDetector.mostRecentModality === 'keyboard') {
const firstFocusable =
(this._element.shadowRoot.querySelector('[sbb-tooltip-close]') as HTMLElement) ||
getFirstFocusableElement(
Array.from(this._element.children).filter(
(e): e is HTMLElement => e instanceof window.HTMLElement,
),
);
await new Promise((resolve) => setTimeout(resolve, 0));

firstFocusable?.focus();
} else {
// Focusing sbb-tooltip__content in order to provide a consistent behavior in Safari where else
// the focus-visible styles would be incorrectly applied
this._tooltipContentElement.tabIndex = 0;
this._tooltipContentElement.focus();
this._element.addEventListener(
'blur',
() => this._tooltipContentElement.removeAttribute('tabindex'),
{
once: true,
},
);
}
}

Expand Down

0 comments on commit bfba1cd

Please sign in to comment.