Skip to content

Commit

Permalink
Add dialog-next-router example (#2369)
Browse files Browse the repository at this point in the history
This PR adds a new example to the site using Next.js App Router. The
example is presented within an iframe with a chrome bar.

Alongside this, a few adjustments were made to the `Dialog` component:

- Fixed `DialogBackdrop` not including the `data-backdrop` attribute in
the initial render, causing a flash of unstyled content when the dialog
is initially open.
- Fixed `Dialog` calling `hideOnInteractOutside` twice when clicking on
the backdrop.
- The built-in `DialogBackdrop` component is no longer focusable.
- Call `autoFocusOnHide` and `autoFocusOnShow` with a `null` argument
when there's no element to focus or the element is not focusable. This
allows users to specify a fallback element to focus on hide or show.

These changes should make it easier to control the Dialog using the
Next.js App Router.
  • Loading branch information
diegohaz committed May 6, 2023
1 parent a835224 commit 30d5bca
Show file tree
Hide file tree
Showing 50 changed files with 837 additions and 268 deletions.
6 changes: 6 additions & 0 deletions .changeset/dialog-backdrop-data-attribute.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ariakit/react-core": patch
"@ariakit/react": patch
---

Fixed `DialogBackdrop` not including the `data-backdrop` attribute in the initial render, causing a flash of unstyled content when the dialog is initially open. ([#2369](https://github.com/ariakit/ariakit/pull/2369))
6 changes: 6 additions & 0 deletions .changeset/dialog-backdrop-duplicate-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ariakit/react-core": patch
"@ariakit/react": patch
---

Fixed `Dialog` calling `hideOnInteractOutside` twice when clicking on the backdrop. ([#2369](https://github.com/ariakit/ariakit/pull/2369))
6 changes: 6 additions & 0 deletions .changeset/dialog-backdrop-tabindex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ariakit/react-core": patch
"@ariakit/react": patch
---

The built-in `DialogBackdrop` component is no longer focusable. ([#2369](https://github.com/ariakit/ariakit/pull/2369))
6 changes: 6 additions & 0 deletions .changeset/dialog-final-focus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ariakit/react-core": patch
"@ariakit/react": patch
---

Call `autoFocusOnHide` and `autoFocusOnShow` with a `null` argument when there's no element to focus or the element is not focusable. This allows users to specify a fallback element to focus on hide or show. ([#2369](https://github.com/ariakit/ariakit/pull/2369))
99 changes: 54 additions & 45 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
Expand Up @@ -116,7 +116,7 @@
"monaco-editor-webpack-plugin": "7.0.1",
"monaco-textmate": "3.0.1",
"monaco-vscode-textmate-theme-converter": "0.1.7",
"next": "13.3.4",
"next": "13.4.1",
"null-loader": "4.0.1",
"onigasm": "2.2.5",
"open-cli": "7.2.0",
Expand Down
1 change: 1 addition & 0 deletions packages/ariakit-react-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
"./dialog/utils/prepend-hidden-dismiss": "./src/dialog/utils/prepend-hidden-dismiss.ts",
"./dialog/utils/orchestrate": "./src/dialog/utils/orchestrate.ts",
"./dialog/utils/mark-tree-outside": "./src/dialog/utils/mark-tree-outside.ts",
"./dialog/utils/is-backdrop": "./src/dialog/utils/is-backdrop.ts",
"./dialog/utils/disable-tree-outside": "./src/dialog/utils/disable-tree-outside.ts",
"./dialog/utils/disable-accessibility-tree-outside": "./src/dialog/utils/disable-accessibility-tree-outside.ts",
"./dialog/dialog": "./src/dialog/dialog.tsx",
Expand Down
70 changes: 15 additions & 55 deletions packages/ariakit-react-core/src/dialog/dialog-backdrop.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
import type {
KeyboardEvent,
MouseEvent as ReactMouseEvent,
ReactNode,
} from "react";
import type { ReactNode } from "react";
import { useMemo, useRef } from "react";
import { isSelfTarget } from "@ariakit/core/utils/events";
import { noop } from "@ariakit/core/utils/misc";
import { useDisclosureContent } from "../disclosure/disclosure-content.js";
import {
useBooleanEvent,
useEvent,
useForkRef,
useSafeLayoutEffect,
} from "../utils/hooks.js";
import { useForkRef, useSafeLayoutEffect } from "../utils/hooks.js";
import type { DialogProps } from "./dialog.js";
import { usePreviousMouseDownRef } from "./utils/use-previous-mouse-down-ref.js";
import { markAncestor } from "./utils/mark-tree-outside.js";

type DialogBackdropProps = Pick<
DialogProps,
| "store"
| "backdrop"
| "backdropProps"
| "hideOnInteractOutside"
| "hideOnEscape"
| "hidden"
"store" | "backdrop" | "backdropProps" | "hidden"
> & {
children?: ReactNode;
};
Expand All @@ -32,8 +17,6 @@ export function DialogBackdrop({
store,
backdrop,
backdropProps,
hideOnInteractOutside = true,
hideOnEscape = true,
hidden,
children,
}: DialogBackdropProps) {
Expand All @@ -59,47 +42,24 @@ export function DialogBackdrop({
backdrop.style.zIndex = getComputedStyle(dialog).zIndex;
}, [contentElement]);

const onClickProp = backdropProps?.onClick;
const hideOnInteractOutsideProp = useBooleanEvent(hideOnInteractOutside);
const mounted = store.useState("mounted");
const previousMouseDownRef = usePreviousMouseDownRef(mounted);

const onClick = useEvent((event: ReactMouseEvent<HTMLDivElement>) => {
onClickProp?.(event);
if (event.defaultPrevented) return;
if (!isSelfTarget(event)) return;
if (previousMouseDownRef.current !== event.currentTarget) return;
if (!hideOnInteractOutsideProp(event)) return;
event.stopPropagation();
store.hide();
});

const onKeyDownProp = backdropProps?.onKeyDown;
const hideOnEscapeProp = useBooleanEvent(hideOnEscape);

// When hideOnInteractOutside is false and the backdrop is clicked, the
// backdrop will receive focus (because we set the tabIndex on it). Therefore,
// the Escape key will not be captured by the Dialog component. So we listen
// to it here.
const onKeyDown = useEvent((event: KeyboardEvent<HTMLDivElement>) => {
onKeyDownProp?.(event);
if (event.defaultPrevented) return;
if (event.key !== "Escape") return;
if (!isSelfTarget(event)) return;
if (!hideOnEscapeProp(event)) return;
store.hide();
});
// Mark the backdrop element as an ancestor of the dialog, otherwise clicking
// on it won't close the dialog when the dialog uses portal, in which case
// elements are only marked outside the portal element.
useSafeLayoutEffect(() => {
const id = contentElement?.id;
if (!id) return;
const backdrop = ref.current;
if (!backdrop) return;
return markAncestor(backdrop, id);
}, [contentElement]);

const props = useDisclosureContent({
store,
id: undefined,
role: "presentation",
tabIndex: -1,
hidden,
...backdropProps,
ref: useForkRef(backdropProps?.ref, ref),
onClick,
onKeyDown,
style: {
position: "fixed",
top: 0,
Expand All @@ -113,7 +73,7 @@ export function DialogBackdrop({
const Component = typeof backdrop !== "boolean" ? backdrop || "div" : "div";

return (
<Component {...props} data-backdrop={contentElement?.id}>
<Component {...props} data-backdrop={contentElement?.id || ""}>
{children}
</Component>
);
Expand Down

1 comment on commit 30d5bca

@vercel
Copy link

@vercel vercel bot commented on 30d5bca May 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

ariakit – ./

ariakit-git-main-ariakit.vercel.app
ariakit-ariakit.vercel.app
www.ariakit.org
ariakit.org

Please sign in to comment.