Skip to content

Commit 6d3d033

Browse files
authored
[🚑️][Dialog]: Hotfix an issue that caused the focus trap to not work properly (#90)
1 parent c26c76a commit 6d3d033

File tree

6 files changed

+74
-36
lines changed

6 files changed

+74
-36
lines changed

‎lib/Dialog/Dialog.tsx

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import * as React from "react";
22
import Portal from "../Portal";
33
import {
4+
FocusTrap,
45
SystemError,
56
SystemKeys,
67
resolvePropWithRenderContext,
78
} from "../internals";
89
import type { MergeElementProps, PropWithRenderContext } from "../types";
910
import {
1011
componentWithForwardedRef,
12+
getScrollingState,
1113
useDeterministicId,
1214
useEventListener,
1315
useIsMounted,
@@ -97,7 +99,9 @@ const DialogBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
9799
previouslyFocusedElement.current =
98100
document.activeElement as HTMLElement | null;
99101

100-
disablePageScroll();
102+
const isBodyScrolling = getScrollingState(document.body).vertical;
103+
104+
if (isBodyScrolling) disablePageScroll();
101105
} else {
102106
enablePageScroll();
103107

@@ -127,9 +131,11 @@ const DialogBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
127131
target: document,
128132
eventType: "keydown",
129133
handler: event => {
130-
event.preventDefault();
134+
if (event.key === SystemKeys.ESCAPE) {
135+
event.preventDefault();
131136

132-
if (event.key === SystemKeys.ESCAPE) emitClose();
137+
emitClose();
138+
}
133139
},
134140
},
135141
open,
@@ -140,26 +146,28 @@ const DialogBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
140146

141147
return (
142148
<Portal>
143-
<div
144-
data-slot="Portal:Root"
145-
role="presentation"
146-
tabIndex={-1}
147-
aria-hidden={!open}
148-
style={{ position: "absolute", top: 0, left: 0, right: 0 }}
149-
>
149+
<FocusTrap enabled={open}>
150150
<div
151-
{...otherProps}
152-
id={id}
153-
ref={ref}
154-
className={className}
155-
data-slot={RootSlot}
156-
data-open={open ? "" : undefined}
151+
data-slot="Portal:Root"
152+
role="presentation"
153+
tabIndex={-1}
154+
aria-hidden={!open}
155+
style={{ position: "absolute", top: 0, left: 0, right: 0 }}
157156
>
158-
<DialogContext.Provider value={context}>
159-
{children}
160-
</DialogContext.Provider>
157+
<div
158+
{...otherProps}
159+
id={id}
160+
ref={ref}
161+
className={className}
162+
data-slot={RootSlot}
163+
data-open={open ? "" : undefined}
164+
>
165+
<DialogContext.Provider value={context}>
166+
{children}
167+
</DialogContext.Provider>
168+
</div>
161169
</div>
162-
</div>
170+
</FocusTrap>
163171
</Portal>
164172
);
165173
};

‎lib/Dialog/components/Content.tsx

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from "react";
22
import { logger } from "../../internals";
3-
import FocusTrap from "../../internals/FocusTrap";
43
import type { MergeElementProps } from "../../types";
54
import { componentWithForwardedRef, useDeterministicId } from "../../utils";
65
import { DialogContext } from "../context";
@@ -39,19 +38,17 @@ const ContentBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
3938
}
4039

4140
return (
42-
<FocusTrap enabled={ctx.open}>
43-
<div
44-
{...otherProps}
45-
id={id}
46-
ref={ref}
47-
className={className}
48-
role={ctx.role}
49-
data-slot={ContentRootSlot}
50-
aria-modal="true"
51-
>
52-
{children}
53-
</div>
54-
</FocusTrap>
41+
<div
42+
{...otherProps}
43+
id={id}
44+
ref={ref}
45+
className={className}
46+
role={ctx.role}
47+
data-slot={ContentRootSlot}
48+
aria-modal="true"
49+
>
50+
{children}
51+
</div>
5552
);
5653
};
5754

‎lib/Menu/BaseMenu.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const BaseMenuBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
6060
</div>
6161
);
6262

63-
if (trapFocus)
63+
if (trapFocus) {
6464
return (
6565
<FocusTrap
6666
enabled={open}
@@ -69,6 +69,7 @@ const BaseMenuBase = (props: Props, ref: React.Ref<HTMLDivElement>) => {
6969
{renderMenu()}
7070
</FocusTrap>
7171
);
72+
}
7273

7374
return renderMenu();
7475
};

‎lib/utils/get-scrolling-state.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const getScrollingState = (element: HTMLElement) => {
2+
const isScrollable = (node: HTMLElement) => {
3+
const overflow = getComputedStyle(node).getPropertyValue("overflow");
4+
5+
return overflow.includes("auto") || overflow.includes("scroll");
6+
};
7+
8+
const getScrollParent = (element: HTMLElement) => {
9+
let current = element.parentNode as HTMLElement | null;
10+
11+
while (current) {
12+
if (!(element instanceof HTMLElement)) break;
13+
if (!(element instanceof SVGElement)) break;
14+
15+
if (isScrollable(current)) return current;
16+
17+
current = current.parentNode as HTMLElement | null;
18+
}
19+
20+
return document.scrollingElement || document.documentElement;
21+
};
22+
23+
const scrollParent = getScrollParent(element);
24+
25+
return {
26+
vertical: scrollParent.scrollHeight > scrollParent.clientHeight,
27+
horizontal: scrollParent.scrollWidth > scrollParent.clientWidth,
28+
};
29+
};
30+
31+
export default getScrollingState;

‎lib/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export { default as createVirtualElement } from "./create-virtual-element";
1717
export { default as dispatchDiscreteCustomEvent } from "./dispatch-discrete-custom-event";
1818
export * from "./dom";
1919
export { default as forkRefs } from "./fork-refs";
20+
export { default as getScrollingState } from "./get-scrolling-state";
2021
export * from "./is";
2122
export * from "./math";
2223
export { default as requestFormSubmit } from "./request-form-submit";

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@styleless-ui/react",
3-
"version": "1.0.0-rc.1",
3+
"version": "1.0.0-rc.2",
44
"description": "Completely unstyled, headless and accessible React UI components.",
55
"author": "mimshins <mostafa.sh.coderino@gmail.com>",
66
"license": "MIT",

0 commit comments

Comments
 (0)