package.dist.index.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dialog Show documentation
Show all versions of dialog Show documentation
Core logic for the dialog widget implemented as a state machine
The newest version!
'use strict';
var anatomy$1 = require('@zag-js/anatomy');
var domQuery = require('@zag-js/dom-query');
var ariaHidden = require('@zag-js/aria-hidden');
var core = require('@zag-js/core');
var dismissable = require('@zag-js/dismissable');
var removeScroll = require('@zag-js/remove-scroll');
var utils = require('@zag-js/utils');
var focusTrap = require('focus-trap');
var types = require('@zag-js/types');
// src/dialog.anatomy.ts
var anatomy = anatomy$1.createAnatomy("dialog").parts(
"trigger",
"backdrop",
"positioner",
"content",
"title",
"description",
"closeTrigger"
);
var parts = anatomy.build();
var dom = domQuery.createScope({
getPositionerId: (ctx) => ctx.ids?.positioner ?? `dialog:${ctx.id}:positioner`,
getBackdropId: (ctx) => ctx.ids?.backdrop ?? `dialog:${ctx.id}:backdrop`,
getContentId: (ctx) => ctx.ids?.content ?? `dialog:${ctx.id}:content`,
getTriggerId: (ctx) => ctx.ids?.trigger ?? `dialog:${ctx.id}:trigger`,
getTitleId: (ctx) => ctx.ids?.title ?? `dialog:${ctx.id}:title`,
getDescriptionId: (ctx) => ctx.ids?.description ?? `dialog:${ctx.id}:description`,
getCloseTriggerId: (ctx) => ctx.ids?.closeTrigger ?? `dialog:${ctx.id}:close`,
getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
getBackdropEl: (ctx) => dom.getById(ctx, dom.getBackdropId(ctx)),
getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
getTitleEl: (ctx) => dom.getById(ctx, dom.getTitleId(ctx)),
getDescriptionEl: (ctx) => dom.getById(ctx, dom.getDescriptionId(ctx)),
getCloseTriggerEl: (ctx) => dom.getById(ctx, dom.getCloseTriggerId(ctx))
});
// src/dialog.connect.ts
function connect(state, send, normalize) {
const ariaLabel = state.context["aria-label"];
const open = state.matches("open");
const rendered = state.context.renderedElements;
return {
open,
setOpen(nextOpen) {
if (nextOpen === open) return;
send(nextOpen ? "OPEN" : "CLOSE");
},
getTriggerProps() {
return normalize.button({
...parts.trigger.attrs,
dir: state.context.dir,
id: dom.getTriggerId(state.context),
"aria-haspopup": "dialog",
type: "button",
"aria-expanded": open,
"data-state": open ? "open" : "closed",
"aria-controls": dom.getContentId(state.context),
onClick(event) {
if (event.defaultPrevented) return;
send("TOGGLE");
}
});
},
getBackdropProps() {
return normalize.element({
...parts.backdrop.attrs,
dir: state.context.dir,
hidden: !open,
id: dom.getBackdropId(state.context),
"data-state": open ? "open" : "closed"
});
},
getPositionerProps() {
return normalize.element({
...parts.positioner.attrs,
dir: state.context.dir,
id: dom.getPositionerId(state.context),
style: {
pointerEvents: open ? void 0 : "none"
}
});
},
getContentProps() {
return normalize.element({
...parts.content.attrs,
dir: state.context.dir,
role: state.context.role,
hidden: !open,
id: dom.getContentId(state.context),
tabIndex: -1,
"data-state": open ? "open" : "closed",
"aria-modal": true,
"aria-label": ariaLabel || void 0,
"aria-labelledby": ariaLabel || !rendered.title ? void 0 : dom.getTitleId(state.context),
"aria-describedby": rendered.description ? dom.getDescriptionId(state.context) : void 0
});
},
getTitleProps() {
return normalize.element({
...parts.title.attrs,
dir: state.context.dir,
id: dom.getTitleId(state.context)
});
},
getDescriptionProps() {
return normalize.element({
...parts.description.attrs,
dir: state.context.dir,
id: dom.getDescriptionId(state.context)
});
},
getCloseTriggerProps() {
return normalize.button({
...parts.closeTrigger.attrs,
dir: state.context.dir,
id: dom.getCloseTriggerId(state.context),
type: "button",
onClick(event) {
if (event.defaultPrevented) return;
event.stopPropagation();
send("CLOSE");
}
});
}
};
}
function machine(userContext) {
const ctx = utils.compact(userContext);
return core.createMachine(
{
id: "dialog",
initial: ctx.open ? "open" : "closed",
context: {
role: "dialog",
renderedElements: {
title: true,
description: true
},
modal: true,
trapFocus: true,
preventScroll: true,
closeOnInteractOutside: true,
closeOnEscape: true,
restoreFocus: true,
...ctx
},
created: ["setAlertDialogProps"],
watch: {
open: ["toggleVisibility"]
},
states: {
open: {
entry: ["checkRenderedElements", "syncZIndex"],
activities: ["trackDismissableElement", "trapFocus", "preventScroll", "hideContentBelow"],
on: {
"CONTROLLED.CLOSE": {
target: "closed"
},
CLOSE: [
{
guard: "isOpenControlled",
actions: ["invokeOnClose"]
},
{
target: "closed",
actions: ["invokeOnClose"]
}
],
TOGGLE: [
{
guard: "isOpenControlled",
actions: ["invokeOnClose"]
},
{
target: "closed",
actions: ["invokeOnClose"]
}
]
}
},
closed: {
on: {
"CONTROLLED.OPEN": {
target: "open"
},
OPEN: [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["invokeOnOpen"]
}
],
TOGGLE: [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["invokeOnOpen"]
}
]
}
}
}
},
{
guards: {
isOpenControlled: (ctx2) => !!ctx2["open.controlled"]
},
activities: {
trackDismissableElement(ctx2, _evt, { send }) {
const getContentEl = () => dom.getContentEl(ctx2);
return dismissable.trackDismissableElement(getContentEl, {
defer: true,
pointerBlocking: ctx2.modal,
exclude: [dom.getTriggerEl(ctx2)],
onInteractOutside(event) {
ctx2.onInteractOutside?.(event);
if (!ctx2.closeOnInteractOutside) {
event.preventDefault();
}
},
persistentElements: ctx2.persistentElements,
onFocusOutside: ctx2.onFocusOutside,
onPointerDownOutside: ctx2.onPointerDownOutside,
onEscapeKeyDown(event) {
ctx2.onEscapeKeyDown?.(event);
if (!ctx2.closeOnEscape) {
event.preventDefault();
}
},
onDismiss() {
send({ type: "CLOSE", src: "interact-outside" });
}
});
},
preventScroll(ctx2) {
if (!ctx2.preventScroll) return;
return removeScroll.preventBodyScroll(dom.getDoc(ctx2));
},
trapFocus(ctx2) {
if (!ctx2.trapFocus || !ctx2.modal) return;
let trap;
const cleanup = domQuery.nextTick(() => {
const contentEl = dom.getContentEl(ctx2);
if (!contentEl) return;
trap = focusTrap.createFocusTrap(contentEl, {
document: dom.getDoc(ctx2),
escapeDeactivates: false,
preventScroll: true,
fallbackFocus: contentEl,
returnFocusOnDeactivate: !!ctx2.restoreFocus,
allowOutsideClick: true,
initialFocus: ctx2.initialFocusEl?.() ?? void 0,
setReturnFocus(triggerEl) {
return ctx2.finalFocusEl?.() ?? triggerEl;
}
});
try {
trap.activate();
} catch {
}
});
return () => {
trap?.deactivate();
cleanup();
};
},
hideContentBelow(ctx2) {
if (!ctx2.modal) return;
const getElements = () => [dom.getContentEl(ctx2)];
return ariaHidden.ariaHidden(getElements, { defer: true });
}
},
actions: {
setAlertDialogProps(ctx2) {
if (ctx2.role !== "alertdialog") return;
ctx2.initialFocusEl || (ctx2.initialFocusEl = () => dom.getCloseTriggerEl(ctx2));
ctx2.closeOnInteractOutside = false;
},
checkRenderedElements(ctx2) {
domQuery.raf(() => {
ctx2.renderedElements.title = !!dom.getTitleEl(ctx2);
ctx2.renderedElements.description = !!dom.getDescriptionEl(ctx2);
});
},
syncZIndex(ctx2) {
domQuery.raf(() => {
const contentEl = dom.getContentEl(ctx2);
if (!contentEl) return;
const win = dom.getWin(ctx2);
const styles = win.getComputedStyle(contentEl);
const elems = [dom.getPositionerEl(ctx2), dom.getBackdropEl(ctx2)];
elems.forEach((node) => {
node?.style.setProperty("--z-index", styles.zIndex);
});
});
},
invokeOnClose(ctx2) {
ctx2.onOpenChange?.({ open: false });
},
invokeOnOpen(ctx2) {
ctx2.onOpenChange?.({ open: true });
},
toggleVisibility(ctx2, evt, { send }) {
send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
}
}
}
);
}
var props = types.createProps()([
"aria-label",
"closeOnEscape",
"closeOnInteractOutside",
"dir",
"finalFocusEl",
"getRootNode",
"getRootNode",
"id",
"id",
"ids",
"initialFocusEl",
"modal",
"onEscapeKeyDown",
"onFocusOutside",
"onInteractOutside",
"onOpenChange",
"onPointerDownOutside",
"open.controlled",
"open",
"persistentElements",
"preventScroll",
"restoreFocus",
"role",
"trapFocus"
]);
var splitProps = utils.createSplitProps(props);
exports.anatomy = anatomy;
exports.connect = connect;
exports.machine = machine;
exports.props = props;
exports.splitProps = splitProps;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy