Skip to content

Commit

Permalink
perf: reduce unnecessary work
Browse files Browse the repository at this point in the history
- reduce unnecessary queries when live regions are not tracked
- narrow scope of queries when possible
  • Loading branch information
AriPerkkio committed Feb 11, 2022
1 parent ae1b4a2 commit 4a3b523
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 11 deletions.
8 changes: 8 additions & 0 deletions .storybook/preview.ts
@@ -1,3 +1,6 @@
import { addons } from '@storybook/addons';
import { STORY_CHANGED } from '@storybook/core-events';

import CaptureAnnouncements from '../src';
import prettyDOMWithShadowDOM from './pretty-dom-with-shadow-dom';
import { AnnouncementEvents, SourceCodeUpdateEvents } from './utils';
Expand All @@ -8,6 +11,11 @@ CaptureAnnouncements({
onCapture: (text, level) => AnnouncementEvents.emit({ text, level }),
});

addons.getChannel().addListener(STORY_CHANGED, () => {
// Reset captures after a story changes
AnnouncementEvents.clear();
});

export const decorators = [
function withSourceCode(Story: StoryFn) {
const html = Story();
Expand Down
7 changes: 7 additions & 0 deletions .storybook/utils.ts
Expand Up @@ -83,9 +83,11 @@ export function createButtonCycle(
type Subscriber<T> = (event: T) => void;
class EventBus<EventType = undefined> {
subscribers: Subscriber<EventType>[] = [];
events: EventType[] = [];

on(subscriber: Subscriber<EventType>) {
this.subscribers.push(subscriber);
this.events.forEach(subscriber);
}

off(subscriber: Subscriber<EventType>) {
Expand All @@ -94,6 +96,11 @@ class EventBus<EventType = undefined> {

emit(event?: EventType) {
this.subscribers.forEach(subscriber => subscriber(event));
this.events.push(event);
}

clear() {
this.events = [];
}
}

Expand Down
20 changes: 13 additions & 7 deletions src/capture-announcements.ts
Expand Up @@ -43,6 +43,8 @@ export default function CaptureAnnouncements(options: Options): Restore {
* - `textContent` of live region should have changed
*/
function updateAnnouncements(node: Node) {
if (liveRegions.size === 0) return;

const element = getClosestElement(node);
if (!element) return;

Expand Down Expand Up @@ -93,8 +95,10 @@ export default function CaptureAnnouncements(options: Options): Restore {
* Check DOM for live regions and update `liveRegions` store
* - TODO: Could be optimized based on appended/updated child
*/
function updateLiveRegions() {
for (const liveRegion of getAllLiveRegions(document)) {
function updateLiveRegions(node: Node) {
const context = isElement(node) ? node : document;

for (const liveRegion of getAllLiveRegions(context)) {
addLiveRegion(liveRegion);
}
}
Expand All @@ -103,7 +107,6 @@ export default function CaptureAnnouncements(options: Options): Restore {
updateAnnouncements(this);
}

// https://github.com/facebook/react/blob/9198a5cec0936a21a5ba194a22fcbac03eba5d1d/packages/react-dom/src/client/setTextContent.js#L12-L35
function onNodeValueChange(this: Node) {
updateAnnouncements(this);
}
Expand All @@ -112,7 +115,7 @@ export default function CaptureAnnouncements(options: Options): Restore {
* Shared handler for methods which mount new nodes on DOM, e.g. appendChild, insertBefore
*/
function onNodeMount(node: Node) {
updateLiveRegions();
updateLiveRegions(node);
updateAnnouncements(node);
}

Expand Down Expand Up @@ -145,7 +148,7 @@ export default function CaptureAnnouncements(options: Options): Restore {

// Previous value was not live region attribute value
if (!isAlreadyTracked && liveRegionAttribute) {
return updateLiveRegions();
return updateLiveRegions(this);
}

// Value was changed to assertive - announce content immediately
Expand All @@ -160,7 +163,7 @@ export default function CaptureAnnouncements(options: Options): Restore {
}

case 'aria-hidden': {
updateLiveRegions();
updateLiveRegions(this);
return updateAnnouncements(this);
}

Expand All @@ -181,7 +184,7 @@ export default function CaptureAnnouncements(options: Options): Restore {
const [attribute] = args;

if (attribute === 'aria-hidden') {
updateLiveRegions();
updateLiveRegions(this);
updateAnnouncements(this);
}
}
Expand All @@ -190,6 +193,8 @@ export default function CaptureAnnouncements(options: Options): Restore {
this: Element,
...args: Parameters<Element['removeChild']>
) {
if (liveRegions.size === 0) return;

const [node] = args;

if (node == null || !isElement(node)) {
Expand Down Expand Up @@ -241,6 +246,7 @@ function onRemoveAttributeBefore(
this: Element,
...args: Parameters<Element['removeAttribute']>
) {
if (liveRegions.size === 0) return;
if (!isElement(this)) return;

const [attribute] = args;
Expand Down
21 changes: 17 additions & 4 deletions src/utils.ts
Expand Up @@ -20,10 +20,19 @@ const LIVE_REGION_QUERY = [

const HIDDEN_QUERY = '[aria-hidden="true"]';

export function getAllLiveRegions(
context: Document | Element
): ReturnType<typeof context['querySelectorAll']> {
return context.querySelectorAll(LIVE_REGION_QUERY);
export function getAllLiveRegions(context: Document | Element): Element[] {
const liveRegions = Array.from(context.querySelectorAll(LIVE_REGION_QUERY));

// Check whether given `context` is also a live region
if (
isElement(context) &&
resolvePolitenessSetting(context) !== 'off' &&
isInDOM(context)
) {
return liveRegions.concat(context).filter(filterUnique);
}

return liveRegions;
}

export function getClosestElement(node: Node): Element | null {
Expand Down Expand Up @@ -142,3 +151,7 @@ export function getTextContent(node: Node | null): string | null {
.join(' ')
);
}

function filterUnique<T>(item: T, index: number, array: T[]): boolean {
return array.indexOf(item) === index;
}

0 comments on commit 4a3b523

Please sign in to comment.