Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Groupper, Modalizer): Consolidating and making consistent how Groupper and Modalizer are activated on different interactions. #404

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
39 changes: 38 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@ All notable changes to this project will be documented in this file. Dates are d

Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [v8.1.0-canary.0](https://github.com/microsoft/tabster/compare/v8.0.1...v8.1.0-canary.0)

- ci: add skipPublish variable to release pipeline [`#402`](https://github.com/microsoft/tabster/pull/402)
- chore: bump loader-utils and shell-quote deps [`#400`](https://github.com/microsoft/tabster/pull/400)
- fix(Groupper, Modalizer): Consolidating and making consistent how Groupper and Modalizer are activated on different interactions. [`e389e55`](https://github.com/microsoft/tabster/commit/e389e55144f7f04320f2018ab6e347b546ebb5ed)

#### [v8.0.1](https://github.com/microsoft/tabster/compare/v8.0.0...v8.0.1)

> 8 July 2024

- fix(Mover): Checking that memorized element is still focusable. [`#393`](https://github.com/microsoft/tabster/pull/393)
- Release 8.0.1 [`7ca8d56`](https://github.com/microsoft/tabster/commit/7ca8d56602d01105a7bb796cc562d1e577616cf3)

#### [v8.0.0](https://github.com/microsoft/tabster/compare/v8.0.0-canary.0...v8.0.0)

Expand All @@ -19,13 +28,41 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- Release 7.1.4 [`be9a752`](https://github.com/microsoft/tabster/commit/be9a752bf753a0f419635c15875c47ceff456f67)
- Release 7.3.0 [`0ff8b1c`](https://github.com/microsoft/tabster/commit/0ff8b1cd82b5d14259b562ba4d2838280101d9e6)

#### [v8.0.0-canary.0](https://github.com/microsoft/tabster/compare/v7.3.0...v8.0.0-canary.0)
#### [v8.0.0-canary.0](https://github.com/microsoft/tabster/compare/v7.4.0-canary.3...v8.0.0-canary.0)

> 21 May 2024

- Rearranging exports so that types are separate from consts and consts are not bulk-exported as subproperty. [`0ba63cb`](https://github.com/microsoft/tabster/commit/0ba63cb5202f851ed4dbd8100270728d4aba032d)
- Release 8.0.0-canary.0 [`caf23e5`](https://github.com/microsoft/tabster/commit/caf23e54adc00c2fd4994cd2a59b351d2f2ac87e)

#### [v7.4.0-canary.3](https://github.com/microsoft/tabster/compare/v7.4.0-canary.2...v7.4.0-canary.3)

> 14 August 2024

- Release 7.4.0-canary.3 [`9be52de`](https://github.com/microsoft/tabster/commit/9be52dea628bb2e72eae50a8ba381ff24c520acb)
- Removing extra condition for activating modalizer. [`2d53cd1`](https://github.com/microsoft/tabster/commit/2d53cd13a922955ad3a62e870985ba25146e67b2)

#### [v7.4.0-canary.2](https://github.com/microsoft/tabster/compare/v7.4.0-canary.1...v7.4.0-canary.2)

> 13 August 2024

- Deactivating only modals that share the same element with groupper when the element gets focused. [`4a15750`](https://github.com/microsoft/tabster/commit/4a15750ad79dd5da506b925079ba44aaf23844f6)
- Release 7.4.0-canary.2 [`2ab0fd2`](https://github.com/microsoft/tabster/commit/2ab0fd2dcdc5d9d680cc4355934cfbacc8442d88)

#### [v7.4.0-canary.1](https://github.com/microsoft/tabster/compare/v7.4.0-canary.0...v7.4.0-canary.1)

> 13 August 2024

- Looking for a parent modalizer when deactivating modalizer on focused element. [`f00ff03`](https://github.com/microsoft/tabster/commit/f00ff038e3a93a393dd7818d5c13ea5a8cd1a123)
- Release 7.4.0-canary.1 [`d69e61b`](https://github.com/microsoft/tabster/commit/d69e61b3c02ae861198f86fd7f652bc6c0d54751)

#### [v7.4.0-canary.0](https://github.com/microsoft/tabster/compare/v7.3.0...v7.4.0-canary.0)

> 1 August 2024

- fix(Groupper, Modalizer): Consolidating and making consistent how Groupper and Modalizer are activated on different interactions. [`e7aeede`](https://github.com/microsoft/tabster/commit/e7aeede77566b6beb8270384a3e702eadf2c95dc)
- Release 7.4.0-canary.0 [`130a19f`](https://github.com/microsoft/tabster/commit/130a19f2bf4ccd3a306ccc1ea16b4318927c9a71)

#### [v7.3.0](https://github.com/microsoft/tabster/compare/v7.2.0...v7.3.0)

> 12 June 2024
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tabster",
"version": "8.0.1",
"version": "8.1.0-canary.0",
"description": "Focus Management Tools for Web",
"author": "Marat Abdullin <marata@microsoft.com>",
"license": "MIT",
Expand Down
68 changes: 30 additions & 38 deletions src/Groupper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,9 @@ export class GroupperAPI implements Types.GroupperAPI {
validateGroupperProps(props);
}

const tabster = this._tabster;
const newGroupper = new Groupper(
this._tabster,
tabster,
element,
this._onGroupperDispose,
props,
Expand All @@ -505,7 +506,7 @@ export class GroupperAPI implements Types.GroupperAPI {

this._grouppers[newGroupper.id] = newGroupper;

const focusedElement = this._tabster.focusedElement.getFocusedElement();
const focusedElement = tabster.focusedElement.getFocusedElement();

// Newly created groupper contains currently focused element, update the state on the next tick (to
// make sure all grouppers are processed).
Expand All @@ -519,9 +520,9 @@ export class GroupperAPI implements Types.GroupperAPI {
// Making sure the focused element hasn't changed.
if (
focusedElement ===
this._tabster.focusedElement.getFocusedElement()
tabster.focusedElement.getFocusedElement()
) {
this._updateCurrent(focusedElement, true, true);
this._updateCurrent(focusedElement);
}
}, 0);
}
Expand All @@ -539,56 +540,52 @@ export class GroupperAPI implements Types.GroupperAPI {

private _onFocus = (element: HTMLElement | undefined): void => {
if (element) {
this._updateCurrent(element, true, true);
this._updateCurrent(element);
}
};

private _onMouseDown = (e: MouseEvent): void => {
if (e.target) {
this._updateCurrent(e.target as HTMLElement, true);
let target = e.target as HTMLElement | null;

while (target && !this._tabster.focusable.isFocusable(target)) {
target = this._tabster.getParent(target) as HTMLElement | null;
}

if (target) {
this._updateCurrent(target);
}
};

private _updateCurrent(
element: HTMLElement,
includeTarget?: boolean,
checkTarget?: boolean
): void {
private _updateCurrent(element: HTMLElement): void {
if (this._updateTimer) {
this._win().clearTimeout(this._updateTimer);
delete this._updateTimer;
}

const tabster = this._tabster;
const newIds: Record<string, true> = {};

let isTarget = true;

for (
let el = element as HTMLElement | null;
let el = tabster.getParent(element);
el;
el = dom.getParentElement(el)
el = tabster.getParent(el)
) {
const groupper = getTabsterOnElement(this._tabster, el)?.groupper;
const groupper = getTabsterOnElement(
tabster,
el as HTMLElement
)?.groupper;

if (groupper) {
newIds[groupper.id] = true;

if (isTarget && checkTarget && el !== element) {
isTarget = false;
}

if (includeTarget || !isTarget) {
this._current[groupper.id] = groupper;
const isTabbable =
groupper.isActive() ||
(element !== el &&
(!groupper.getProps().delegated ||
groupper.getFirst(false) !== element));
this._current[groupper.id] = groupper;
const isTabbable =
groupper.isActive() ||
(element !== el &&
(!groupper.getProps().delegated ||
groupper.getFirst(false) !== element));

groupper.makeTabbable(isTabbable);
}

isTarget = false;
groupper.makeTabbable(isTabbable);
}
}

Expand Down Expand Up @@ -695,8 +692,7 @@ export class GroupperAPI implements Types.GroupperAPI {
): HTMLElement | null {
const tabster = this._tabster;
const ctx = RootAPI.getTabsterContext(tabster, element);
const modalizerInGroupper = ctx?.modalizerInGroupper;
let groupper = ctx?.groupper || modalizerInGroupper;
let groupper = ctx?.groupper || ctx?.modalizerInGroupper;
const groupperElement = groupper?.getElement();

if (
Expand Down Expand Up @@ -733,10 +729,6 @@ export class GroupperAPI implements Types.GroupperAPI {
) {
if (groupper) {
groupper.makeTabbable(false);

if (modalizerInGroupper) {
tabster.modalizer?.setActive(undefined);
}
}

// This part happens asynchronously inside setTimeout,
Expand Down
77 changes: 50 additions & 27 deletions src/Modalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,11 @@ export class ModalizerAPI implements Types.ModalizerAPI {
}
part[id] = modalizer;

const focusedElement =
this._tabster.focusedElement.getFocusedElement() ?? null;

// Adding a modalizer which is already focused, activate it
if (
dom.nodeContains(
element,
this._tabster.focusedElement.getFocusedElement() ?? null
)
) {
if (dom.nodeContains(element, focusedElement)) {
if (userId !== this.activeId) {
this.setActive(modalizer);
} else {
Expand Down Expand Up @@ -499,7 +497,7 @@ export class ModalizerAPI implements Types.ModalizerAPI {

if (el) {
groupper = getTabsterOnElement(
this._tabster,
tabster,
el
)?.groupper;
}
Expand Down Expand Up @@ -593,10 +591,8 @@ export class ModalizerAPI implements Types.ModalizerAPI {
noFocusFirst?: boolean,
noFocusDefault?: boolean
): boolean {
const ctx = RootAPI.getTabsterContext(
this._tabster,
elementFromModalizer
);
const tabster = this._tabster;
const ctx = RootAPI.getTabsterContext(tabster, elementFromModalizer);

const modalizer = ctx?.modalizer;

Expand All @@ -613,8 +609,8 @@ export class ModalizerAPI implements Types.ModalizerAPI {

if (
!noFocusFirst &&
this._tabster.keyboardNavigation.isNavigatingWithKeyboard() &&
this._tabster.focusedElement.focusFirst({
tabster.keyboardNavigation.isNavigatingWithKeyboard() &&
tabster.focusedElement.focusFirst({
container: modalizerRoot,
})
) {
Expand All @@ -627,12 +623,12 @@ export class ModalizerAPI implements Types.ModalizerAPI {

if (
!noFocusDefault &&
this._tabster.focusedElement.focusDefault(modalizerRoot)
tabster.focusedElement.focusDefault(modalizerRoot)
) {
return true;
}

this._tabster.focusedElement.resetFocus(modalizerRoot);
tabster.focusedElement.resetFocus(modalizerRoot);
}
} else if (__DEV__) {
console.error("Element is not in Modalizer.", elementFromModalizer);
Expand Down Expand Up @@ -840,9 +836,10 @@ export class ModalizerAPI implements Types.ModalizerAPI {
focusedElement: HTMLElement | undefined,
detail: Types.FocusedElementDetail
): void => {
const tabster = this._tabster;
const ctx =
focusedElement &&
RootAPI.getTabsterContext(this._tabster, focusedElement);
RootAPI.getTabsterContext(tabster, focusedElement);

// Modalizer behaviour is opt in, only apply to elements that have a tabster context
if (!ctx || !focusedElement) {
Expand All @@ -854,7 +851,7 @@ export class ModalizerAPI implements Types.ModalizerAPI {
for (
let e: HTMLElement | null = focusedElement;
e;
e = dom.getParentElement(e)
e = tabster.getParent(e) as HTMLElement | null
) {
// If the newly focused element is inside some of the hidden containers,
// remove aria-hidden from those synchronously for the screen readers
Expand All @@ -863,18 +860,43 @@ export class ModalizerAPI implements Types.ModalizerAPI {

if (augmentedMap.has(e)) {
augmentedMap.delete(e);
augmentAttribute(this._tabster, e, _ariaHidden);
augmentAttribute(tabster, e, _ariaHidden);
}
}

const modalizer = ctx.modalizer;
let modalizer = ctx.modalizer;

const tabsterOnFocusedElement = getTabsterOnElement(
tabster,
focusedElement
);
const modalizerOnFocusedElement = tabsterOnFocusedElement?.modalizer;

if (modalizerOnFocusedElement) {
modalizerOnFocusedElement.focused();

if (
modalizerOnFocusedElement.userId === this.activeId &&
tabsterOnFocusedElement.groupper
) {
const parentElement = tabster.getParent(focusedElement);
const parentModalizer =
parentElement &&
RootAPI.getTabsterContext(tabster, parentElement)
?.modalizer;

if (parentModalizer) {
modalizer = parentModalizer;
} else {
this.setActive(undefined);
return;
}
}
}

// An inactive groupper with the modalizer on the same node will not give the modalizer
// in the context, yet we still want to track that the modalizer's container was focused.
(
modalizer ||
getTabsterOnElement(this._tabster, focusedElement)?.modalizer
)?.focused();
modalizer?.focused();

if (modalizer?.userId === this.activeId) {
this.currentIsOthersAccessible =
Expand Down Expand Up @@ -917,7 +939,8 @@ export class ModalizerAPI implements Types.ModalizerAPI {
return;
}

const ctx = RootAPI.getTabsterContext(this._tabster, outsideElement);
const tabster = this._tabster;
const ctx = RootAPI.getTabsterContext(tabster, outsideElement);
const modalizer = ctx?.modalizer;
const activeId = this.activeId;

Expand All @@ -931,7 +954,7 @@ export class ModalizerAPI implements Types.ModalizerAPI {
const container = ctx?.root.getElement();

if (container) {
let toFocus = this._tabster.focusable.findFirst({
let toFocus = tabster.focusable.findFirst({
container,
useActiveModalizer: true,
});
Expand All @@ -941,7 +964,7 @@ export class ModalizerAPI implements Types.ModalizerAPI {
outsideElement.compareDocumentPosition(toFocus) &
document.DOCUMENT_POSITION_PRECEDING
) {
toFocus = this._tabster.focusable.findLast({
toFocus = tabster.focusable.findLast({
container,
useActiveModalizer: true,
});
Expand All @@ -952,7 +975,7 @@ export class ModalizerAPI implements Types.ModalizerAPI {
}
}

this._tabster.focusedElement.focus(toFocus);
tabster.focusedElement.focus(toFocus);

return;
}
Expand Down
Loading
Loading