Mirror: React hooks for accessible, common web interactions. UI super powers without the UI.

Update selection restore handling for modals

+4 -4
src/useDialogFocus.ts
···
document.addEventListener('keydown', onKey);
return () => {
const active = document.activeElement as HTMLElement;
if (!active || contains(element, active)) {
restoreSelection(selection);
}
-
-
element.removeEventListener('mousedown', onClick);
-
document.body.removeEventListener('focusin', onFocus);
-
document.removeEventListener('keydown', onKey);
};
}, [ref.current, disabled]);
}
···
document.addEventListener('keydown', onKey);
return () => {
+
element.removeEventListener('mousedown', onClick);
+
document.body.removeEventListener('focusin', onFocus);
+
document.removeEventListener('keydown', onKey);
+
const active = document.activeElement as HTMLElement;
if (!active || contains(element, active)) {
restoreSelection(selection);
}
};
}, [ref.current, disabled]);
}
+3 -3
src/useMenuFocus.ts
···
document.addEventListener('keydown', onKey);
return () => {
const active = document.activeElement as HTMLElement;
if (!active || contains(element, active)) {
restoreSelection(selection);
}
-
-
document.body.removeEventListener('focusin', onFocus);
-
document.removeEventListener('keydown', onKey);
};
}, [ref.current, disabled]);
}
···
document.addEventListener('keydown', onKey);
return () => {
+
document.body.removeEventListener('focusin', onFocus);
+
document.removeEventListener('keydown', onKey);
+
const active = document.activeElement as HTMLElement;
if (!active || contains(element, active)) {
restoreSelection(selection);
}
};
}, [ref.current, disabled]);
}
+12 -8
src/useModalFocus.ts
···
const hasPriority = usePriority(ref, disabled);
useLayoutEffect(() => {
-
const { current: element } = ref;
-
if (!element || disabled) return;
let selection: RestoreSelection | null = null;
-
if (!document.activeElement || !contains(element, document.activeElement)) {
-
const newTarget = getAutofocusTarget(element);
-
selection = snapshotSelection(element);
-
newTarget.focus();
}
function onBlur(event: FocusEvent) {
if (!hasPriority.current || !element || event.defaultPrevented) return;
if (
···
}
function onKeyDown(event: KeyboardEvent) {
if (!hasPriority.current || !element || event.defaultPrevented) return;
if (event.code === 'Tab') {
···
document.addEventListener('keydown', onKeyDown);
return () => {
-
restoreSelection(selection);
document.body.removeEventListener('focusout', onBlur);
document.removeEventListener('keydown', onKeyDown);
};
-
}, [ref.current, hasPriority, disabled]);
}
···
const hasPriority = usePriority(ref, disabled);
useLayoutEffect(() => {
+
if (disabled) return;
let selection: RestoreSelection | null = null;
+
if (
+
!document.activeElement ||
+
!contains(ref.current, document.activeElement)
+
) {
+
const newTarget = ref.current ? getAutofocusTarget(ref.current) : null;
+
selection = snapshotSelection();
+
if (newTarget) newTarget.focus();
}
function onBlur(event: FocusEvent) {
+
const { current: element } = ref;
if (!hasPriority.current || !element || event.defaultPrevented) return;
if (
···
}
function onKeyDown(event: KeyboardEvent) {
+
const { current: element } = ref;
if (!hasPriority.current || !element || event.defaultPrevented) return;
if (event.code === 'Tab') {
···
document.addEventListener('keydown', onKeyDown);
return () => {
document.body.removeEventListener('focusout', onBlur);
document.removeEventListener('keydown', onKeyDown);
+
restoreSelection(selection);
};
+
}, [ref, hasPriority, disabled]);
}