@windmorph/react 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/date-picker/date-picker-styles.d.ts +9 -9
- package/dist/components/dialog/Dialog.d.ts +4 -2
- package/dist/components/dialog/Dialog.js +2 -2
- package/dist/components/dialog/Dialog.js.map +1 -1
- package/dist/components/dialog/dialog-styles.js +5 -5
- package/dist/components/dialog/dialog-styles.js.map +1 -1
- package/dist/components/icon-button/IconButton.d.ts +3 -0
- package/dist/components/icon-button/IconButton.js +3 -0
- package/dist/components/icon-button/IconButton.js.map +1 -1
- package/dist/components/menu/use-reveal-entering.d.ts +19 -0
- package/dist/components/navigation/NavItem.js +1 -1
- package/dist/components/navigation/NavItem.js.map +1 -1
- package/dist/components/navigation/NavigationRail.d.ts +21 -2
- package/dist/components/navigation/NavigationRail.js +18 -4
- package/dist/components/navigation/NavigationRail.js.map +1 -1
- package/dist/components/navigation/nav-item-styles.js +4 -4
- package/dist/components/navigation/nav-item-styles.js.map +1 -1
- package/dist/components/navigation/navigation-styles.d.ts +21 -0
- package/dist/components/navigation/navigation-styles.js +6 -1
- package/dist/components/navigation/navigation-styles.js.map +1 -1
- package/dist/components/select/Select.js +6 -1
- package/dist/components/select/Select.js.map +1 -1
- package/dist/components/select/search-list.js +1 -1
- package/dist/components/select/search-list.js.map +1 -1
- package/dist/components/sheet/SideSheet.d.ts +2 -0
- package/dist/components/sheet/SideSheet.js +1 -1
- package/dist/components/sheet/SideSheet.js.map +1 -1
- package/dist/components/text-field/TextField.js +9 -1
- package/dist/components/text-field/TextField.js.map +1 -1
- package/dist/components/time-picker/TimeField.d.ts +118 -0
- package/dist/components/time-picker/TimeField.js +183 -0
- package/dist/components/time-picker/TimeField.js.map +1 -0
- package/dist/components/time-picker/TimeFieldDialog.js +70 -0
- package/dist/components/time-picker/TimeFieldDialog.js.map +1 -0
- package/dist/components/time-picker/TimePicker.js +1 -4
- package/dist/components/time-picker/TimePicker.js.map +1 -1
- package/dist/components/time-picker/hour-cycle.js +10 -0
- package/dist/components/time-picker/hour-cycle.js.map +1 -0
- package/dist/components/time-picker/time-format.js +84 -0
- package/dist/components/time-picker/time-format.js.map +1 -0
- package/dist/composites/button-group/ButtonGroup.d.ts +7 -0
- package/dist/composites/button-group/ButtonGroup.js +3 -2
- package/dist/composites/button-group/ButtonGroup.js.map +1 -1
- package/dist/composites/button-group/button-group-styles.d.ts +15 -3
- package/dist/composites/button-group/button-group-styles.js +16 -1
- package/dist/composites/button-group/button-group-styles.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/primitives/ButtonBase.js +1 -0
- package/dist/primitives/ButtonBase.js.map +1 -1
- package/dist/primitives.d.ts +4 -1
- package/dist/primitives.js +4 -1
- package/dist/styles/utilities.css +8 -0
- package/dist/styles.compiled.css +1 -1
- package/dist/theme/ThemeProvider.js +17 -0
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/utils/closed-by.d.ts +5 -0
- package/dist/utils/placement.d.ts +11 -0
- package/package.json +2 -2
|
@@ -156,14 +156,14 @@ export declare const datePickerStyles: import("tailwind-variants").TVReturnType<
|
|
|
156
156
|
export declare const dockedDatePickerStyles: import("tailwind-variants").TVReturnType<{
|
|
157
157
|
[key: string]: {
|
|
158
158
|
[key: string]: import("tailwind-variants").ClassValue | {
|
|
159
|
-
actions?: import("tailwind-variants").ClassValue;
|
|
160
|
-
item?: import("tailwind-variants").ClassValue;
|
|
161
159
|
panel?: import("tailwind-variants").ClassValue;
|
|
160
|
+
actions?: import("tailwind-variants").ClassValue;
|
|
162
161
|
header?: import("tailwind-variants").ClassValue;
|
|
163
162
|
view?: import("tailwind-variants").ClassValue;
|
|
164
|
-
|
|
163
|
+
item?: import("tailwind-variants").ClassValue;
|
|
165
164
|
check?: import("tailwind-variants").ClassValue;
|
|
166
165
|
menuIcon?: import("tailwind-variants").ClassValue;
|
|
166
|
+
list?: import("tailwind-variants").ClassValue;
|
|
167
167
|
group?: import("tailwind-variants").ClassValue;
|
|
168
168
|
calendar?: import("tailwind-variants").ClassValue;
|
|
169
169
|
menuButton?: import("tailwind-variants").ClassValue;
|
|
@@ -172,14 +172,14 @@ export declare const dockedDatePickerStyles: import("tailwind-variants").TVRetur
|
|
|
172
172
|
} | {
|
|
173
173
|
[x: string]: {
|
|
174
174
|
[x: string]: import("tailwind-variants").ClassValue | {
|
|
175
|
-
actions?: import("tailwind-variants").ClassValue;
|
|
176
|
-
item?: import("tailwind-variants").ClassValue;
|
|
177
175
|
panel?: import("tailwind-variants").ClassValue;
|
|
176
|
+
actions?: import("tailwind-variants").ClassValue;
|
|
178
177
|
header?: import("tailwind-variants").ClassValue;
|
|
179
178
|
view?: import("tailwind-variants").ClassValue;
|
|
180
|
-
|
|
179
|
+
item?: import("tailwind-variants").ClassValue;
|
|
181
180
|
check?: import("tailwind-variants").ClassValue;
|
|
182
181
|
menuIcon?: import("tailwind-variants").ClassValue;
|
|
182
|
+
list?: import("tailwind-variants").ClassValue;
|
|
183
183
|
group?: import("tailwind-variants").ClassValue;
|
|
184
184
|
calendar?: import("tailwind-variants").ClassValue;
|
|
185
185
|
menuButton?: import("tailwind-variants").ClassValue;
|
|
@@ -200,14 +200,14 @@ export declare const dockedDatePickerStyles: import("tailwind-variants").TVRetur
|
|
|
200
200
|
}, undefined, {
|
|
201
201
|
[key: string]: {
|
|
202
202
|
[key: string]: import("tailwind-variants").ClassValue | {
|
|
203
|
-
actions?: import("tailwind-variants").ClassValue;
|
|
204
|
-
item?: import("tailwind-variants").ClassValue;
|
|
205
203
|
panel?: import("tailwind-variants").ClassValue;
|
|
204
|
+
actions?: import("tailwind-variants").ClassValue;
|
|
206
205
|
header?: import("tailwind-variants").ClassValue;
|
|
207
206
|
view?: import("tailwind-variants").ClassValue;
|
|
208
|
-
|
|
207
|
+
item?: import("tailwind-variants").ClassValue;
|
|
209
208
|
check?: import("tailwind-variants").ClassValue;
|
|
210
209
|
menuIcon?: import("tailwind-variants").ClassValue;
|
|
210
|
+
list?: import("tailwind-variants").ClassValue;
|
|
211
211
|
group?: import("tailwind-variants").ClassValue;
|
|
212
212
|
calendar?: import("tailwind-variants").ClassValue;
|
|
213
213
|
menuButton?: import("tailwind-variants").ClassValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ClosedBy } from "../../utils/closed-by.js";
|
|
2
|
-
import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
|
|
2
|
+
import { CSSProperties, ComponentPropsWithRef, ReactElement, ReactNode } from "react";
|
|
3
3
|
import { AriaDialogProps } from "react-aria";
|
|
4
4
|
//#region src/components/dialog/Dialog.d.ts
|
|
5
5
|
/**
|
|
@@ -216,6 +216,8 @@ export interface DialogHeaderProps extends Omit<ComponentPropsWithRef<'div'>, 't
|
|
|
216
216
|
* from closing it too. @default false
|
|
217
217
|
*/
|
|
218
218
|
closeDisabled?: boolean;
|
|
219
|
+
/** Replaces the full-screen close button's icon. */
|
|
220
|
+
closeIcon?: ReactElement;
|
|
219
221
|
/** Classes for each part, by slot. */
|
|
220
222
|
classNames?: DialogHeaderClassNames;
|
|
221
223
|
}
|
|
@@ -233,7 +235,7 @@ export interface DialogHeaderProps extends Omit<ComponentPropsWithRef<'div'>, 't
|
|
|
233
235
|
* <DialogActions>…</DialogActions>
|
|
234
236
|
* </Dialog>
|
|
235
237
|
*/
|
|
236
|
-
export declare function DialogHeader({ children, labels, action, divider, closeDisabled, className, classNames, ...props }: DialogHeaderProps): import("react").JSX.Element;
|
|
238
|
+
export declare function DialogHeader({ children, labels, action, divider, closeDisabled, closeIcon, className, classNames, ...props }: DialogHeaderProps): import("react").JSX.Element;
|
|
237
239
|
export interface DialogContentProps extends ComponentPropsWithRef<'div'> {
|
|
238
240
|
/**
|
|
239
241
|
* The basic dialog's optional dividers: 1px `outline-variant` lines across the panel
|
|
@@ -325,7 +325,7 @@ const DEFAULT_HEADER_LABELS = { close: "Close" };
|
|
|
325
325
|
* <DialogActions>…</DialogActions>
|
|
326
326
|
* </Dialog>
|
|
327
327
|
*/
|
|
328
|
-
function DialogHeader({ children, labels, action, divider = false, closeDisabled = false, className, classNames, ...props }) {
|
|
328
|
+
function DialogHeader({ children, labels, action, divider = false, closeDisabled = false, closeIcon, className, classNames, ...props }) {
|
|
329
329
|
const { titleProps, hasIcon, fullScreen, close, setHeaderAction } = useContext(DialogPartsContext);
|
|
330
330
|
const hasAction = action !== void 0;
|
|
331
331
|
useLayoutEffect(() => {
|
|
@@ -344,7 +344,7 @@ function DialogHeader({ children, labels, action, divider = false, closeDisabled
|
|
|
344
344
|
fullScreen !== "never" && /* @__PURE__ */ jsx(IconButton, {
|
|
345
345
|
variant: "standard",
|
|
346
346
|
density: 0,
|
|
347
|
-
icon: /* @__PURE__ */ jsx(CloseIcon, {}),
|
|
347
|
+
icon: closeIcon ?? /* @__PURE__ */ jsx(CloseIcon, {}),
|
|
348
348
|
"aria-label": labels?.close ?? DEFAULT_HEADER_LABELS.close,
|
|
349
349
|
disabled: closeDisabled,
|
|
350
350
|
onPress: close,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dialog.js","names":["Overlay"],"sources":["../../../src/components/dialog/Dialog.tsx"],"sourcesContent":["'use client';\n\nimport {\n Children,\n Fragment,\n createContext,\n isValidElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type RefObject,\n type CSSProperties,\n type DOMAttributes,\n type ReactNode,\n type Ref,\n} from 'react';\nimport {\n mergeProps,\n useDialog,\n useFocusRing,\n useModalOverlay,\n useObjectRef,\n useOverlayTrigger,\n type AriaDialogProps,\n} from 'react-aria';\nimport { useOverlayTriggerState, type OverlayTriggerState } from 'react-stately';\nimport { Overlay } from '../../primitives/Overlay';\nimport {\n TriggerContext,\n useTriggerProps,\n type TriggerContextValue,\n} from '../../primitives/TriggerContext';\nimport { usePresence } from '../../primitives/use-presence';\nimport { closedByOverlayOptions, type ClosedBy } from '../../utils/closed-by';\nimport { cn } from '../../utils/cn';\nimport { focusFirstInteractive, tabbables } from '../../utils/focus';\nimport { useWarnOnce } from '../../utils/warn-once';\nimport { DensityZeroButtons } from '../button/DensityZeroButtons';\nimport { IconButton } from '../icon-button/IconButton';\nimport { DIALOG_ROOT_STYLE, dialogStyles } from './dialog-styles';\nimport { mergeDataTokens } from '../../utils/merge-data-tokens';\n\n/** Material Symbols \"close\" (Apache-2.0). */\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z\" />\n </svg>\n );\n}\n\n/**\n * When a dialog fills the window (the M3 full-screen dialog): `never`, `always`, or\n * `compact` for windows narrower than 600px only, the M3 recommendation.\n */\nexport type DialogFullScreen = 'never' | 'always' | 'compact';\n\n/**\n * How a basic dialog enters and leaves: `reveal`, the M3 dialog motion, or `scale`, the\n * original pop (a fade with a scale from 90%).\n */\nexport type DialogTransition = 'reveal' | 'scale';\n\n/** Where a basic dialog sits in the window, keeping the spec's 56px margin on wider windows. */\nexport type DialogPlacement = 'center' | 'top' | 'bottom' | 'start' | 'end';\n\n/**\n * What a full-screen dialog grows out of (a container transform): `\"trigger\"` for the\n * `DialogTrigger`'s button, an element such as a FAB, or a box in window coordinates.\n */\nexport type DialogOrigin = 'trigger' | Element | DOMRectReadOnly;\n\ninterface DialogTriggerContextValue {\n state: OverlayTriggerState;\n /** Links the dialog to its trigger (`aria-controls`). */\n overlayProps: { id?: string };\n /** The trigger, for `origin=\"trigger\"`. */\n triggerRef: RefObject<HTMLElement | null>;\n}\n\n/** Where a container transform starts, measured from its origin. */\ninterface OriginBox {\n /** The origin's box and corners as a `clip-path` of the window. */\n clip: string;\n /** The origin's container colour, or the dialog's own when it has none. */\n color: string;\n}\n\n/** How browsers serialise a computed `transparent`. */\nconst TRANSPARENT = 'rgba(0, 0, 0, 0)';\n\n/** A corner radius in px; a percentage resolves against the origin's shorter side. */\nfunction cornerRadius(value: string, rect: DOMRectReadOnly): string {\n if (!value.endsWith('%')) return value || '0px';\n return `${(parseFloat(value) / 100) * Math.min(rect.width, rect.height)}px`;\n}\n\n/** The origin's box as insets from the window (the full-screen dialog's box). */\nfunction measureOrigin(origin: Element | DOMRectReadOnly): OriginBox {\n const isElement = origin instanceof Element;\n const rect = isElement ? origin.getBoundingClientRect() : origin;\n const style = isElement ? getComputedStyle(origin) : null;\n const radius = cornerRadius(style?.borderTopLeftRadius ?? '0px', rect);\n const top = rect.top;\n const left = rect.left;\n const right = window.innerWidth - rect.right;\n const bottom = window.innerHeight - rect.bottom;\n const background = style?.backgroundColor ?? TRANSPARENT;\n return {\n clip: `inset(${top}px ${right}px ${bottom}px ${left}px round ${radius})`,\n color: background === TRANSPARENT ? 'var(--md-sys-color-surface-container-high)' : background,\n };\n}\n\nconst DialogTriggerContext = createContext<DialogTriggerContextValue | null>(null);\n\n/**\n * Calls `onOpened` once the enter motion has finished: every CSS transition running on the\n * scrim, the motion wrapper, the panel and the panel's parts when they first render. Styles\n * are read on the first frame, so the `@starting-style` transitions have begun. A transition\n * cut short (the dialog closes while entering) never finishes, so a dialog that closes early\n * doesn't report opening.\n */\nfunction useOpened(\n scrimRef: RefObject<HTMLElement | null>,\n motionRef: RefObject<HTMLElement | null>,\n panelRef: RefObject<HTMLElement | null>,\n onOpened: (() => void) | undefined,\n) {\n const latest = useRef(onOpened);\n useLayoutEffect(() => {\n latest.current = onOpened;\n });\n useEffect(() => {\n let active = true;\n const frame = requestAnimationFrame(() => {\n const panel = panelRef.current;\n const elements = [scrimRef.current, motionRef.current, panel, ...(panel?.children ?? [])];\n const transitions = elements.flatMap((element) => {\n if (!element || typeof element.getAnimations !== 'function') return [];\n // Reading a style starts the transitions that haven't started yet.\n void getComputedStyle(element).opacity;\n return element.getAnimations().filter((animation) => 'transitionProperty' in animation);\n });\n Promise.all(transitions.map((transition) => transition.finished)).then(\n () => {\n if (active) latest.current?.();\n },\n () => undefined,\n );\n });\n return () => {\n active = false;\n cancelAnimationFrame(frame);\n };\n }, [scrimRef, motionRef, panelRef]);\n}\n\ninterface DialogPartsContextValue {\n titleProps: DOMAttributes<HTMLElement>;\n /** The id an alert dialog's description (`DialogContent`) takes. */\n contentProps: DOMAttributes<HTMLElement>;\n hasIcon: boolean;\n fullScreen: DialogFullScreen;\n close: () => void;\n /** `DialogContent` reports that it's there, so the dialog is described by it. */\n setHasContent: (has: boolean) => void;\n /** `DialogHeader` reports whether it holds the confirming action. */\n setHeaderAction: (has: boolean) => void;\n /** Full screen without a header action: `DialogActions` become a bottom bar. */\n bottomBar: boolean;\n}\n\nconst DialogPartsContext = createContext<DialogPartsContextValue>({\n titleProps: {},\n contentProps: {},\n hasIcon: false,\n fullScreen: 'never',\n close: () => undefined,\n setHasContent: () => undefined,\n setHeaderAction: () => undefined,\n bottomBar: false,\n});\n\nexport interface DialogTriggerProps {\n /** The trigger (a Button, IconButton, …) followed by the `Dialog`. */\n children: ReactNode;\n /** Controlled open state. */\n open?: boolean;\n /** Initial open state when uncontrolled. @default false */\n defaultOpen?: boolean;\n /** Called when the dialog opens or closes. */\n onOpenChange?: (open: boolean) => void;\n}\n\n/**\n * Opens a `Dialog` from a button. The first child is the trigger (any button-like\n * component); the rest is the dialog.\n *\n * @example\n * <DialogTrigger>\n * <Button>Delete</Button>\n * <Dialog>…</Dialog>\n * </DialogTrigger>\n */\nexport function DialogTrigger({ children, open, defaultOpen, onOpenChange }: DialogTriggerProps) {\n const state = useOverlayTriggerState({ isOpen: open, defaultOpen, onOpenChange });\n const triggerRef = useRef<HTMLElement>(null);\n const { triggerProps, overlayProps } = useOverlayTrigger({ type: 'dialog' }, state, triggerRef);\n const triggerValue = useTriggerProps({\n ...(triggerProps as TriggerContextValue),\n ref: triggerRef,\n });\n const [trigger, ...dialog] = Children.toArray(children);\n return (\n <DialogTriggerContext value={{ state, overlayProps, triggerRef }}>\n <TriggerContext value={triggerValue}>{trigger}</TriggerContext>\n {dialog}\n </DialogTriggerContext>\n );\n}\n\nexport interface DialogClassNames {\n /** The dimmed layer behind the dialog. */\n scrim?: string;\n /**\n * The fixed, full-window flex box that places the dialog. It pads 24px on compact windows\n * and 56px from the medium breakpoint, and `placement` sets its alignment, so alignment\n * classes here (`items-*`, `justify-*`) position the dialog anywhere within the spec's\n * margin, and padding classes change that margin.\n */\n positioner?: string;\n /** The dialog's surface: its colour, corners, padding, size and shadow. */\n panel?: string;\n /** The icon above the title. */\n icon?: string;\n}\n\nexport interface DialogRenderProps {\n /** Closes the dialog. */\n close: () => void;\n}\n\nexport interface DialogProps\n extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'role'>, Omit<AriaDialogProps, 'role'> {\n /** Controlled open state, when not inside a `DialogTrigger`. */\n open?: boolean;\n /** Initial open state when uncontrolled, when not inside a `DialogTrigger`. @default false */\n defaultOpen?: boolean;\n /** Called when the dialog opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /**\n * Basic dialogs are alert dialogs on the web (the spec): they need a decision, are\n * described by their `DialogContent`, and aren't dismissed by pressing outside. A dialog\n * that can be full screen is a `dialog`.\n * @default \"alertdialog\", or \"dialog\" when fullScreen isn't \"never\"\n */\n role?: 'dialog' | 'alertdialog';\n /**\n * How the user can close the dialog, as HTML's `<dialog closedby>`: `any` (Escape or a\n * press outside), `closerequest` (Escape only) or `none` (only its own buttons or the app).\n * @default \"closerequest\" for an alertdialog, \"any\" otherwise\n */\n closedBy?: ClosedBy;\n /** Icon above the title (which is then centred). Decorative. Not shown in full screen. */\n icon?: ReactNode;\n /**\n * Fills the window, with a `DialogHeader` holding the close button, title and confirming\n * action instead of `DialogActions` (or with them as a bottom bar when the header has no\n * action). `compact`, the spec's recommendation, does so only below 600px; `always` fills\n * every window. @default \"never\"\n */\n fullScreen?: DialogFullScreen;\n /**\n * Grows the full-screen dialog out of this origin and shrinks it back into it on close,\n * the spec's container transform from a FAB: `\"trigger\"` (the `DialogTrigger`'s button),\n * an element, or a box in window coordinates. The clip, corners and container colour\n * move from the origin to the window on the slow spatial spring and the content fades\n * in; reduced motion keeps only the fades. Used only while the dialog is full screen.\n */\n origin?: DialogOrigin;\n /**\n * Where a basic dialog sits: centred (the spec's default) or against one side of the\n * window, keeping 24px from its edges on compact windows and 56px on wider ones. For any\n * other position, align it with `classNames.positioner` (for example\n * `\"items-start justify-end\"` for the top end corner). It also sets the motion's\n * direction: centred or at the top the dialog slides down and grows downward as it\n * enters, at the bottom up, and at the start or end along the x axis (mirrored in\n * right-to-left layouts).\n * @default \"center\"\n */\n placement?: DialogPlacement;\n children?: ReactNode | ((props: DialogRenderProps) => ReactNode);\n /**\n * Classes for the dialog's parts, merged over the library's: `scrim`, `positioner` (the\n * full-window box that places the dialog; align it anywhere with `items-*` and\n * `justify-*`), `panel` (the surface) and `icon`.\n */\n classNames?: DialogClassNames;\n /** Goes on the outermost element, with `className`. */\n style?: CSSProperties;\n /**\n * How a basic dialog enters and leaves. `reveal` is the M3 dialog motion: it slides 50px\n * away from the edge it sits against while its container grows from that edge, and its\n * headline and content, then its actions, fade in. `scale` is the library's original pop,\n * an extension beyond the M3 motion: the dialog fades in while it scales up from 90%, and\n * fades out while it scales to 95%, from the centre (`placement=\"center\"`) or from the edge\n * it sits against. Either way reduced motion keeps only the fades and `instant` turns the\n * motion off. A full-screen dialog keeps its own motion and ignores it.\n * @default \"reveal\"\n */\n transition?: DialogTransition;\n /**\n * Skips the enter and exit motion: the dialog, its parts and the scrim appear and leave at\n * once, and the dialog leaves the document as soon as it closes. Reduced motion already\n * keeps only the fades. @default false\n */\n instant?: boolean;\n /**\n * Called when the dialog has finished opening: once its enter motion (the slide, the\n * container's growth and every part's fade) has ended, or right after it opens with\n * `instant`. Not called when it closes before then.\n */\n onOpened?: () => void;\n /**\n * Called when the dialog has finished closing: once its exit motion has ended and it has\n * left the document, or right after it closes with `instant`.\n */\n onClosed?: () => void;\n}\n\n/**\n * M3 basic dialog: a modal panel over a scrim, rendered in a portal that keeps the\n * surrounding theme. It's an alert dialog (described by its `DialogContent`). Focus moves\n * to its first interactive element (or one marked `autoFocus`), is contained, and is\n * restored on close; Escape closes it; the page behind does not scroll and is hidden from\n * assistive tech. Name it with a `DialogTitle` (or `aria-label`).\n *\n * It enters with the M3 dialog motion: it slides 50px away from the window edge it sits\n * against while its container grows from that edge, then its headline and content fade in,\n * then its actions; it leaves by fading its parts, sliding back and shrinking, then fading.\n * Any children take part: the actions phase is for `DialogActions` (or any child with\n * `data-slot=\"actions\"`), and every other child fades in with the content. `onOpened` and\n * `onClosed` report the end of each motion; `instant` turns it off.\n *\n * `className` and `style` go on the outermost element, a full-window layer around the\n * positioner whose inline placement they can't move, so a layout class (`static`,\n * `overflow-hidden`, a transform) never hides, clips or stretches the dialog; style the\n * surface with `classNames.panel`. `ref` and other attributes go on the dialog panel.\n *\n * @example\n * <Dialog icon={<DeleteIcon />}>\n * {({ close }) => (\n * <>\n * <DialogTitle>Delete 3 files?</DialogTitle>\n * <DialogContent>They will be removed from all devices.</DialogContent>\n * <DialogActions>\n * <Button variant=\"text\" onPress={close}>Cancel</Button>\n * <Button variant=\"text\" onPress={remove}>Delete</Button>\n * </DialogActions>\n * </>\n * )}\n * </Dialog>\n */\nexport function Dialog({\n open,\n defaultOpen,\n onOpenChange,\n origin,\n onClosed,\n ...props\n}: DialogProps) {\n const trigger = useContext(DialogTriggerContext);\n const ownState = useOverlayTriggerState({ isOpen: open, defaultOpen, onOpenChange });\n const state = trigger?.state ?? ownState;\n const { isPresent, isExiting, exitProps } = usePresence(state.isOpen, 'opacity', !props.instant);\n const onClosedRef = useRef(onClosed);\n useLayoutEffect(() => {\n onClosedRef.current = onClosed;\n });\n const wasPresent = useRef(isPresent);\n useEffect(() => {\n if (wasPresent.current && !isPresent) onClosedRef.current?.();\n wasPresent.current = isPresent;\n }, [isPresent]);\n const usesOrigin = origin !== undefined && (props.fullScreen ?? 'never') !== 'never';\n // The origin is measured before the dialog is in the document (a layout effect, then a\n // synchronous re-render before paint), so the dialog's first style already starts on the\n // origin; and again as it closes, in case the origin moved. `box` is null when there's\n // nothing to measure (`\"trigger\"` outside a `DialogTrigger`).\n const [measured, setMeasured] = useState<{ box: OriginBox | null } | null>(null);\n if (!isPresent && measured !== null) setMeasured(null);\n const triggerRef = trigger?.triggerRef;\n const isOpen = state.isOpen;\n useLayoutEffect(() => {\n if (!usesOrigin || !isPresent) return;\n const target = origin === 'trigger' ? triggerRef?.current : origin;\n setMeasured({ box: target ? measureOrigin(target) : null });\n }, [usesOrigin, origin, triggerRef, isOpen, isPresent]);\n if (!isPresent || (usesOrigin && measured === null)) return null;\n return (\n <Overlay exiting={isExiting}>\n <DialogModal\n {...props}\n state={state}\n isExiting={isExiting}\n exitProps={exitProps}\n triggerOverlayProps={trigger?.overlayProps}\n originBox={usesOrigin ? (measured?.box ?? null) : null}\n />\n </Overlay>\n );\n}\n\nfunction DialogModal({\n state,\n isExiting,\n exitProps,\n triggerOverlayProps,\n originBox,\n role: roleProp,\n closedBy,\n icon,\n fullScreen = 'never',\n placement = 'center',\n instant = false,\n transition = 'reveal',\n onOpened,\n children,\n className,\n classNames,\n style,\n ref,\n ...rest\n}: Omit<DialogProps, 'open' | 'defaultOpen' | 'onOpenChange' | 'onClosed'> & {\n state: OverlayTriggerState;\n isExiting: boolean;\n exitProps: ReturnType<typeof usePresence>['exitProps'];\n triggerOverlayProps?: { id?: string };\n originBox: OriginBox | null;\n}) {\n const role = roleProp ?? (fullScreen === 'never' ? 'alertdialog' : 'dialog');\n const panelRef = useObjectRef(ref as Ref<HTMLDivElement>);\n const motionRef = useRef<HTMLDivElement>(null);\n const scrimRef = useRef<HTMLDivElement>(null);\n useOpened(scrimRef, motionRef, panelRef, onOpened);\n const [hasContent, setHasContent] = useState(false);\n const [headerAction, setHeaderAction] = useState(false);\n const { modalProps, underlayProps } = useModalOverlay(\n closedByOverlayOptions(\n closedBy ?? (role === 'alertdialog' ? 'closerequest' : 'any'),\n isExiting,\n ),\n state,\n panelRef,\n );\n const { dialogProps, titleProps, contentProps } = useDialog({ ...rest, role }, panelRef);\n // An alert dialog is described by its content; leave the reference out when there's none.\n const describedBy =\n rest['aria-describedby'] ?? (hasContent ? dialogProps['aria-describedby'] : undefined);\n\n // The spec: \"focus should automatically land on the first interactive element within the\n // dialog\", not on the panel `useDialog` focuses. A scrolling `DialogContent` is focusable\n // (so the keyboard can scroll it) but isn't a control. When that element is one of the\n // actions, focus goes to the least destructive one (`leastDestructiveAction`).\n useEffect(() => focusFirstInteractive(panelRef.current, leastDestructiveAction), [panelRef]);\n\n const hasIcon = fullScreen !== 'always' && icon !== undefined && icon !== null;\n const bottomBar = fullScreen !== 'never' && !headerAction;\n const origin = originBox !== null;\n const styles = dialogStyles({\n hasIcon,\n fullScreen,\n placement,\n bottomBar,\n origin,\n instant,\n transition,\n });\n const exiting = isExiting || undefined;\n\n return (\n <>\n <div\n ref={scrimRef}\n aria-hidden=\"true\"\n data-exiting={exiting}\n className={styles.scrim({ class: classNames?.scrim })}\n />\n <div style={{ ...style, ...DIALOG_ROOT_STYLE }} className={styles.root({ class: className })}>\n <div {...underlayProps} className={styles.positioner({ class: classNames?.positioner })}>\n <div\n {...exitProps}\n ref={motionRef}\n data-exiting={exiting}\n style={\n originBox\n ? ({\n '--m3-dialog-origin': originBox.clip,\n '--m3-dialog-origin-color': originBox.color,\n } as CSSProperties)\n : undefined\n }\n className={styles.motion()}\n >\n <div\n {...mergeProps(rest, triggerOverlayProps ?? {}, modalProps, dialogProps)}\n aria-describedby={describedBy}\n ref={panelRef}\n data-exiting={exiting}\n // The component tokens' hook (dialog-tokens.ts).\n data-tokens={mergeDataTokens('md-comp-dialog', rest)}\n data-full-screen={fullScreen === 'never' ? undefined : fullScreen}\n data-origin={origin || undefined}\n className={styles.panel({\n class: [transition === 'reveal' && styles.parts(), classNames?.panel],\n })}\n >\n <TriggerContext value={null}>\n <DialogPartsContext\n value={{\n titleProps,\n contentProps,\n hasIcon,\n fullScreen,\n close: state.close,\n setHasContent,\n setHeaderAction,\n bottomBar,\n }}\n >\n {hasIcon && (\n <span\n aria-hidden=\"true\"\n data-slot=\"icon\"\n className={styles.icon({\n class: cn(\n fullScreen === 'compact' && 'max-medium:hidden',\n classNames?.icon,\n ),\n })}\n >\n {icon}\n </span>\n )}\n {typeof children === 'function' ? children({ close: state.close }) : children}\n </DialogPartsContext>\n </TriggerContext>\n </div>\n </div>\n </div>\n </div>\n </>\n );\n}\n\nexport type DialogTitleProps = ComponentPropsWithRef<'h2'>;\n\n/**\n * The dialog's headline; it also names the dialog for assistive tech. In a dialog that can\n * be full screen, use `DialogHeader` instead.\n */\nexport function DialogTitle({ className, ...props }: DialogTitleProps) {\n const { titleProps, hasIcon } = useContext(DialogPartsContext);\n return (\n <h2\n {...mergeProps(titleProps, props)}\n data-slot=\"title\"\n className={dialogStyles({ hasIcon }).title({ class: className })}\n />\n );\n}\n\nexport interface DialogHeaderClassNames {\n /** The header row; `className` is merged here too. */\n root?: string;\n /** The close button. */\n close?: string;\n /** The headline. */\n title?: string;\n}\n\n/** Words a {@link DialogHeader} announces. */\nexport interface DialogHeaderLabels {\n /** The full-screen close button's name. @default \"Close\" */\n close: string;\n}\n\nconst DEFAULT_HEADER_LABELS: DialogHeaderLabels = { close: 'Close' };\n\nexport interface DialogHeaderProps extends Omit<ComponentPropsWithRef<'div'>, 'title'> {\n /** The headline; it names the dialog. */\n children: ReactNode;\n /** Words the header announces, with English defaults. */\n labels?: Partial<DialogHeaderLabels>;\n /**\n * The confirming action, usually a text `Button` (\"Save\"). Shown in full screen only;\n * without it, a full-screen dialog shows its `DialogActions` as a bottom bar.\n */\n action?: ReactNode;\n /** A 1px `outline-variant` divider under the full-screen header. @default false */\n divider?: boolean;\n /**\n * Disables the full-screen close button, e.g. while the confirming action is saving, so the\n * dialog can't be left halfway. Pair it with the `Dialog`'s `closedBy=\"none\"` to keep Escape\n * from closing it too. @default false\n */\n closeDisabled?: boolean;\n /** Classes for each part, by slot. */\n classNames?: DialogHeaderClassNames;\n}\n\n/**\n * The headline of a dialog that can be full screen. In full screen it is the M3 full-screen\n * dialog's header: a close icon button, the headline and the confirming action. Otherwise\n * it is a plain `DialogTitle`, and the dialog's `DialogActions` carry the actions.\n *\n * @example\n * <Dialog fullScreen=\"compact\">\n * <DialogHeader action={<Button variant=\"text\" onPress={save}>Save</Button>}>\n * Edit name\n * </DialogHeader>\n * <DialogContent>…</DialogContent>\n * <DialogActions>…</DialogActions>\n * </Dialog>\n */\nexport function DialogHeader({\n children,\n labels,\n action,\n divider = false,\n closeDisabled = false,\n className,\n classNames,\n ...props\n}: DialogHeaderProps) {\n const { titleProps, hasIcon, fullScreen, close, setHeaderAction } =\n useContext(DialogPartsContext);\n const hasAction = action !== undefined;\n useLayoutEffect(() => {\n setHeaderAction(hasAction);\n return () => setHeaderAction(false);\n }, [hasAction, setHeaderAction]);\n const styles = dialogStyles({ hasIcon, fullScreen, divider });\n return (\n <div {...props} className={styles.header({ class: cn(classNames?.root, className) })}>\n {fullScreen !== 'never' && (\n <IconButton\n variant=\"standard\"\n density={0}\n icon={<CloseIcon />}\n aria-label={labels?.close ?? DEFAULT_HEADER_LABELS.close}\n disabled={closeDisabled}\n onPress={close}\n className={styles.headerButton({ class: cn(styles.close(), classNames?.close) })}\n />\n )}\n <h2 {...titleProps} data-slot=\"title\" className={styles.title({ class: classNames?.title })}>\n {children}\n </h2>\n {fullScreen !== 'never' && action !== undefined && (\n <div className={styles.headerButton()}>\n <DensityZeroButtons>{action}</DensityZeroButtons>\n </div>\n )}\n </div>\n );\n}\n\nexport interface DialogContentProps extends ComponentPropsWithRef<'div'> {\n /**\n * The basic dialog's optional dividers: 1px `outline-variant` lines across the panel\n * above and below the content, e.g. around a scrolling list. Not drawn in full screen.\n * @default false\n */\n dividers?: boolean;\n}\n\n/**\n * Whether an element's content is taller than its box, from a `ResizeObserver` on it and\n * its children (so it is measured only when a size changes).\n */\nfunction useOverflows(ref: RefObject<HTMLElement | null>) {\n const [overflows, setOverflows] = useState(false);\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() =>\n setOverflows(element.scrollHeight > element.clientHeight + 1),\n );\n observer.observe(element);\n for (const child of element.children) observer.observe(child);\n return () => observer.disconnect();\n }, [ref]);\n return overflows;\n}\n\n/**\n * The dialog's supporting text or content; scrolls when the dialog is too tall. It describes\n * an alert dialog. While it scrolls it is focusable (with a focus ring), so the keyboard can\n * scroll it (`data-scrollable`); the dialog's initial focus still goes to its first control.\n */\nexport function DialogContent({ className, dividers = false, ref, ...props }: DialogContentProps) {\n const { fullScreen, contentProps, setHasContent } = useContext(DialogPartsContext);\n const contentRef = useObjectRef(ref as Ref<HTMLDivElement>);\n const overflows = useOverflows(contentRef);\n const { isFocusVisible, focusProps } = useFocusRing();\n useLayoutEffect(() => {\n setHasContent(true);\n return () => setHasContent(false);\n }, [setHasContent]);\n return (\n <div\n {...mergeProps(contentProps, overflows ? focusProps : {}, props)}\n ref={contentRef}\n tabIndex={props.tabIndex ?? (overflows ? 0 : undefined)}\n data-scrollable={overflows || undefined}\n data-focus-visible={(overflows && isFocusVisible) || undefined}\n data-slot=\"content\"\n className={dialogStyles({ fullScreen, dividers }).content({ class: className })}\n />\n );\n}\n\nexport type DialogActionsProps = ComponentPropsWithRef<'div'>;\n\n/** The elements among `children`, counting a fragment's children rather than the fragment. */\nfunction countActions(children: ReactNode): number {\n let count = 0;\n Children.forEach(children, (child) => {\n if (!isValidElement<{ children?: ReactNode }>(child)) return;\n count += child.type === Fragment ? countActions(child.props.children) : 1;\n });\n return count;\n}\n\n/** `children` as a flat list, with fragments' children in place of the fragments. */\nfunction flatChildren(children: ReactNode): ReactNode[] {\n return Children.toArray(children).flatMap((child) =>\n isValidElement<{ children?: ReactNode }>(child) && child.type === Fragment\n ? flatChildren(child.props.children)\n : [child],\n );\n}\n\n/**\n * Where a dialog's initial focus goes when its first interactive element is one of its\n * actions: the dismissive, least destructive action (the WAI-ARIA alert dialog pattern:\n * \"focus the least destructive action\"). That's the first action in source order, which is\n * the row's first button on one line and its last when stacked, since stacked actions are\n * rendered with the confirming action on top. The row says which (`data-stacked`) in the\n * same render that reorders it, so the rule holds whenever the dialog takes focus, before\n * or after the actions stack.\n */\nexport function leastDestructiveAction(first: HTMLElement): HTMLElement {\n const row = first.closest<HTMLElement>('[data-slot=\"actions\"]');\n if (!row) return first;\n const actions = tabbables(row);\n return (row.hasAttribute('data-stacked') ? actions.at(-1) : actions[0]) ?? first;\n}\n\n/**\n * Whether the actions are stacked: they don't fit on one line, and the layout lets them\n * stack (`--m3-dialog-actions-stack`, off in the full-screen bottom bar). Measured on mount\n * and on every resize of the row or a button. Switching reorders the buttons, and moving\n * the focused one drops focus to the page, so it's focused again.\n */\nfunction useStackedActions(ref: RefObject<HTMLDivElement | null>) {\n const [stacked, setStacked] = useState(false);\n const current = useRef(false);\n // The button with focus, kept until focus moves somewhere else.\n const focused = useRef<HTMLElement | null>(null);\n useLayoutEffect(() => {\n const row = ref.current;\n if (!row) return;\n const measure = () => {\n // A hidden row (the header carries the confirming action) keeps its order.\n if (row.clientWidth === 0) return;\n const style = getComputedStyle(row);\n const items = [...row.children] as HTMLElement[];\n const gap = parseFloat(style.columnGap) || 0;\n const room =\n row.clientWidth -\n (parseFloat(style.paddingLeft) || 0) -\n (parseFloat(style.paddingRight) || 0);\n const needed =\n items.reduce((sum, item) => sum + item.offsetWidth, 0) + gap * (items.length - 1);\n const next =\n style.getPropertyValue('--m3-dialog-actions-stack').trim() === '1' &&\n items.length > 1 &&\n needed > room + 0.5;\n if (next === current.current) return;\n current.current = next;\n setStacked(next);\n };\n const onFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement) focused.current = event.target;\n };\n const onFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget !== null) focused.current = null;\n };\n row.addEventListener('focusin', onFocusIn);\n row.addEventListener('focusout', onFocusOut);\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(row);\n for (const item of row.children) observer?.observe(item);\n measure();\n return () => {\n row.removeEventListener('focusin', onFocusIn);\n row.removeEventListener('focusout', onFocusOut);\n observer?.disconnect();\n };\n }, [ref]);\n useLayoutEffect(() => {\n const element = focused.current;\n const active = element?.ownerDocument.activeElement;\n if (element?.isConnected && (!active || active === element.ownerDocument.body)) element.focus();\n }, [stacked]);\n return stacked;\n}\n\n/**\n * Row of actions at the end of the dialog, 8px apart. Put the confirming action last:\n * when the actions do not fit on one line they stack with it on top (M3: \"Confirming\n * actions appear above dismissive actions\"). Stacked, the buttons are rendered in that\n * visual order, so Tab and screen readers reach the confirming action first, top to bottom,\n * as they reach the dismissive one first in a row. When the actions are the dialog's first\n * controls, its initial focus goes to the dismissive action, stacked (the bottom one) or\n * not: the least destructive choice, as the WAI-ARIA alert dialog pattern asks; a stack\n * that forms or unforms later keeps focus where it is. While the dialog is full screen they're\n * hidden when `DialogHeader` carries the confirming action, and otherwise form the spec's\n * 56px bottom action bar. Use at most two actions (the spec); in development it warns once\n * when it holds more.\n */\nexport function DialogActions({ className, children, ref, ...props }: DialogActionsProps) {\n const { fullScreen, bottomBar } = useContext(DialogPartsContext);\n const actionCount = countActions(children);\n useWarnOnce(\n actionCount > 2,\n `[@windmorph/react] DialogActions holds ${actionCount} actions; M3 dialogs have at most two ` +\n '(no third such as \"Learn more\"). Show more inline, or before the dialog opens.',\n );\n const rowRef = useObjectRef(ref);\n const stacked = useStackedActions(rowRef);\n return (\n <div\n {...props}\n ref={rowRef}\n data-slot=\"actions\"\n data-stacked={stacked || undefined}\n className={dialogStyles({ fullScreen, bottomBar }).actions({ class: className })}\n >\n {/* The same keys either way, so switching moves the buttons rather than remounting them. */}\n {stacked ? flatChildren(children).reverse() : flatChildren(children)}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8CA,SAAS,YAAY;CACnB,OACE,oBAAC,OAAD;EAAK,SAAQ;EAAiB,MAAK;EACjC,UAAA,oBAAC,QAAD,EAAM,GAAE,oGAAqG,CAAA;CAC1G,CAAA;AAET;;AAwCA,MAAM,cAAc;;AAGpB,SAAS,aAAa,OAAe,MAA+B;CAClE,IAAI,CAAC,MAAM,SAAS,GAAG,GAAG,OAAO,SAAS;CAC1C,OAAO,GAAI,WAAW,KAAK,IAAI,MAAO,KAAK,IAAI,KAAK,OAAO,KAAK,MAAM,EAAE;AAC1E;;AAGA,SAAS,cAAc,QAA8C;CACnE,MAAM,YAAY,kBAAkB;CACpC,MAAM,OAAO,YAAY,OAAO,sBAAsB,IAAI;CAC1D,MAAM,QAAQ,YAAY,iBAAiB,MAAM,IAAI;CACrD,MAAM,SAAS,aAAa,OAAO,uBAAuB,OAAO,IAAI;CACrE,MAAM,MAAM,KAAK;CACjB,MAAM,OAAO,KAAK;CAClB,MAAM,QAAQ,OAAO,aAAa,KAAK;CACvC,MAAM,SAAS,OAAO,cAAc,KAAK;CACzC,MAAM,aAAa,OAAO,mBAAmB;CAC7C,OAAO;EACL,MAAM,SAAS,IAAI,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,WAAW,OAAO;EACtE,OAAO,eAAe,cAAc,+CAA+C;CACrF;AACF;AAEA,MAAM,uBAAuB,cAAgD,IAAI;;;;;;;;AASjF,SAAS,UACP,UACA,WACA,UACA,UACA;CACA,MAAM,SAAS,OAAO,QAAQ;CAC9B,sBAAsB;EACpB,OAAO,UAAU;CACnB,CAAC;CACD,gBAAgB;EACd,IAAI,SAAS;EACb,MAAM,QAAQ,4BAA4B;GACxC,MAAM,QAAQ,SAAS;GAEvB,MAAM,cAAc;IADF,SAAS;IAAS,UAAU;IAAS;IAAO,GAAI,OAAO,YAAY,CAAC;GAC3D,CAAC,CAAC,SAAS,YAAY;IAChD,IAAI,CAAC,WAAW,OAAO,QAAQ,kBAAkB,YAAY,OAAO,CAAC;IAErE,iBAAsB,OAAO,CAAC,CAAC;IAC/B,OAAO,QAAQ,cAAc,CAAC,CAAC,QAAQ,cAAc,wBAAwB,SAAS;GACxF,CAAC;GACD,QAAQ,IAAI,YAAY,KAAK,eAAe,WAAW,QAAQ,CAAC,CAAC,CAAC,WAC1D;IACJ,IAAI,QAAQ,OAAO,UAAU;GAC/B,SACM,KAAA,CACR;EACF,CAAC;EACD,aAAa;GACX,SAAS;GACT,qBAAqB,KAAK;EAC5B;CACF,GAAG;EAAC;EAAU;EAAW;CAAQ,CAAC;AACpC;AAiBA,MAAM,qBAAqB,cAAuC;CAChE,YAAY,CAAC;CACb,cAAc,CAAC;CACf,SAAS;CACT,YAAY;CACZ,aAAa,KAAA;CACb,qBAAqB,KAAA;CACrB,uBAAuB,KAAA;CACvB,WAAW;AACb,CAAC;;;;;;;;;;;AAuBD,SAAgB,cAAc,EAAE,UAAU,MAAM,aAAa,gBAAoC;CAC/F,MAAM,QAAQ,uBAAuB;EAAE,QAAQ;EAAM;EAAa;CAAa,CAAC;CAChF,MAAM,aAAa,OAAoB,IAAI;CAC3C,MAAM,EAAE,cAAc,iBAAiB,kBAAkB,EAAE,MAAM,SAAS,GAAG,OAAO,UAAU;CAC9F,MAAM,eAAe,gBAAgB;EACnC,GAAI;EACJ,KAAK;CACP,CAAC;CACD,MAAM,CAAC,SAAS,GAAG,UAAU,SAAS,QAAQ,QAAQ;CACtD,OACE,qBAAC,sBAAD;EAAsB,OAAO;GAAE;GAAO;GAAc;EAAW;EAA/D,UAAA,CACE,oBAAC,gBAAD;GAAgB,OAAO;GAAe,UAAA;EAAwB,CAAA,GAC7D,MACmB;;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgJA,SAAgB,OAAO,EACrB,MACA,aACA,cACA,QACA,UACA,GAAG,SACW;CACd,MAAM,UAAU,WAAW,oBAAoB;CAC/C,MAAM,WAAW,uBAAuB;EAAE,QAAQ;EAAM;EAAa;CAAa,CAAC;CACnF,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,EAAE,WAAW,WAAW,cAAc,YAAY,MAAM,QAAQ,WAAW,CAAC,MAAM,OAAO;CAC/F,MAAM,cAAc,OAAO,QAAQ;CACnC,sBAAsB;EACpB,YAAY,UAAU;CACxB,CAAC;CACD,MAAM,aAAa,OAAO,SAAS;CACnC,gBAAgB;EACd,IAAI,WAAW,WAAW,CAAC,WAAW,YAAY,UAAU;EAC5D,WAAW,UAAU;CACvB,GAAG,CAAC,SAAS,CAAC;CACd,MAAM,aAAa,WAAW,KAAA,MAAc,MAAM,cAAc,aAAa;CAK7E,MAAM,CAAC,UAAU,eAAe,SAA2C,IAAI;CAC/E,IAAI,CAAC,aAAa,aAAa,MAAM,YAAY,IAAI;CACrD,MAAM,aAAa,SAAS;CAC5B,MAAM,SAAS,MAAM;CACrB,sBAAsB;EACpB,IAAI,CAAC,cAAc,CAAC,WAAW;EAC/B,MAAM,SAAS,WAAW,YAAY,YAAY,UAAU;EAC5D,YAAY,EAAE,KAAK,SAAS,cAAc,MAAM,IAAI,KAAK,CAAC;CAC5D,GAAG;EAAC;EAAY;EAAQ;EAAY;EAAQ;CAAS,CAAC;CACtD,IAAI,CAAC,aAAc,cAAc,aAAa,MAAO,OAAO;CAC5D,OACE,oBAACA,WAAD;EAAS,SAAS;EAChB,UAAA,oBAAC,aAAD;GACE,GAAI;GACG;GACI;GACA;GACX,qBAAqB,SAAS;GAC9B,WAAW,aAAc,UAAU,OAAO,OAAQ;EACnD,CAAA;CACM,CAAA;AAEb;AAEA,SAAS,YAAY,EACnB,OACA,WACA,WACA,qBACA,WACA,MAAM,UACN,UACA,MACA,aAAa,SACb,YAAY,UACZ,UAAU,OACV,aAAa,UACb,UACA,UACA,WACA,YACA,OACA,KACA,GAAG,QAOF;CACD,MAAM,OAAO,aAAa,eAAe,UAAU,gBAAgB;CACnE,MAAM,WAAW,aAAa,GAA0B;CACxD,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,WAAW,OAAuB,IAAI;CAC5C,UAAU,UAAU,WAAW,UAAU,QAAQ;CACjD,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,cAAc,mBAAmB,SAAS,KAAK;CACtD,MAAM,EAAE,YAAY,kBAAkB,gBACpC,uBACE,aAAa,SAAS,gBAAgB,iBAAiB,QACvD,SACF,GACA,OACA,QACF;CACA,MAAM,EAAE,aAAa,YAAY,iBAAiB,UAAU;EAAE,GAAG;EAAM;CAAK,GAAG,QAAQ;CAEvF,MAAM,cACJ,KAAK,wBAAwB,aAAa,YAAY,sBAAsB,KAAA;CAM9E,gBAAgB,sBAAsB,SAAS,SAAS,sBAAsB,GAAG,CAAC,QAAQ,CAAC;CAE3F,MAAM,UAAU,eAAe,YAAY,SAAS,KAAA,KAAa,SAAS;CAC1E,MAAM,YAAY,eAAe,WAAW,CAAC;CAC7C,MAAM,SAAS,cAAc;CAC7B,MAAM,SAAS,aAAa;EAC1B;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,MAAM,UAAU,aAAa,KAAA;CAE7B,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,KAAK;EACL,eAAY;EACZ,gBAAc;EACd,WAAW,OAAO,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;CACrD,CAAA,GACD,oBAAC,OAAD;EAAK,OAAO;GAAE,GAAG;GAAO,GAAG;EAAkB;EAAG,WAAW,OAAO,KAAK,EAAE,OAAO,UAAU,CAAC;EACzF,UAAA,oBAAC,OAAD;GAAK,GAAI;GAAe,WAAW,OAAO,WAAW,EAAE,OAAO,YAAY,WAAW,CAAC;GACpF,UAAA,oBAAC,OAAD;IACE,GAAI;IACJ,KAAK;IACL,gBAAc;IACd,OACE,YACK;KACC,sBAAsB,UAAU;KAChC,4BAA4B,UAAU;IACxC,IACA,KAAA;IAEN,WAAW,OAAO,OAAO;IAEzB,UAAA,oBAAC,OAAD;KACE,GAAI,WAAW,MAAM,uBAAuB,CAAC,GAAG,YAAY,WAAW;KACvE,oBAAkB;KAClB,KAAK;KACL,gBAAc;KAEd,eAAa,gBAAgB,kBAAkB,IAAI;KACnD,oBAAkB,eAAe,UAAU,KAAA,IAAY;KACvD,eAAa,UAAU,KAAA;KACvB,WAAW,OAAO,MAAM,EACtB,OAAO,CAAC,eAAe,YAAY,OAAO,MAAM,GAAG,YAAY,KAAK,EACtE,CAAC;KAED,UAAA,oBAAC,gBAAD;MAAgB,OAAO;MACrB,UAAA,qBAAC,oBAAD;OACE,OAAO;QACL;QACA;QACA;QACA;QACA,OAAO,MAAM;QACb;QACA;QACA;OACF;OAVF,UAAA,CAYG,WACC,oBAAC,QAAD;QACE,eAAY;QACZ,aAAU;QACV,WAAW,OAAO,KAAK,EACrB,OAAO,GACL,eAAe,aAAa,qBAC5B,YAAY,IACd,EACF,CAAC;QAEA,UAAA;OACG,CAAA,GAEP,OAAO,aAAa,aAAa,SAAS,EAAE,OAAO,MAAM,MAAM,CAAC,IAAI,QACnD;;KACN,CAAA;IACb,CAAA;GACF,CAAA;EACF,CAAA;CACF,CAAA,CACL,EAAA,CAAA;AAEN;;;;;AAQA,SAAgB,YAAY,EAAE,WAAW,GAAG,SAA2B;CACrE,MAAM,EAAE,YAAY,YAAY,WAAW,kBAAkB;CAC7D,OACE,oBAAC,MAAD;EACE,GAAI,WAAW,YAAY,KAAK;EAChC,aAAU;EACV,WAAW,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,UAAU,CAAC;CAChE,CAAA;AAEL;AAiBA,MAAM,wBAA4C,EAAE,OAAO,QAAQ;;;;;;;;;;;;;;;AAsCnE,SAAgB,aAAa,EAC3B,UACA,QACA,QACA,UAAU,OACV,gBAAgB,OAChB,WACA,YACA,GAAG,SACiB;CACpB,MAAM,EAAE,YAAY,SAAS,YAAY,OAAO,oBAC9C,WAAW,kBAAkB;CAC/B,MAAM,YAAY,WAAW,KAAA;CAC7B,sBAAsB;EACpB,gBAAgB,SAAS;EACzB,aAAa,gBAAgB,KAAK;CACpC,GAAG,CAAC,WAAW,eAAe,CAAC;CAC/B,MAAM,SAAS,aAAa;EAAE;EAAS;EAAY;CAAQ,CAAC;CAC5D,OACE,qBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,OAAO,OAAO,EAAE,OAAO,GAAG,YAAY,MAAM,SAAS,EAAE,CAAC;EAAnF,UAAA;GACG,eAAe,WACd,oBAAC,YAAD;IACE,SAAQ;IACR,SAAS;IACT,MAAM,oBAAC,WAAD,CAAY,CAAA;IAClB,cAAY,QAAQ,SAAS,sBAAsB;IACnD,UAAU;IACV,SAAS;IACT,WAAW,OAAO,aAAa,EAAE,OAAO,GAAG,OAAO,MAAM,GAAG,YAAY,KAAK,EAAE,CAAC;GAChF,CAAA;GAEH,oBAAC,MAAD;IAAI,GAAI;IAAY,aAAU;IAAQ,WAAW,OAAO,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;IACvF;GACC,CAAA;GACH,eAAe,WAAW,WAAW,KAAA,KACpC,oBAAC,OAAD;IAAK,WAAW,OAAO,aAAa;IAClC,UAAA,oBAAC,oBAAD,EAAA,UAAqB,OAA2B,CAAA;GAC7C,CAAA;EAEJ;;AAET;;;;;AAeA,SAAS,aAAa,KAAoC;CACxD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,sBAAsB;EACpB,MAAM,UAAU,IAAI;EACpB,IAAI,CAAC,WAAW,OAAO,mBAAmB,aAAa;EACvD,MAAM,WAAW,IAAI,qBACnB,aAAa,QAAQ,eAAe,QAAQ,eAAe,CAAC,CAC9D;EACA,SAAS,QAAQ,OAAO;EACxB,KAAK,MAAM,SAAS,QAAQ,UAAU,SAAS,QAAQ,KAAK;EAC5D,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,GAAG,CAAC;CACR,OAAO;AACT;;;;;;AAOA,SAAgB,cAAc,EAAE,WAAW,WAAW,OAAO,KAAK,GAAG,SAA6B;CAChG,MAAM,EAAE,YAAY,cAAc,kBAAkB,WAAW,kBAAkB;CACjF,MAAM,aAAa,aAAa,GAA0B;CAC1D,MAAM,YAAY,aAAa,UAAU;CACzC,MAAM,EAAE,gBAAgB,eAAe,aAAa;CACpD,sBAAsB;EACpB,cAAc,IAAI;EAClB,aAAa,cAAc,KAAK;CAClC,GAAG,CAAC,aAAa,CAAC;CAClB,OACE,oBAAC,OAAD;EACE,GAAI,WAAW,cAAc,YAAY,aAAa,CAAC,GAAG,KAAK;EAC/D,KAAK;EACL,UAAU,MAAM,aAAa,YAAY,IAAI,KAAA;EAC7C,mBAAiB,aAAa,KAAA;EAC9B,sBAAqB,aAAa,kBAAmB,KAAA;EACrD,aAAU;EACV,WAAW,aAAa;GAAE;GAAY;EAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,UAAU,CAAC;CAC/E,CAAA;AAEL;;AAKA,SAAS,aAAa,UAA6B;CACjD,IAAI,QAAQ;CACZ,SAAS,QAAQ,WAAW,UAAU;EACpC,IAAI,CAAC,eAAyC,KAAK,GAAG;EACtD,SAAS,MAAM,SAAS,WAAW,aAAa,MAAM,MAAM,QAAQ,IAAI;CAC1E,CAAC;CACD,OAAO;AACT;;AAGA,SAAS,aAAa,UAAkC;CACtD,OAAO,SAAS,QAAQ,QAAQ,CAAC,CAAC,SAAS,UACzC,eAAyC,KAAK,KAAK,MAAM,SAAS,WAC9D,aAAa,MAAM,MAAM,QAAQ,IACjC,CAAC,KAAK,CACZ;AACF;;;;;;;;;;AAWA,SAAgB,uBAAuB,OAAiC;CACtE,MAAM,MAAM,MAAM,QAAqB,yBAAuB;CAC9D,IAAI,CAAC,KAAK,OAAO;CACjB,MAAM,UAAU,UAAU,GAAG;CAC7B,QAAQ,IAAI,aAAa,cAAc,IAAI,QAAQ,GAAG,EAAE,IAAI,QAAQ,OAAO;AAC7E;;;;;;;AAQA,SAAS,kBAAkB,KAAuC;CAChE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,UAAU,OAAO,KAAK;CAE5B,MAAM,UAAU,OAA2B,IAAI;CAC/C,sBAAsB;EACpB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK;EACV,MAAM,gBAAgB;GAEpB,IAAI,IAAI,gBAAgB,GAAG;GAC3B,MAAM,QAAQ,iBAAiB,GAAG;GAClC,MAAM,QAAQ,CAAC,GAAG,IAAI,QAAQ;GAC9B,MAAM,MAAM,WAAW,MAAM,SAAS,KAAK;GAC3C,MAAM,OACJ,IAAI,eACH,WAAW,MAAM,WAAW,KAAK,MACjC,WAAW,MAAM,YAAY,KAAK;GACrC,MAAM,SACJ,MAAM,QAAQ,KAAK,SAAS,MAAM,KAAK,aAAa,CAAC,IAAI,OAAO,MAAM,SAAS;GACjF,MAAM,OACJ,MAAM,iBAAiB,2BAA2B,CAAC,CAAC,KAAK,MAAM,OAC/D,MAAM,SAAS,KACf,SAAS,OAAO;GAClB,IAAI,SAAS,QAAQ,SAAS;GAC9B,QAAQ,UAAU;GAClB,WAAW,IAAI;EACjB;EACA,MAAM,aAAa,UAAsB;GACvC,IAAI,MAAM,kBAAkB,aAAa,QAAQ,UAAU,MAAM;EACnE;EACA,MAAM,cAAc,UAAsB;GACxC,IAAI,MAAM,kBAAkB,MAAM,QAAQ,UAAU;EACtD;EACA,IAAI,iBAAiB,WAAW,SAAS;EACzC,IAAI,iBAAiB,YAAY,UAAU;EAC3C,MAAM,WAAW,OAAO,mBAAmB,cAAc,OAAO,IAAI,eAAe,OAAO;EAC1F,UAAU,QAAQ,GAAG;EACrB,KAAK,MAAM,QAAQ,IAAI,UAAU,UAAU,QAAQ,IAAI;EACvD,QAAQ;EACR,aAAa;GACX,IAAI,oBAAoB,WAAW,SAAS;GAC5C,IAAI,oBAAoB,YAAY,UAAU;GAC9C,UAAU,WAAW;EACvB;CACF,GAAG,CAAC,GAAG,CAAC;CACR,sBAAsB;EACpB,MAAM,UAAU,QAAQ;EACxB,MAAM,SAAS,SAAS,cAAc;EACtC,IAAI,SAAS,gBAAgB,CAAC,UAAU,WAAW,QAAQ,cAAc,OAAO,QAAQ,MAAM;CAChG,GAAG,CAAC,OAAO,CAAC;CACZ,OAAO;AACT;;;;;;;;;;;;;;AAeA,SAAgB,cAAc,EAAE,WAAW,UAAU,KAAK,GAAG,SAA6B;CACxF,MAAM,EAAE,YAAY,cAAc,WAAW,kBAAkB;CAC/D,MAAM,cAAc,aAAa,QAAQ;CACzC,YACE,cAAc,GACd,0CAA0C,YAAY,qHAExD;CACA,MAAM,SAAS,aAAa,GAAG;CAC/B,MAAM,UAAU,kBAAkB,MAAM;CACxC,OACE,oBAAC,OAAD;EACE,GAAI;EACJ,KAAK;EACL,aAAU;EACV,gBAAc,WAAW,KAAA;EACzB,WAAW,aAAa;GAAE;GAAY;EAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,UAAU,CAAC;EAG9E,UAAA,UAAU,aAAa,QAAQ,CAAC,CAAC,QAAQ,IAAI,aAAa,QAAQ;CAChE,CAAA;AAET"}
|
|
1
|
+
{"version":3,"file":"Dialog.js","names":["Overlay"],"sources":["../../../src/components/dialog/Dialog.tsx"],"sourcesContent":["'use client';\n\nimport {\n Children,\n Fragment,\n createContext,\n isValidElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ComponentPropsWithRef,\n type RefObject,\n type CSSProperties,\n type DOMAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n} from 'react';\nimport {\n mergeProps,\n useDialog,\n useFocusRing,\n useModalOverlay,\n useObjectRef,\n useOverlayTrigger,\n type AriaDialogProps,\n} from 'react-aria';\nimport { useOverlayTriggerState, type OverlayTriggerState } from 'react-stately';\nimport { Overlay } from '../../primitives/Overlay';\nimport {\n TriggerContext,\n useTriggerProps,\n type TriggerContextValue,\n} from '../../primitives/TriggerContext';\nimport { usePresence } from '../../primitives/use-presence';\nimport { closedByOverlayOptions, type ClosedBy } from '../../utils/closed-by';\nimport { cn } from '../../utils/cn';\nimport { focusFirstInteractive, tabbables } from '../../utils/focus';\nimport { useWarnOnce } from '../../utils/warn-once';\nimport { DensityZeroButtons } from '../button/DensityZeroButtons';\nimport { IconButton } from '../icon-button/IconButton';\nimport { DIALOG_ROOT_STYLE, dialogStyles } from './dialog-styles';\nimport { mergeDataTokens } from '../../utils/merge-data-tokens';\n\n/** Material Symbols \"close\" (Apache-2.0). */\nfunction CloseIcon() {\n return (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z\" />\n </svg>\n );\n}\n\n/**\n * When a dialog fills the window (the M3 full-screen dialog): `never`, `always`, or\n * `compact` for windows narrower than 600px only, the M3 recommendation.\n */\nexport type DialogFullScreen = 'never' | 'always' | 'compact';\n\n/**\n * How a basic dialog enters and leaves: `reveal`, the M3 dialog motion, or `scale`, the\n * original pop (a fade with a scale from 90%).\n */\nexport type DialogTransition = 'reveal' | 'scale';\n\n/** Where a basic dialog sits in the window, keeping the spec's 56px margin on wider windows. */\nexport type DialogPlacement = 'center' | 'top' | 'bottom' | 'start' | 'end';\n\n/**\n * What a full-screen dialog grows out of (a container transform): `\"trigger\"` for the\n * `DialogTrigger`'s button, an element such as a FAB, or a box in window coordinates.\n */\nexport type DialogOrigin = 'trigger' | Element | DOMRectReadOnly;\n\ninterface DialogTriggerContextValue {\n state: OverlayTriggerState;\n /** Links the dialog to its trigger (`aria-controls`). */\n overlayProps: { id?: string };\n /** The trigger, for `origin=\"trigger\"`. */\n triggerRef: RefObject<HTMLElement | null>;\n}\n\n/** Where a container transform starts, measured from its origin. */\ninterface OriginBox {\n /** The origin's box and corners as a `clip-path` of the window. */\n clip: string;\n /** The origin's container colour, or the dialog's own when it has none. */\n color: string;\n}\n\n/** How browsers serialise a computed `transparent`. */\nconst TRANSPARENT = 'rgba(0, 0, 0, 0)';\n\n/** A corner radius in px; a percentage resolves against the origin's shorter side. */\nfunction cornerRadius(value: string, rect: DOMRectReadOnly): string {\n if (!value.endsWith('%')) return value || '0px';\n return `${(parseFloat(value) / 100) * Math.min(rect.width, rect.height)}px`;\n}\n\n/** The origin's box as insets from the window (the full-screen dialog's box). */\nfunction measureOrigin(origin: Element | DOMRectReadOnly): OriginBox {\n const isElement = origin instanceof Element;\n const rect = isElement ? origin.getBoundingClientRect() : origin;\n const style = isElement ? getComputedStyle(origin) : null;\n const radius = cornerRadius(style?.borderTopLeftRadius ?? '0px', rect);\n const top = rect.top;\n const left = rect.left;\n const right = window.innerWidth - rect.right;\n const bottom = window.innerHeight - rect.bottom;\n const background = style?.backgroundColor ?? TRANSPARENT;\n return {\n clip: `inset(${top}px ${right}px ${bottom}px ${left}px round ${radius})`,\n color: background === TRANSPARENT ? 'var(--md-sys-color-surface-container-high)' : background,\n };\n}\n\nconst DialogTriggerContext = createContext<DialogTriggerContextValue | null>(null);\n\n/**\n * Calls `onOpened` once the enter motion has finished: every CSS transition running on the\n * scrim, the motion wrapper, the panel and the panel's parts when they first render. Styles\n * are read on the first frame, so the `@starting-style` transitions have begun. A transition\n * cut short (the dialog closes while entering) never finishes, so a dialog that closes early\n * doesn't report opening.\n */\nfunction useOpened(\n scrimRef: RefObject<HTMLElement | null>,\n motionRef: RefObject<HTMLElement | null>,\n panelRef: RefObject<HTMLElement | null>,\n onOpened: (() => void) | undefined,\n) {\n const latest = useRef(onOpened);\n useLayoutEffect(() => {\n latest.current = onOpened;\n });\n useEffect(() => {\n let active = true;\n const frame = requestAnimationFrame(() => {\n const panel = panelRef.current;\n const elements = [scrimRef.current, motionRef.current, panel, ...(panel?.children ?? [])];\n const transitions = elements.flatMap((element) => {\n if (!element || typeof element.getAnimations !== 'function') return [];\n // Reading a style starts the transitions that haven't started yet.\n void getComputedStyle(element).opacity;\n return element.getAnimations().filter((animation) => 'transitionProperty' in animation);\n });\n Promise.all(transitions.map((transition) => transition.finished)).then(\n () => {\n if (active) latest.current?.();\n },\n () => undefined,\n );\n });\n return () => {\n active = false;\n cancelAnimationFrame(frame);\n };\n }, [scrimRef, motionRef, panelRef]);\n}\n\ninterface DialogPartsContextValue {\n titleProps: DOMAttributes<HTMLElement>;\n /** The id an alert dialog's description (`DialogContent`) takes. */\n contentProps: DOMAttributes<HTMLElement>;\n hasIcon: boolean;\n fullScreen: DialogFullScreen;\n close: () => void;\n /** `DialogContent` reports that it's there, so the dialog is described by it. */\n setHasContent: (has: boolean) => void;\n /** `DialogHeader` reports whether it holds the confirming action. */\n setHeaderAction: (has: boolean) => void;\n /** Full screen without a header action: `DialogActions` become a bottom bar. */\n bottomBar: boolean;\n}\n\nconst DialogPartsContext = createContext<DialogPartsContextValue>({\n titleProps: {},\n contentProps: {},\n hasIcon: false,\n fullScreen: 'never',\n close: () => undefined,\n setHasContent: () => undefined,\n setHeaderAction: () => undefined,\n bottomBar: false,\n});\n\nexport interface DialogTriggerProps {\n /** The trigger (a Button, IconButton, …) followed by the `Dialog`. */\n children: ReactNode;\n /** Controlled open state. */\n open?: boolean;\n /** Initial open state when uncontrolled. @default false */\n defaultOpen?: boolean;\n /** Called when the dialog opens or closes. */\n onOpenChange?: (open: boolean) => void;\n}\n\n/**\n * Opens a `Dialog` from a button. The first child is the trigger (any button-like\n * component); the rest is the dialog.\n *\n * @example\n * <DialogTrigger>\n * <Button>Delete</Button>\n * <Dialog>…</Dialog>\n * </DialogTrigger>\n */\nexport function DialogTrigger({ children, open, defaultOpen, onOpenChange }: DialogTriggerProps) {\n const state = useOverlayTriggerState({ isOpen: open, defaultOpen, onOpenChange });\n const triggerRef = useRef<HTMLElement>(null);\n const { triggerProps, overlayProps } = useOverlayTrigger({ type: 'dialog' }, state, triggerRef);\n const triggerValue = useTriggerProps({\n ...(triggerProps as TriggerContextValue),\n ref: triggerRef,\n });\n const [trigger, ...dialog] = Children.toArray(children);\n return (\n <DialogTriggerContext value={{ state, overlayProps, triggerRef }}>\n <TriggerContext value={triggerValue}>{trigger}</TriggerContext>\n {dialog}\n </DialogTriggerContext>\n );\n}\n\nexport interface DialogClassNames {\n /** The dimmed layer behind the dialog. */\n scrim?: string;\n /**\n * The fixed, full-window flex box that places the dialog. It pads 24px on compact windows\n * and 56px from the medium breakpoint, and `placement` sets its alignment, so alignment\n * classes here (`items-*`, `justify-*`) position the dialog anywhere within the spec's\n * margin, and padding classes change that margin.\n */\n positioner?: string;\n /** The dialog's surface: its colour, corners, padding, size and shadow. */\n panel?: string;\n /** The icon above the title. */\n icon?: string;\n}\n\nexport interface DialogRenderProps {\n /** Closes the dialog. */\n close: () => void;\n}\n\nexport interface DialogProps\n extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'role'>, Omit<AriaDialogProps, 'role'> {\n /** Controlled open state, when not inside a `DialogTrigger`. */\n open?: boolean;\n /** Initial open state when uncontrolled, when not inside a `DialogTrigger`. @default false */\n defaultOpen?: boolean;\n /** Called when the dialog opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /**\n * Basic dialogs are alert dialogs on the web (the spec): they need a decision, are\n * described by their `DialogContent`, and aren't dismissed by pressing outside. A dialog\n * that can be full screen is a `dialog`.\n * @default \"alertdialog\", or \"dialog\" when fullScreen isn't \"never\"\n */\n role?: 'dialog' | 'alertdialog';\n /**\n * How the user can close the dialog, as HTML's `<dialog closedby>`: `any` (Escape or a\n * press outside), `closerequest` (Escape only) or `none` (only its own buttons or the app).\n * @default \"closerequest\" for an alertdialog, \"any\" otherwise\n */\n closedBy?: ClosedBy;\n /** Icon above the title (which is then centred). Decorative. Not shown in full screen. */\n icon?: ReactNode;\n /**\n * Fills the window, with a `DialogHeader` holding the close button, title and confirming\n * action instead of `DialogActions` (or with them as a bottom bar when the header has no\n * action). `compact`, the spec's recommendation, does so only below 600px; `always` fills\n * every window. @default \"never\"\n */\n fullScreen?: DialogFullScreen;\n /**\n * Grows the full-screen dialog out of this origin and shrinks it back into it on close,\n * the spec's container transform from a FAB: `\"trigger\"` (the `DialogTrigger`'s button),\n * an element, or a box in window coordinates. The clip, corners and container colour\n * move from the origin to the window on the slow spatial spring and the content fades\n * in; reduced motion keeps only the fades. Used only while the dialog is full screen.\n */\n origin?: DialogOrigin;\n /**\n * Where a basic dialog sits: centred (the spec's default) or against one side of the\n * window, keeping 24px from its edges on compact windows and 56px on wider ones. For any\n * other position, align it with `classNames.positioner` (for example\n * `\"items-start justify-end\"` for the top end corner). It also sets the motion's\n * direction: centred or at the top the dialog slides down and grows downward as it\n * enters, at the bottom up, and at the start or end along the x axis (mirrored in\n * right-to-left layouts).\n * @default \"center\"\n */\n placement?: DialogPlacement;\n children?: ReactNode | ((props: DialogRenderProps) => ReactNode);\n /**\n * Classes for the dialog's parts, merged over the library's: `scrim`, `positioner` (the\n * full-window box that places the dialog; align it anywhere with `items-*` and\n * `justify-*`), `panel` (the surface) and `icon`.\n */\n classNames?: DialogClassNames;\n /** Goes on the outermost element, with `className`. */\n style?: CSSProperties;\n /**\n * How a basic dialog enters and leaves. `reveal` is the M3 dialog motion: it slides 50px\n * away from the edge it sits against while its container grows from that edge, and its\n * headline and content, then its actions, fade in. `scale` is the library's original pop,\n * an extension beyond the M3 motion: the dialog fades in while it scales up from 90%, and\n * fades out while it scales to 95%, from the centre (`placement=\"center\"`) or from the edge\n * it sits against. Either way reduced motion keeps only the fades and `instant` turns the\n * motion off. A full-screen dialog keeps its own motion and ignores it.\n * @default \"reveal\"\n */\n transition?: DialogTransition;\n /**\n * Skips the enter and exit motion: the dialog, its parts and the scrim appear and leave at\n * once, and the dialog leaves the document as soon as it closes. Reduced motion already\n * keeps only the fades. @default false\n */\n instant?: boolean;\n /**\n * Called when the dialog has finished opening: once its enter motion (the slide, the\n * container's growth and every part's fade) has ended, or right after it opens with\n * `instant`. Not called when it closes before then.\n */\n onOpened?: () => void;\n /**\n * Called when the dialog has finished closing: once its exit motion has ended and it has\n * left the document, or right after it closes with `instant`.\n */\n onClosed?: () => void;\n}\n\n/**\n * M3 basic dialog: a modal panel over a scrim, rendered in a portal that keeps the\n * surrounding theme. It's an alert dialog (described by its `DialogContent`). Focus moves\n * to its first interactive element (or one marked `autoFocus`), is contained, and is\n * restored on close; Escape closes it; the page behind does not scroll and is hidden from\n * assistive tech. Name it with a `DialogTitle` (or `aria-label`).\n *\n * It enters with the M3 dialog motion: it slides 50px away from the window edge it sits\n * against while its container grows from that edge, then its headline and content fade in,\n * then its actions; it leaves by fading its parts, sliding back and shrinking, then fading.\n * Any children take part: the actions phase is for `DialogActions` (or any child with\n * `data-slot=\"actions\"`), and every other child fades in with the content. `onOpened` and\n * `onClosed` report the end of each motion; `instant` turns it off.\n *\n * `className` and `style` go on the outermost element, a full-window layer around the\n * positioner whose inline placement they can't move, so a layout class (`static`,\n * `overflow-hidden`, a transform) never hides, clips or stretches the dialog; style the\n * surface with `classNames.panel`. `ref` and other attributes go on the dialog panel.\n *\n * @example\n * <Dialog icon={<DeleteIcon />}>\n * {({ close }) => (\n * <>\n * <DialogTitle>Delete 3 files?</DialogTitle>\n * <DialogContent>They will be removed from all devices.</DialogContent>\n * <DialogActions>\n * <Button variant=\"text\" onPress={close}>Cancel</Button>\n * <Button variant=\"text\" onPress={remove}>Delete</Button>\n * </DialogActions>\n * </>\n * )}\n * </Dialog>\n */\nexport function Dialog({\n open,\n defaultOpen,\n onOpenChange,\n origin,\n onClosed,\n ...props\n}: DialogProps) {\n const trigger = useContext(DialogTriggerContext);\n const ownState = useOverlayTriggerState({ isOpen: open, defaultOpen, onOpenChange });\n const state = trigger?.state ?? ownState;\n const { isPresent, isExiting, exitProps } = usePresence(state.isOpen, 'opacity', !props.instant);\n const onClosedRef = useRef(onClosed);\n useLayoutEffect(() => {\n onClosedRef.current = onClosed;\n });\n const wasPresent = useRef(isPresent);\n useEffect(() => {\n if (wasPresent.current && !isPresent) onClosedRef.current?.();\n wasPresent.current = isPresent;\n }, [isPresent]);\n const usesOrigin = origin !== undefined && (props.fullScreen ?? 'never') !== 'never';\n // The origin is measured before the dialog is in the document (a layout effect, then a\n // synchronous re-render before paint), so the dialog's first style already starts on the\n // origin; and again as it closes, in case the origin moved. `box` is null when there's\n // nothing to measure (`\"trigger\"` outside a `DialogTrigger`).\n const [measured, setMeasured] = useState<{ box: OriginBox | null } | null>(null);\n if (!isPresent && measured !== null) setMeasured(null);\n const triggerRef = trigger?.triggerRef;\n const isOpen = state.isOpen;\n useLayoutEffect(() => {\n if (!usesOrigin || !isPresent) return;\n const target = origin === 'trigger' ? triggerRef?.current : origin;\n setMeasured({ box: target ? measureOrigin(target) : null });\n }, [usesOrigin, origin, triggerRef, isOpen, isPresent]);\n if (!isPresent || (usesOrigin && measured === null)) return null;\n return (\n <Overlay exiting={isExiting}>\n <DialogModal\n {...props}\n state={state}\n isExiting={isExiting}\n exitProps={exitProps}\n triggerOverlayProps={trigger?.overlayProps}\n originBox={usesOrigin ? (measured?.box ?? null) : null}\n />\n </Overlay>\n );\n}\n\nfunction DialogModal({\n state,\n isExiting,\n exitProps,\n triggerOverlayProps,\n originBox,\n role: roleProp,\n closedBy,\n icon,\n fullScreen = 'never',\n placement = 'center',\n instant = false,\n transition = 'reveal',\n onOpened,\n children,\n className,\n classNames,\n style,\n ref,\n ...rest\n}: Omit<DialogProps, 'open' | 'defaultOpen' | 'onOpenChange' | 'onClosed'> & {\n state: OverlayTriggerState;\n isExiting: boolean;\n exitProps: ReturnType<typeof usePresence>['exitProps'];\n triggerOverlayProps?: { id?: string };\n originBox: OriginBox | null;\n}) {\n const role = roleProp ?? (fullScreen === 'never' ? 'alertdialog' : 'dialog');\n const panelRef = useObjectRef(ref as Ref<HTMLDivElement>);\n const motionRef = useRef<HTMLDivElement>(null);\n const scrimRef = useRef<HTMLDivElement>(null);\n useOpened(scrimRef, motionRef, panelRef, onOpened);\n const [hasContent, setHasContent] = useState(false);\n const [headerAction, setHeaderAction] = useState(false);\n const { modalProps, underlayProps } = useModalOverlay(\n closedByOverlayOptions(\n closedBy ?? (role === 'alertdialog' ? 'closerequest' : 'any'),\n isExiting,\n ),\n state,\n panelRef,\n );\n const { dialogProps, titleProps, contentProps } = useDialog({ ...rest, role }, panelRef);\n // An alert dialog is described by its content; leave the reference out when there's none.\n const describedBy =\n rest['aria-describedby'] ?? (hasContent ? dialogProps['aria-describedby'] : undefined);\n\n // The spec: \"focus should automatically land on the first interactive element within the\n // dialog\", not on the panel `useDialog` focuses. A scrolling `DialogContent` is focusable\n // (so the keyboard can scroll it) but isn't a control. When that element is one of the\n // actions, focus goes to the least destructive one (`leastDestructiveAction`).\n useEffect(() => focusFirstInteractive(panelRef.current, leastDestructiveAction), [panelRef]);\n\n const hasIcon = fullScreen !== 'always' && icon !== undefined && icon !== null;\n const bottomBar = fullScreen !== 'never' && !headerAction;\n const origin = originBox !== null;\n const styles = dialogStyles({\n hasIcon,\n fullScreen,\n placement,\n bottomBar,\n origin,\n instant,\n transition,\n });\n const exiting = isExiting || undefined;\n\n return (\n <>\n <div\n ref={scrimRef}\n aria-hidden=\"true\"\n data-exiting={exiting}\n className={styles.scrim({ class: classNames?.scrim })}\n />\n <div style={{ ...style, ...DIALOG_ROOT_STYLE }} className={styles.root({ class: className })}>\n <div {...underlayProps} className={styles.positioner({ class: classNames?.positioner })}>\n <div\n {...exitProps}\n ref={motionRef}\n data-exiting={exiting}\n style={\n originBox\n ? ({\n '--m3-dialog-origin': originBox.clip,\n '--m3-dialog-origin-color': originBox.color,\n } as CSSProperties)\n : undefined\n }\n className={styles.motion()}\n >\n <div\n {...mergeProps(rest, triggerOverlayProps ?? {}, modalProps, dialogProps)}\n aria-describedby={describedBy}\n ref={panelRef}\n data-exiting={exiting}\n // The component tokens' hook (dialog-tokens.ts).\n data-tokens={mergeDataTokens('md-comp-dialog', rest)}\n data-full-screen={fullScreen === 'never' ? undefined : fullScreen}\n data-origin={origin || undefined}\n className={styles.panel({\n class: [transition === 'reveal' && styles.parts(), classNames?.panel],\n })}\n >\n <TriggerContext value={null}>\n <DialogPartsContext\n value={{\n titleProps,\n contentProps,\n hasIcon,\n fullScreen,\n close: state.close,\n setHasContent,\n setHeaderAction,\n bottomBar,\n }}\n >\n {hasIcon && (\n <span\n aria-hidden=\"true\"\n data-slot=\"icon\"\n className={styles.icon({\n class: cn(\n fullScreen === 'compact' && 'max-medium:hidden',\n classNames?.icon,\n ),\n })}\n >\n {icon}\n </span>\n )}\n {typeof children === 'function' ? children({ close: state.close }) : children}\n </DialogPartsContext>\n </TriggerContext>\n </div>\n </div>\n </div>\n </div>\n </>\n );\n}\n\nexport type DialogTitleProps = ComponentPropsWithRef<'h2'>;\n\n/**\n * The dialog's headline; it also names the dialog for assistive tech. In a dialog that can\n * be full screen, use `DialogHeader` instead.\n */\nexport function DialogTitle({ className, ...props }: DialogTitleProps) {\n const { titleProps, hasIcon } = useContext(DialogPartsContext);\n return (\n <h2\n {...mergeProps(titleProps, props)}\n data-slot=\"title\"\n className={dialogStyles({ hasIcon }).title({ class: className })}\n />\n );\n}\n\nexport interface DialogHeaderClassNames {\n /** The header row; `className` is merged here too. */\n root?: string;\n /** The close button. */\n close?: string;\n /** The headline. */\n title?: string;\n}\n\n/** Words a {@link DialogHeader} announces. */\nexport interface DialogHeaderLabels {\n /** The full-screen close button's name. @default \"Close\" */\n close: string;\n}\n\nconst DEFAULT_HEADER_LABELS: DialogHeaderLabels = { close: 'Close' };\n\nexport interface DialogHeaderProps extends Omit<ComponentPropsWithRef<'div'>, 'title'> {\n /** The headline; it names the dialog. */\n children: ReactNode;\n /** Words the header announces, with English defaults. */\n labels?: Partial<DialogHeaderLabels>;\n /**\n * The confirming action, usually a text `Button` (\"Save\"). Shown in full screen only;\n * without it, a full-screen dialog shows its `DialogActions` as a bottom bar.\n */\n action?: ReactNode;\n /** A 1px `outline-variant` divider under the full-screen header. @default false */\n divider?: boolean;\n /**\n * Disables the full-screen close button, e.g. while the confirming action is saving, so the\n * dialog can't be left halfway. Pair it with the `Dialog`'s `closedBy=\"none\"` to keep Escape\n * from closing it too. @default false\n */\n closeDisabled?: boolean;\n /** Replaces the full-screen close button's icon. */\n closeIcon?: ReactElement;\n /** Classes for each part, by slot. */\n classNames?: DialogHeaderClassNames;\n}\n\n/**\n * The headline of a dialog that can be full screen. In full screen it is the M3 full-screen\n * dialog's header: a close icon button, the headline and the confirming action. Otherwise\n * it is a plain `DialogTitle`, and the dialog's `DialogActions` carry the actions.\n *\n * @example\n * <Dialog fullScreen=\"compact\">\n * <DialogHeader action={<Button variant=\"text\" onPress={save}>Save</Button>}>\n * Edit name\n * </DialogHeader>\n * <DialogContent>…</DialogContent>\n * <DialogActions>…</DialogActions>\n * </Dialog>\n */\nexport function DialogHeader({\n children,\n labels,\n action,\n divider = false,\n closeDisabled = false,\n closeIcon,\n className,\n classNames,\n ...props\n}: DialogHeaderProps) {\n const { titleProps, hasIcon, fullScreen, close, setHeaderAction } =\n useContext(DialogPartsContext);\n const hasAction = action !== undefined;\n useLayoutEffect(() => {\n setHeaderAction(hasAction);\n return () => setHeaderAction(false);\n }, [hasAction, setHeaderAction]);\n const styles = dialogStyles({ hasIcon, fullScreen, divider });\n return (\n <div {...props} className={styles.header({ class: cn(classNames?.root, className) })}>\n {fullScreen !== 'never' && (\n <IconButton\n variant=\"standard\"\n density={0}\n icon={closeIcon ?? <CloseIcon />}\n aria-label={labels?.close ?? DEFAULT_HEADER_LABELS.close}\n disabled={closeDisabled}\n onPress={close}\n className={styles.headerButton({ class: cn(styles.close(), classNames?.close) })}\n />\n )}\n <h2 {...titleProps} data-slot=\"title\" className={styles.title({ class: classNames?.title })}>\n {children}\n </h2>\n {fullScreen !== 'never' && action !== undefined && (\n <div className={styles.headerButton()}>\n <DensityZeroButtons>{action}</DensityZeroButtons>\n </div>\n )}\n </div>\n );\n}\n\nexport interface DialogContentProps extends ComponentPropsWithRef<'div'> {\n /**\n * The basic dialog's optional dividers: 1px `outline-variant` lines across the panel\n * above and below the content, e.g. around a scrolling list. Not drawn in full screen.\n * @default false\n */\n dividers?: boolean;\n}\n\n/**\n * Whether an element's content is taller than its box, from a `ResizeObserver` on it and\n * its children (so it is measured only when a size changes).\n */\nfunction useOverflows(ref: RefObject<HTMLElement | null>) {\n const [overflows, setOverflows] = useState(false);\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() =>\n setOverflows(element.scrollHeight > element.clientHeight + 1),\n );\n observer.observe(element);\n for (const child of element.children) observer.observe(child);\n return () => observer.disconnect();\n }, [ref]);\n return overflows;\n}\n\n/**\n * The dialog's supporting text or content; scrolls when the dialog is too tall. It describes\n * an alert dialog. While it scrolls it is focusable (with a focus ring), so the keyboard can\n * scroll it (`data-scrollable`); the dialog's initial focus still goes to its first control.\n */\nexport function DialogContent({ className, dividers = false, ref, ...props }: DialogContentProps) {\n const { fullScreen, contentProps, setHasContent } = useContext(DialogPartsContext);\n const contentRef = useObjectRef(ref as Ref<HTMLDivElement>);\n const overflows = useOverflows(contentRef);\n const { isFocusVisible, focusProps } = useFocusRing();\n useLayoutEffect(() => {\n setHasContent(true);\n return () => setHasContent(false);\n }, [setHasContent]);\n return (\n <div\n {...mergeProps(contentProps, overflows ? focusProps : {}, props)}\n ref={contentRef}\n tabIndex={props.tabIndex ?? (overflows ? 0 : undefined)}\n data-scrollable={overflows || undefined}\n data-focus-visible={(overflows && isFocusVisible) || undefined}\n data-slot=\"content\"\n className={dialogStyles({ fullScreen, dividers }).content({ class: className })}\n />\n );\n}\n\nexport type DialogActionsProps = ComponentPropsWithRef<'div'>;\n\n/** The elements among `children`, counting a fragment's children rather than the fragment. */\nfunction countActions(children: ReactNode): number {\n let count = 0;\n Children.forEach(children, (child) => {\n if (!isValidElement<{ children?: ReactNode }>(child)) return;\n count += child.type === Fragment ? countActions(child.props.children) : 1;\n });\n return count;\n}\n\n/** `children` as a flat list, with fragments' children in place of the fragments. */\nfunction flatChildren(children: ReactNode): ReactNode[] {\n return Children.toArray(children).flatMap((child) =>\n isValidElement<{ children?: ReactNode }>(child) && child.type === Fragment\n ? flatChildren(child.props.children)\n : [child],\n );\n}\n\n/**\n * Where a dialog's initial focus goes when its first interactive element is one of its\n * actions: the dismissive, least destructive action (the WAI-ARIA alert dialog pattern:\n * \"focus the least destructive action\"). That's the first action in source order, which is\n * the row's first button on one line and its last when stacked, since stacked actions are\n * rendered with the confirming action on top. The row says which (`data-stacked`) in the\n * same render that reorders it, so the rule holds whenever the dialog takes focus, before\n * or after the actions stack.\n */\nexport function leastDestructiveAction(first: HTMLElement): HTMLElement {\n const row = first.closest<HTMLElement>('[data-slot=\"actions\"]');\n if (!row) return first;\n const actions = tabbables(row);\n return (row.hasAttribute('data-stacked') ? actions.at(-1) : actions[0]) ?? first;\n}\n\n/**\n * Whether the actions are stacked: they don't fit on one line, and the layout lets them\n * stack (`--m3-dialog-actions-stack`, off in the full-screen bottom bar). Measured on mount\n * and on every resize of the row or a button. Switching reorders the buttons, and moving\n * the focused one drops focus to the page, so it's focused again.\n */\nfunction useStackedActions(ref: RefObject<HTMLDivElement | null>) {\n const [stacked, setStacked] = useState(false);\n const current = useRef(false);\n // The button with focus, kept until focus moves somewhere else.\n const focused = useRef<HTMLElement | null>(null);\n useLayoutEffect(() => {\n const row = ref.current;\n if (!row) return;\n const measure = () => {\n // A hidden row (the header carries the confirming action) keeps its order.\n if (row.clientWidth === 0) return;\n const style = getComputedStyle(row);\n const items = [...row.children] as HTMLElement[];\n const gap = parseFloat(style.columnGap) || 0;\n const room =\n row.clientWidth -\n (parseFloat(style.paddingLeft) || 0) -\n (parseFloat(style.paddingRight) || 0);\n const needed =\n items.reduce((sum, item) => sum + item.offsetWidth, 0) + gap * (items.length - 1);\n const next =\n style.getPropertyValue('--m3-dialog-actions-stack').trim() === '1' &&\n items.length > 1 &&\n needed > room + 0.5;\n if (next === current.current) return;\n current.current = next;\n setStacked(next);\n };\n const onFocusIn = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement) focused.current = event.target;\n };\n const onFocusOut = (event: FocusEvent) => {\n if (event.relatedTarget !== null) focused.current = null;\n };\n row.addEventListener('focusin', onFocusIn);\n row.addEventListener('focusout', onFocusOut);\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure);\n observer?.observe(row);\n for (const item of row.children) observer?.observe(item);\n measure();\n return () => {\n row.removeEventListener('focusin', onFocusIn);\n row.removeEventListener('focusout', onFocusOut);\n observer?.disconnect();\n };\n }, [ref]);\n useLayoutEffect(() => {\n const element = focused.current;\n const active = element?.ownerDocument.activeElement;\n if (element?.isConnected && (!active || active === element.ownerDocument.body)) element.focus();\n }, [stacked]);\n return stacked;\n}\n\n/**\n * Row of actions at the end of the dialog, 8px apart. Put the confirming action last:\n * when the actions do not fit on one line they stack with it on top (M3: \"Confirming\n * actions appear above dismissive actions\"). Stacked, the buttons are rendered in that\n * visual order, so Tab and screen readers reach the confirming action first, top to bottom,\n * as they reach the dismissive one first in a row. When the actions are the dialog's first\n * controls, its initial focus goes to the dismissive action, stacked (the bottom one) or\n * not: the least destructive choice, as the WAI-ARIA alert dialog pattern asks; a stack\n * that forms or unforms later keeps focus where it is. While the dialog is full screen they're\n * hidden when `DialogHeader` carries the confirming action, and otherwise form the spec's\n * 56px bottom action bar. Use at most two actions (the spec); in development it warns once\n * when it holds more.\n */\nexport function DialogActions({ className, children, ref, ...props }: DialogActionsProps) {\n const { fullScreen, bottomBar } = useContext(DialogPartsContext);\n const actionCount = countActions(children);\n useWarnOnce(\n actionCount > 2,\n `[@windmorph/react] DialogActions holds ${actionCount} actions; M3 dialogs have at most two ` +\n '(no third such as \"Learn more\"). Show more inline, or before the dialog opens.',\n );\n const rowRef = useObjectRef(ref);\n const stacked = useStackedActions(rowRef);\n return (\n <div\n {...props}\n ref={rowRef}\n data-slot=\"actions\"\n data-stacked={stacked || undefined}\n className={dialogStyles({ fullScreen, bottomBar }).actions({ class: className })}\n >\n {/* The same keys either way, so switching moves the buttons rather than remounting them. */}\n {stacked ? flatChildren(children).reverse() : flatChildren(children)}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -57,7 +57,7 @@ const dialogStyles = tv({
|
|
|
57
57
|
headerButton: "",
|
|
58
58
|
close: "[--md-comp-icon-button-icon-color:var(--md-sys-color-on-surface)]",
|
|
59
59
|
content: [
|
|
60
|
-
"min-h-0 flex-1 overflow-y-auto pb-[24px] text-body-medium",
|
|
60
|
+
"-mt-[8px] min-h-0 flex-1 overflow-y-auto pt-[8px] pb-[24px] text-body-medium",
|
|
61
61
|
"text-[color:var(--_md-comp-dialog-supporting-text-color)]",
|
|
62
62
|
"focus-ring"
|
|
63
63
|
],
|
|
@@ -138,7 +138,7 @@ const dialogStyles = tv({
|
|
|
138
138
|
panel: ["size-full max-h-none max-w-none rounded-none p-0 shadow-none", "bg-surface-container-high"],
|
|
139
139
|
header: "flex h-[56px] shrink-0 items-center gap-[4px] ps-[4px] pe-[12px]",
|
|
140
140
|
title: "min-w-0 flex-1 truncate ps-[4px] pb-0 text-start text-title-large",
|
|
141
|
-
content: "px-[24px] pt-[24px]",
|
|
141
|
+
content: "mt-0 px-[24px] pt-[24px]",
|
|
142
142
|
actions: "hidden"
|
|
143
143
|
},
|
|
144
144
|
compact: {
|
|
@@ -177,7 +177,7 @@ const dialogStyles = tv({
|
|
|
177
177
|
header: ["max-medium:flex max-medium:h-[56px] max-medium:shrink-0 max-medium:items-center", "max-medium:gap-[4px] max-medium:ps-[4px] max-medium:pe-[12px]"],
|
|
178
178
|
headerButton: "medium:hidden",
|
|
179
179
|
title: ["max-medium:min-w-0 max-medium:flex-1 max-medium:truncate max-medium:ps-[4px]", "max-medium:pb-0 max-medium:text-start max-medium:text-title-large"],
|
|
180
|
-
content: "max-medium:px-[24px] max-medium:pt-[24px]",
|
|
180
|
+
content: "max-medium:mt-0 max-medium:px-[24px] max-medium:pt-[24px]",
|
|
181
181
|
actions: "max-medium:hidden"
|
|
182
182
|
}
|
|
183
183
|
},
|
|
@@ -244,12 +244,12 @@ const dialogStyles = tv({
|
|
|
244
244
|
{
|
|
245
245
|
fullScreen: "never",
|
|
246
246
|
dividers: true,
|
|
247
|
-
class: { content: "-mx-[24px] mb-[24px] border-y border-outline-variant px-[24px] py-[8px]" }
|
|
247
|
+
class: { content: "mt-0 -mx-[24px] mb-[24px] border-y border-outline-variant px-[24px] py-[8px]" }
|
|
248
248
|
},
|
|
249
249
|
{
|
|
250
250
|
fullScreen: "compact",
|
|
251
251
|
dividers: true,
|
|
252
|
-
class: { content: ["medium:-mx-[24px] medium:mb-[24px] medium:border-y medium:border-outline-variant", "medium:px-[24px] medium:py-[8px]"] }
|
|
252
|
+
class: { content: ["medium:mt-0 medium:-mx-[24px] medium:mb-[24px] medium:border-y medium:border-outline-variant", "medium:px-[24px] medium:py-[8px]"] }
|
|
253
253
|
},
|
|
254
254
|
{
|
|
255
255
|
fullScreen: "never",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-styles.js","names":[],"sources":["../../../src/components/dialog/dialog-styles.ts"],"sourcesContent":["import { tv, type VariantProps } from '../../utils/tv';\n\n/*\n * Values follow Compose Material 3 (AlertDialog.kt and DialogTokens): 280–560px wide (the\n * minimum capped by the window's 24px margins), 24px padding, 28px corners,\n * surface-container-high at elevation 3, a 24px secondary icon and the title 16px apart, the\n * title centred when there is an icon, 24px below the supporting text, 8px between actions,\n * and stacked actions with the confirming action on top. Optional dividers above and below\n * the content are 1px `outline-variant`. The scrim is `scrim` at 32% (M3).\n *\n * Motion (2026-10-14): Compose has no dialog motion of its own (the platform animates\n * windows), so the basic dialog follows the M3 dialog enter and exit as Material Web encodes\n * it, mapped onto the M3 Expressive springs (spatial for movement and size, effects for\n * opacity). Entering, the dialog slides 50px away from the window edge it sits against\n * (downward when centred), its container grows from that edge from 0 to its full size (a\n * clip on a library-owned wrapper, so text is never shown outside the container and the\n * spec's 0 start is kept), and it fades in on the fast effects spring while the scrim fades\n * in on the slow one; the headline, icon and supporting text fade in after 50ms and the\n * actions after 150ms. Leaving follows the reference's close timing exactly, on M3's\n * emphasized-accelerate easing and duration tokens: the parts fade out over 100ms, the\n * dialog slides back 50px and its container shrinks to 35% over 150ms (slow at first, so\n * it is still moving and shrinking until it is gone), the container fades out from 100ms to\n * 150ms, and the scrim fades out over 150ms. Reduced motion keeps only the\n * fades of the dialog and the scrim; `instant` turns all of it off.\n * The positioner keeps 24px from the window's edges on compact windows and the spec's 56px\n * on wider ones, and `placement` aligns the dialog in it.\n *\n * Full-screen dialogs follow the M3 dialog spec's full-screen type: the panel fills the\n * window on `surface-container-high` with no corners, elevation or padding; a 56px header\n * holds the `on-surface` close icon button, the `title-large` headline and the confirming\n * text button (with an optional `outline-variant` divider), and the content is padded 24px\n * at the top and sides. With a header action `DialogActions` are hidden; without one they\n * form a 56px bottom action bar. The panel slides up 48px and fades in on the slow springs\n * (the spec's speed for full-screen animations), or, with an `origin`, grows out of it (a\n * container transform). `fullScreen: 'compact'` applies all of this only below 600px (the M3\n * compact window class) and is a basic dialog otherwise.\n *\n * The basic dialog's container colour, corners and shadow, and the icon, title and supporting\n * text colours, come from the dialog's component tokens (`dialog-tokens.ts`,\n * `--md-comp-dialog-*`); the panel carries `data-tokens=\"md-comp-dialog\"`, and the parts read\n * one private variable each. A full-screen panel keeps its own `surface-container-high`. A\n * consumer class (`bg-surface-container`) still wins. Every class is written out in full.\n */\n\n/** The dialog root's placement, inline so it wins over consumer layout classes. */\nexport const DIALOG_ROOT_STYLE = { position: 'fixed', inset: 0 } as const;\n\n/** Variant definitions for {@link Dialog} and its parts. */\nexport const dialogStyles = tv({\n slots: {\n scrim: [\n 'fixed inset-0 z-(--md-sys-z-scrim) bg-scrim/32 opacity-100',\n '[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'starting:opacity-0',\n 'data-exiting:opacity-0',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n // The dialog's outermost element, which takes the consumer's `className` and `style`. It\n // covers the window through an inline `position: fixed; inset: 0` (`DIALOG_ROOT_STYLE`),\n // which a consumer class can't move: a layout class such as `static` or `absolute top-24`\n // never puts the dialog in the page's flow or out of the window.\n root: 'z-(--md-sys-z-dialog)',\n positioner: 'fixed inset-0 z-(--md-sys-z-dialog) flex p-[24px] medium:p-[56px]',\n /*\n * The library-owned wrapper that moves: it slides 50px (`--m3-dialog-slide`), its clip\n * grows the container (`--m3-dialog-enter-clip` → `--m3-dialog-open-clip`, which rests\n * 32px outside the panel so the shadow shows, its corners concentric with the panel's\n * `--m3-dialog-corner`) and it fades. Leaving, the clip shrinks to 35%\n * (`--m3-dialog-exit-clip`) and the fade waits 100ms for the parts to fade first. The\n * exit uses the reference's curves rather than springs (2026-10-14): the slide and shrink\n * run 150ms on emphasized-accelerate, which never overshoots and keeps moving until the\n * fade (50ms, linear, after 100ms) has ended. A spring front-loads the motion: the\n * expressive spatial one overshot past 50px and below 35%, and the critically damped\n * effects one finished shrinking before the fade, leaving a still 35% box fading. The\n * clip's sides open from the panel's edges to the shadow's 32px together with its corner\n * radius, so the growing edge keeps the panel's corners on every frame.\n */\n motion: [\n 'flex max-h-full max-w-full',\n '[--m3-dialog-corner:var(--md-comp-dialog-container-shape,var(--md-sys-shape-corner-extra-large))]',\n '[--m3-dialog-open-clip:inset(-32px_round_calc(var(--m3-dialog-corner)_+_32px))]',\n '[--m3-dialog-enter-clip:inset(0_0_100%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_0_65%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:0_-50px] [--m3-dialog-scale-origin:center]',\n 'translate-none opacity-100 [clip-path:var(--m3-dialog-open-clip)]',\n 'starting:[translate:var(--m3-dialog-slide)] starting:opacity-0',\n 'starting:[clip-path:var(--m3-dialog-enter-clip)]',\n 'data-exiting:[translate:var(--m3-dialog-slide)] data-exiting:opacity-0',\n 'data-exiting:[clip-path:var(--m3-dialog-exit-clip)]',\n 'motion-reduce:data-exiting:translate-none',\n 'motion-reduce:data-exiting:[clip-path:var(--m3-dialog-open-clip)]',\n '[transition-property:opacity,translate,clip-path] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-1),var(--md-sys-motion-duration-short-3),var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n 'data-exiting:[transition-delay:var(--md-sys-motion-duration-short-2),0s,0s]',\n 'motion-reduce:data-exiting:[transition-delay:0s]',\n 'motion-reduce:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n ],\n /*\n * Classes for the panel that stagger its parts (its children): every part fades in after\n * 50ms on the default effects spring (the headline, icon and supporting text, and any\n * custom child), and the actions (`data-slot=\"actions\"`) after 150ms on the fast one.\n * Leaving, they all fade out at once on the fast spring. Basic dialogs only (see the\n * `fullScreen` variants); reduced motion leaves the parts to the wrapper's fade.\n */\n parts: '',\n panel: [\n 'flex max-h-full min-w-[min(280px,calc(100vw-48px))] max-w-[560px] flex-col p-[24px]',\n 'rounded-[var(--_md-comp-dialog-container-shape)] bg-[var(--_md-comp-dialog-container-color)]',\n 'text-on-surface shadow-[shadow:var(--_md-comp-dialog-container-elevation)]',\n 'outline-none',\n // Forced colours drop the fill and shadow, so the panel draws its edge instead.\n 'forced-colors:outline-solid forced-colors:outline-1 forced-colors:outline-[CanvasText]',\n ],\n icon: [\n 'mx-auto inline-flex pb-[16px] [&>svg]:size-[24px]',\n 'text-[color:var(--_md-comp-dialog-with-icon-icon-color)]',\n ],\n title: [\n 'pb-[16px] text-headline-small font-brand',\n 'text-[color:var(--_md-comp-dialog-headline-color)]',\n ],\n header: '',\n headerButton: '',\n close: '[--md-comp-icon-button-icon-color:var(--md-sys-color-on-surface)]',\n content: [\n 'min-h-0 flex-1 overflow-y-auto pb-[24px] text-body-medium',\n 'text-[color:var(--_md-comp-dialog-supporting-text-color)]',\n 'focus-ring',\n ],\n // Stacked (`data-stacked`, set by `DialogActions` when they don't fit on one line), the\n // buttons are rendered confirming action first and wrap forwards instead of in reverse:\n // the same picture, sizes included, in focus order. The custom property tells it\n // whether the layout lets them stack.\n actions: [\n 'flex flex-wrap-reverse items-center justify-end gap-[8px] [--m3-dialog-actions-stack:1]',\n 'data-stacked:flex-wrap',\n ],\n },\n variants: {\n hasIcon: {\n true: { title: 'text-center' },\n false: { title: 'text-start' },\n },\n /*\n * The dialog enters from the window edge it sits against (the spec's enter and exit\n * pattern): it slides 50px away from that edge while its container grows away from it,\n * and leaves the same way back. Centred or at the top it slides down and grows downward\n * (the reference motion), at the bottom it slides up and grows upward, and at the start\n * or end it moves and grows along the x axis, mirrored in right-to-left layouts.\n */\n placement: {\n center: { positioner: 'items-center justify-center' },\n top: {\n positioner: 'items-start justify-center',\n motion: '[--m3-dialog-scale-origin:top]',\n },\n bottom: {\n positioner: 'items-end justify-center',\n motion: [\n '[--m3-dialog-enter-clip:inset(100%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(65%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:0_50px] [--m3-dialog-scale-origin:bottom]',\n ],\n },\n start: {\n positioner: 'items-center justify-start',\n motion: [\n '[--m3-dialog-enter-clip:inset(0_100%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_65%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:-50px_0] [--m3-dialog-scale-origin:left]',\n 'rtl:[--m3-dialog-enter-clip:inset(0_0_0_100%_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-exit-clip:inset(0_0_0_65%_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-slide:50px_0] rtl:[--m3-dialog-scale-origin:right]',\n ],\n },\n end: {\n positioner: 'items-center justify-end',\n motion: [\n '[--m3-dialog-enter-clip:inset(0_0_0_100%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_0_0_65%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:50px_0] [--m3-dialog-scale-origin:right]',\n 'rtl:[--m3-dialog-enter-clip:inset(0_100%_0_0_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-exit-clip:inset(0_65%_0_0_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-slide:-50px_0] rtl:[--m3-dialog-scale-origin:left]',\n ],\n },\n },\n fullScreen: {\n never: {\n headerButton: 'hidden',\n parts: [\n 'motion-safe:*:starting:opacity-0 motion-safe:data-exiting:*:opacity-0',\n '*:[transition-property:opacity]',\n '*:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n '*:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n '*:[transition-delay:var(--md-sys-motion-duration-short-1)]',\n '*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n '*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n '*:data-[slot=actions]:[transition-delay:var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:*:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'data-exiting:*:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n 'data-exiting:*:[transition-delay:0s] data-exiting:*:data-[slot=actions]:[transition-delay:0s]',\n 'data-exiting:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'data-exiting:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n },\n /*\n * Full screen keeps its own motion: the dialog slides up 48px as it fades in on the slow\n * springs (the spec's speed for full-screen motion) with no clip, and slides back down\n * as it fades out on the fast ones, its parts fading with it.\n */\n always: {\n positioner: 'p-0 medium:p-0',\n motion: [\n 'size-full [--m3-dialog-slide:0_48px]',\n '[--m3-dialog-open-clip:none] [--m3-dialog-enter-clip:none] [--m3-dialog-exit-clip:none]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'data-exiting:[transition-delay:0s]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n panel: [\n 'size-full max-h-none max-w-none rounded-none p-0 shadow-none',\n 'bg-surface-container-high',\n ],\n header: 'flex h-[56px] shrink-0 items-center gap-[4px] ps-[4px] pe-[12px]',\n title: 'min-w-0 flex-1 truncate ps-[4px] pb-0 text-start text-title-large',\n content: 'px-[24px] pt-[24px]',\n actions: 'hidden',\n },\n compact: {\n positioner: 'max-medium:p-0',\n motion: [\n 'max-medium:size-full max-medium:[--m3-dialog-slide:0_48px]',\n 'max-medium:[--m3-dialog-open-clip:none] max-medium:[--m3-dialog-enter-clip:none]',\n 'max-medium:[--m3-dialog-exit-clip:none]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'max-medium:data-exiting:[transition-delay:0s]',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'max-medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n parts: [\n 'medium:motion-safe:*:starting:opacity-0 medium:motion-safe:data-exiting:*:opacity-0',\n 'medium:*:[transition-property:opacity]',\n 'medium:*:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'medium:*:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'medium:*:[transition-delay:var(--md-sys-motion-duration-short-1)]',\n 'medium:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'medium:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n 'medium:*:data-[slot=actions]:[transition-delay:var(--md-sys-motion-duration-short-3)]',\n 'medium:data-exiting:*:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'medium:data-exiting:*:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n 'medium:data-exiting:*:[transition-delay:0s]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-delay:0s]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n panel: [\n 'max-medium:size-full max-medium:max-h-none max-medium:max-w-none',\n 'max-medium:rounded-none max-medium:p-0 max-medium:shadow-none',\n 'max-medium:bg-surface-container-high',\n ],\n header: [\n 'max-medium:flex max-medium:h-[56px] max-medium:shrink-0 max-medium:items-center',\n 'max-medium:gap-[4px] max-medium:ps-[4px] max-medium:pe-[12px]',\n ],\n headerButton: 'medium:hidden',\n title: [\n 'max-medium:min-w-0 max-medium:flex-1 max-medium:truncate max-medium:ps-[4px]',\n 'max-medium:pb-0 max-medium:text-start max-medium:text-title-large',\n ],\n content: 'max-medium:px-[24px] max-medium:pt-[24px]',\n actions: 'max-medium:hidden',\n },\n },\n /** Full screen without a header action: the actions form a 56px bottom bar. */\n bottomBar: { true: {}, false: {} },\n /** A divider under the full-screen header. */\n divider: { true: {}, false: {} },\n /** The basic dialog's optional dividers above and below `DialogContent`. */\n dividers: { true: {}, false: {} },\n /** A container transform from a trigger (`origin`) into the full-screen dialog. */\n origin: { true: {}, false: {} },\n /**\n * The basic dialog's enter and exit: `reveal`, the M3 dialog motion above, or `scale`,\n * the original pop (see the compound variants). Full-screen dialogs ignore it.\n */\n transition: { reveal: {}, scale: {} },\n /** No enter or exit motion: the dialog, its parts and the scrim appear and go at once. */\n instant: {\n true: {\n scrim: '[transition-property:none]!',\n motion: '[transition-property:none]!',\n panel: '[transition-property:none]!',\n parts: '*:[transition-property:none]!',\n },\n false: {},\n },\n },\n compoundVariants: [\n {\n fullScreen: 'always',\n bottomBar: true,\n class: {\n actions: 'flex h-[56px] shrink-0 flex-nowrap px-[24px] [--m3-dialog-actions-stack:0]',\n },\n },\n {\n fullScreen: 'compact',\n bottomBar: true,\n class: {\n actions:\n 'max-medium:flex max-medium:h-[56px] max-medium:shrink-0 max-medium:flex-nowrap max-medium:px-[24px] max-medium:[--m3-dialog-actions-stack:0]',\n },\n },\n {\n fullScreen: 'always',\n divider: true,\n class: { header: 'border-b border-outline-variant' },\n },\n {\n fullScreen: 'compact',\n divider: true,\n class: { header: 'max-medium:border-b max-medium:border-outline-variant' },\n },\n /*\n * Dividers run the panel's full width, 1px `outline-variant`, with 8px between them and\n * the content; the body keeps 24px to the actions below the bottom one.\n */\n {\n fullScreen: 'never',\n dividers: true,\n class: {\n content: '-mx-[24px] mb-[24px] border-y border-outline-variant px-[24px] py-[8px]',\n },\n },\n {\n fullScreen: 'compact',\n dividers: true,\n class: {\n content: [\n 'medium:-mx-[24px] medium:mb-[24px] medium:border-y medium:border-outline-variant',\n 'medium:px-[24px] medium:py-[8px]',\n ],\n },\n },\n /*\n * `transition=\"scale\"`, the library's original pop (an extension beyond the M3 dialog\n * motion): the scrim fades on the default effects spring, and the dialog fades in while it\n * scales up from 90% on the default springs, then fades out while it scales to 95% on the\n * fast ones. No clip, no slide, no staggered parts. It scales from the edge it sits\n * against (`--m3-dialog-scale-origin`: the centre for `center`, the top, bottom, start or\n * end edge otherwise). Reduced motion keeps only the fades. Basic dialogs only (from 600px\n * for `compact`).\n */\n {\n fullScreen: 'never',\n transition: 'scale',\n class: {\n scrim: [\n '[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n motion: [\n '[--m3-dialog-slide:0_0] [--m3-dialog-open-clip:none]',\n '[--m3-dialog-enter-clip:none] [--m3-dialog-exit-clip:none]',\n 'origin-(--m3-dialog-scale-origin) scale-none starting:scale-90 data-exiting:scale-95',\n 'motion-reduce:data-exiting:scale-none',\n '[transition-property:opacity,scale] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-fast-easing)]',\n 'data-exiting:[transition-delay:0s]',\n ],\n },\n },\n {\n fullScreen: 'compact',\n transition: 'scale',\n class: {\n scrim: [\n 'medium:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'medium:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n motion: [\n 'medium:[--m3-dialog-slide:0_0] medium:[--m3-dialog-open-clip:none]',\n 'medium:[--m3-dialog-enter-clip:none] medium:[--m3-dialog-exit-clip:none]',\n 'medium:origin-(--m3-dialog-scale-origin) medium:scale-none',\n 'medium:starting:scale-90 medium:data-exiting:scale-95',\n 'medium:motion-reduce:data-exiting:scale-none',\n 'medium:[transition-property:opacity,scale]',\n 'medium:motion-reduce:[transition-property:opacity]',\n 'medium:[transition-duration:var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n 'medium:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-fast-duration)]',\n 'medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-fast-easing)]',\n 'medium:data-exiting:[transition-delay:0s]',\n ],\n },\n },\n /*\n * Container transform (the spec: \"Use a container transform pattern to transition a FAB\n * into a full-screen dialog\"): the clip starts on the origin's box and corners\n * (`--m3-dialog-origin`, measured by the dialog) and opens to the window on the slow\n * spatial spring, while the container colour moves from the origin's\n * (`--m3-dialog-origin-color`) and the content fades in. Leaving collapses back into the\n * origin on emphasized-accelerate over 250ms (2026-10-15), as the basic exit avoids\n * springs: the fast spatial spring collapsed the clip past the origin to nothing and\n * regrew it while still visible. The container stays opaque for the first 60% and fades\n * over the last 100ms, linear, ending with the collapse (2026-10-17, after Material\n * Components' container transform, whose return fades from 60% to 90%), so it is seen going\n * back into the origin. Reduced motion keeps only the fades (the dialog's and its content's).\n */\n {\n fullScreen: 'always',\n origin: true,\n class: {\n motion: [\n '[--m3-dialog-slide:0_0] [--m3-dialog-open-clip:inset(0_round_0)]',\n '[--m3-dialog-enter-clip:var(--m3-dialog-origin)] [--m3-dialog-exit-clip:var(--m3-dialog-origin)]',\n '[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-2),var(--md-sys-motion-duration-medium-1),var(--md-sys-motion-duration-medium-1)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n // Full screen's exit starts every transition at once; the fade waits here.\n 'data-exiting:[transition-delay:var(--md-sys-motion-duration-short-3),0s,0s]',\n 'motion-reduce:data-exiting:[transition-delay:0s]',\n ],\n panel: [\n '[transition-property:background-color] motion-reduce:[transition-property:none]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'starting:bg-(--m3-dialog-origin-color) motion-safe:data-exiting:bg-(--m3-dialog-origin-color)',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n '*:[transition-property:opacity] *:starting:opacity-0 data-exiting:*:opacity-0',\n '*:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '*:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n ],\n },\n },\n {\n fullScreen: 'compact',\n origin: true,\n class: {\n motion: [\n 'max-medium:[--m3-dialog-slide:0_0] max-medium:[--m3-dialog-open-clip:inset(0_round_0)]',\n 'max-medium:[--m3-dialog-enter-clip:var(--m3-dialog-origin)]',\n 'max-medium:[--m3-dialog-exit-clip:var(--m3-dialog-origin)]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-2),var(--md-sys-motion-duration-medium-1),var(--md-sys-motion-duration-medium-1)]',\n 'max-medium:data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n 'max-medium:data-exiting:[transition-delay:var(--md-sys-motion-duration-short-3),0s,0s]',\n // The breakpoint outranks the base reduced-motion exit: restate it, so the fade\n // keeps its duration and starts at once while the spatial springs are instant.\n 'max-medium:motion-reduce:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n 'max-medium:motion-reduce:data-exiting:[transition-delay:0s]',\n ],\n panel: [\n 'max-medium:[transition-property:background-color]',\n 'max-medium:motion-reduce:[transition-property:none]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'max-medium:starting:bg-(--m3-dialog-origin-color)',\n 'max-medium:motion-safe:data-exiting:bg-(--m3-dialog-origin-color)',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'max-medium:*:[transition-property:opacity] max-medium:*:starting:opacity-0',\n 'max-medium:data-exiting:*:opacity-0',\n 'max-medium:*:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n 'max-medium:*:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n ],\n },\n },\n ],\n defaultVariants: {\n dividers: false,\n origin: false,\n instant: false,\n transition: 'reveal',\n hasIcon: false,\n fullScreen: 'never',\n placement: 'center',\n bottomBar: false,\n divider: false,\n },\n});\n\n/**\n * The variants of {@link dialogStyles}, for building on its styles. They are the recipe's keys, not\n * component props: their names (`hasIcon`, `isOpen`…) follow the classes and may change.\n */\nexport type DialogStyleProps = VariantProps<typeof dialogStyles>;\n"],"mappings":";;;AA6CA,MAAa,oBAAoB;CAAE,UAAU;CAAS,OAAO;AAAE;;AAG/D,MAAa,eAAe,GAAG;CAC7B,OAAO;EACL,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAKA,MAAM;EACN,YAAY;EAeZ,QAAQ;GACN;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAQA,OAAO;EACP,OAAO;GACL;GACA;GACA;GACA;GAEA;EACF;EACA,MAAM,CACJ,qDACA,0DACF;EACA,OAAO,CACL,4CACA,oDACF;EACA,QAAQ;EACR,cAAc;EACd,OAAO;EACP,SAAS;GACP;GACA;GACA;EACF;EAKA,SAAS,CACP,2FACA,wBACF;CACF;CACA,UAAU;EACR,SAAS;GACP,MAAM,EAAE,OAAO,cAAc;GAC7B,OAAO,EAAE,OAAO,aAAa;EAC/B;EAQA,WAAW;GACT,QAAQ,EAAE,YAAY,8BAA8B;GACpD,KAAK;IACH,YAAY;IACZ,QAAQ;GACV;GACA,QAAQ;IACN,YAAY;IACZ,QAAQ;KACN;KACA;KACA;IACF;GACF;GACA,OAAO;IACL,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;IACF;GACF;GACA,KAAK;IACH,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA,YAAY;GACV,OAAO;IACL,cAAc;IACd,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;GAMA,QAAQ;IACN,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO,CACL,gEACA,2BACF;IACA,QAAQ;IACR,OAAO;IACP,SAAS;IACT,SAAS;GACX;GACA,SAAS;IACP,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;IACF;IACA,QAAQ,CACN,mFACA,+DACF;IACA,cAAc;IACd,OAAO,CACL,gFACA,mEACF;IACA,SAAS;IACT,SAAS;GACX;EACF;;EAEA,WAAW;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEjC,SAAS;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAE/B,UAAU;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEhC,QAAQ;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;;;;EAK9B,YAAY;GAAE,QAAQ,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEpC,SAAS;GACP,MAAM;IACJ,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;GACT;GACA,OAAO,CAAC;EACV;CACF;CACA,kBAAkB;EAChB;GACE,YAAY;GACZ,WAAW;GACX,OAAO,EACL,SAAS,6EACX;EACF;EACA;GACE,YAAY;GACZ,WAAW;GACX,OAAO,EACL,SACE,+IACJ;EACF;EACA;GACE,YAAY;GACZ,SAAS;GACT,OAAO,EAAE,QAAQ,kCAAkC;EACrD;EACA;GACE,YAAY;GACZ,SAAS;GACT,OAAO,EAAE,QAAQ,wDAAwD;EAC3E;EAKA;GACE,YAAY;GACZ,UAAU;GACV,OAAO,EACL,SAAS,0EACX;EACF;EACA;GACE,YAAY;GACZ,UAAU;GACV,OAAO,EACL,SAAS,CACP,oFACA,kCACF,EACF;EACF;EAUA;GACE,YAAY;GACZ,YAAY;GACZ,OAAO;IACL,OAAO;KACL;KACA;KACA;KACA;IACF;IACA,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA;GACE,YAAY;GACZ,YAAY;GACZ,OAAO;IACL,OAAO;KACL;KACA;KACA;KACA;IACF;IACA,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EAcA;GACE,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KAEA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA;GACE,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KAGA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;CACF;CACA,iBAAiB;EACf,UAAU;EACV,QAAQ;EACR,SAAS;EACT,YAAY;EACZ,SAAS;EACT,YAAY;EACZ,WAAW;EACX,WAAW;EACX,SAAS;CACX;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"dialog-styles.js","names":[],"sources":["../../../src/components/dialog/dialog-styles.ts"],"sourcesContent":["import { tv, type VariantProps } from '../../utils/tv';\n\n/*\n * Values follow Compose Material 3 (AlertDialog.kt and DialogTokens): 280–560px wide (the\n * minimum capped by the window's 24px margins), 24px padding, 28px corners,\n * surface-container-high at elevation 3, a 24px secondary icon and the title 16px apart, the\n * title centred when there is an icon, 24px below the supporting text, 8px between actions,\n * and stacked actions with the confirming action on top. Optional dividers above and below\n * the content are 1px `outline-variant`. The scrim is `scrim` at 32% (M3).\n *\n * Motion (2026-10-14): Compose has no dialog motion of its own (the platform animates\n * windows), so the basic dialog follows the M3 dialog enter and exit as Material Web encodes\n * it, mapped onto the M3 Expressive springs (spatial for movement and size, effects for\n * opacity). Entering, the dialog slides 50px away from the window edge it sits against\n * (downward when centred), its container grows from that edge from 0 to its full size (a\n * clip on a library-owned wrapper, so text is never shown outside the container and the\n * spec's 0 start is kept), and it fades in on the fast effects spring while the scrim fades\n * in on the slow one; the headline, icon and supporting text fade in after 50ms and the\n * actions after 150ms. Leaving follows the reference's close timing exactly, on M3's\n * emphasized-accelerate easing and duration tokens: the parts fade out over 100ms, the\n * dialog slides back 50px and its container shrinks to 35% over 150ms (slow at first, so\n * it is still moving and shrinking until it is gone), the container fades out from 100ms to\n * 150ms, and the scrim fades out over 150ms. Reduced motion keeps only the\n * fades of the dialog and the scrim; `instant` turns all of it off.\n * The positioner keeps 24px from the window's edges on compact windows and the spec's 56px\n * on wider ones, and `placement` aligns the dialog in it.\n *\n * Full-screen dialogs follow the M3 dialog spec's full-screen type: the panel fills the\n * window on `surface-container-high` with no corners, elevation or padding; a 56px header\n * holds the `on-surface` close icon button, the `title-large` headline and the confirming\n * text button (with an optional `outline-variant` divider), and the content is padded 24px\n * at the top and sides. With a header action `DialogActions` are hidden; without one they\n * form a 56px bottom action bar. The panel slides up 48px and fades in on the slow springs\n * (the spec's speed for full-screen animations), or, with an `origin`, grows out of it (a\n * container transform). `fullScreen: 'compact'` applies all of this only below 600px (the M3\n * compact window class) and is a basic dialog otherwise.\n *\n * The basic dialog's container colour, corners and shadow, and the icon, title and supporting\n * text colours, come from the dialog's component tokens (`dialog-tokens.ts`,\n * `--md-comp-dialog-*`); the panel carries `data-tokens=\"md-comp-dialog\"`, and the parts read\n * one private variable each. A full-screen panel keeps its own `surface-container-high`. A\n * consumer class (`bg-surface-container`) still wins. Every class is written out in full.\n */\n\n/** The dialog root's placement, inline so it wins over consumer layout classes. */\nexport const DIALOG_ROOT_STYLE = { position: 'fixed', inset: 0 } as const;\n\n/** Variant definitions for {@link Dialog} and its parts. */\nexport const dialogStyles = tv({\n slots: {\n scrim: [\n 'fixed inset-0 z-(--md-sys-z-scrim) bg-scrim/32 opacity-100',\n '[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'starting:opacity-0',\n 'data-exiting:opacity-0',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n // The dialog's outermost element, which takes the consumer's `className` and `style`. It\n // covers the window through an inline `position: fixed; inset: 0` (`DIALOG_ROOT_STYLE`),\n // which a consumer class can't move: a layout class such as `static` or `absolute top-24`\n // never puts the dialog in the page's flow or out of the window.\n root: 'z-(--md-sys-z-dialog)',\n positioner: 'fixed inset-0 z-(--md-sys-z-dialog) flex p-[24px] medium:p-[56px]',\n /*\n * The library-owned wrapper that moves: it slides 50px (`--m3-dialog-slide`), its clip\n * grows the container (`--m3-dialog-enter-clip` → `--m3-dialog-open-clip`, which rests\n * 32px outside the panel so the shadow shows, its corners concentric with the panel's\n * `--m3-dialog-corner`) and it fades. Leaving, the clip shrinks to 35%\n * (`--m3-dialog-exit-clip`) and the fade waits 100ms for the parts to fade first. The\n * exit uses the reference's curves rather than springs (2026-10-14): the slide and shrink\n * run 150ms on emphasized-accelerate, which never overshoots and keeps moving until the\n * fade (50ms, linear, after 100ms) has ended. A spring front-loads the motion: the\n * expressive spatial one overshot past 50px and below 35%, and the critically damped\n * effects one finished shrinking before the fade, leaving a still 35% box fading. The\n * clip's sides open from the panel's edges to the shadow's 32px together with its corner\n * radius, so the growing edge keeps the panel's corners on every frame.\n */\n motion: [\n 'flex max-h-full max-w-full',\n '[--m3-dialog-corner:var(--md-comp-dialog-container-shape,var(--md-sys-shape-corner-extra-large))]',\n '[--m3-dialog-open-clip:inset(-32px_round_calc(var(--m3-dialog-corner)_+_32px))]',\n '[--m3-dialog-enter-clip:inset(0_0_100%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_0_65%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:0_-50px] [--m3-dialog-scale-origin:center]',\n 'translate-none opacity-100 [clip-path:var(--m3-dialog-open-clip)]',\n 'starting:[translate:var(--m3-dialog-slide)] starting:opacity-0',\n 'starting:[clip-path:var(--m3-dialog-enter-clip)]',\n 'data-exiting:[translate:var(--m3-dialog-slide)] data-exiting:opacity-0',\n 'data-exiting:[clip-path:var(--m3-dialog-exit-clip)]',\n 'motion-reduce:data-exiting:translate-none',\n 'motion-reduce:data-exiting:[clip-path:var(--m3-dialog-open-clip)]',\n '[transition-property:opacity,translate,clip-path] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-1),var(--md-sys-motion-duration-short-3),var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n 'data-exiting:[transition-delay:var(--md-sys-motion-duration-short-2),0s,0s]',\n 'motion-reduce:data-exiting:[transition-delay:0s]',\n 'motion-reduce:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n ],\n /*\n * Classes for the panel that stagger its parts (its children): every part fades in after\n * 50ms on the default effects spring (the headline, icon and supporting text, and any\n * custom child), and the actions (`data-slot=\"actions\"`) after 150ms on the fast one.\n * Leaving, they all fade out at once on the fast spring. Basic dialogs only (see the\n * `fullScreen` variants); reduced motion leaves the parts to the wrapper's fade.\n */\n parts: '',\n panel: [\n 'flex max-h-full min-w-[min(280px,calc(100vw-48px))] max-w-[560px] flex-col p-[24px]',\n 'rounded-[var(--_md-comp-dialog-container-shape)] bg-[var(--_md-comp-dialog-container-color)]',\n 'text-on-surface shadow-[shadow:var(--_md-comp-dialog-container-elevation)]',\n 'outline-none',\n // Forced colours drop the fill and shadow, so the panel draws its edge instead.\n 'forced-colors:outline-solid forced-colors:outline-1 forced-colors:outline-[CanvasText]',\n ],\n icon: [\n 'mx-auto inline-flex pb-[16px] [&>svg]:size-[24px]',\n 'text-[color:var(--_md-comp-dialog-with-icon-icon-color)]',\n ],\n title: [\n 'pb-[16px] text-headline-small font-brand',\n 'text-[color:var(--_md-comp-dialog-headline-color)]',\n ],\n header: '',\n headerButton: '',\n close: '[--md-comp-icon-button-icon-color:var(--md-sys-color-on-surface)]',\n content: [\n // 8px of room above the first field, for an outlined field's label, which sits across\n // its top edge and would be clipped by this scroller. The margin takes the same 8px off\n // the title's spacing, so nothing moves.\n '-mt-[8px] min-h-0 flex-1 overflow-y-auto pt-[8px] pb-[24px] text-body-medium',\n 'text-[color:var(--_md-comp-dialog-supporting-text-color)]',\n 'focus-ring',\n ],\n // Stacked (`data-stacked`, set by `DialogActions` when they don't fit on one line), the\n // buttons are rendered confirming action first and wrap forwards instead of in reverse:\n // the same picture, sizes included, in focus order. The custom property tells it\n // whether the layout lets them stack.\n actions: [\n 'flex flex-wrap-reverse items-center justify-end gap-[8px] [--m3-dialog-actions-stack:1]',\n 'data-stacked:flex-wrap',\n ],\n },\n variants: {\n hasIcon: {\n true: { title: 'text-center' },\n false: { title: 'text-start' },\n },\n /*\n * The dialog enters from the window edge it sits against (the spec's enter and exit\n * pattern): it slides 50px away from that edge while its container grows away from it,\n * and leaves the same way back. Centred or at the top it slides down and grows downward\n * (the reference motion), at the bottom it slides up and grows upward, and at the start\n * or end it moves and grows along the x axis, mirrored in right-to-left layouts.\n */\n placement: {\n center: { positioner: 'items-center justify-center' },\n top: {\n positioner: 'items-start justify-center',\n motion: '[--m3-dialog-scale-origin:top]',\n },\n bottom: {\n positioner: 'items-end justify-center',\n motion: [\n '[--m3-dialog-enter-clip:inset(100%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(65%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:0_50px] [--m3-dialog-scale-origin:bottom]',\n ],\n },\n start: {\n positioner: 'items-center justify-start',\n motion: [\n '[--m3-dialog-enter-clip:inset(0_100%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_65%_0_0_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:-50px_0] [--m3-dialog-scale-origin:left]',\n 'rtl:[--m3-dialog-enter-clip:inset(0_0_0_100%_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-exit-clip:inset(0_0_0_65%_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-slide:50px_0] rtl:[--m3-dialog-scale-origin:right]',\n ],\n },\n end: {\n positioner: 'items-center justify-end',\n motion: [\n '[--m3-dialog-enter-clip:inset(0_0_0_100%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-exit-clip:inset(0_0_0_65%_round_var(--m3-dialog-corner))]',\n '[--m3-dialog-slide:50px_0] [--m3-dialog-scale-origin:right]',\n 'rtl:[--m3-dialog-enter-clip:inset(0_100%_0_0_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-exit-clip:inset(0_65%_0_0_round_var(--m3-dialog-corner))]',\n 'rtl:[--m3-dialog-slide:-50px_0] rtl:[--m3-dialog-scale-origin:left]',\n ],\n },\n },\n fullScreen: {\n never: {\n headerButton: 'hidden',\n parts: [\n 'motion-safe:*:starting:opacity-0 motion-safe:data-exiting:*:opacity-0',\n '*:[transition-property:opacity]',\n '*:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n '*:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n '*:[transition-delay:var(--md-sys-motion-duration-short-1)]',\n '*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n '*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n '*:data-[slot=actions]:[transition-delay:var(--md-sys-motion-duration-short-3)]',\n 'data-exiting:*:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'data-exiting:*:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n 'data-exiting:*:[transition-delay:0s] data-exiting:*:data-[slot=actions]:[transition-delay:0s]',\n 'data-exiting:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'data-exiting:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n },\n /*\n * Full screen keeps its own motion: the dialog slides up 48px as it fades in on the slow\n * springs (the spec's speed for full-screen motion) with no clip, and slides back down\n * as it fades out on the fast ones, its parts fading with it.\n */\n always: {\n positioner: 'p-0 medium:p-0',\n motion: [\n 'size-full [--m3-dialog-slide:0_48px]',\n '[--m3-dialog-open-clip:none] [--m3-dialog-enter-clip:none] [--m3-dialog-exit-clip:none]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'data-exiting:[transition-delay:0s]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n panel: [\n 'size-full max-h-none max-w-none rounded-none p-0 shadow-none',\n 'bg-surface-container-high',\n ],\n header: 'flex h-[56px] shrink-0 items-center gap-[4px] ps-[4px] pe-[12px]',\n title: 'min-w-0 flex-1 truncate ps-[4px] pb-0 text-start text-title-large',\n content: 'mt-0 px-[24px] pt-[24px]',\n actions: 'hidden',\n },\n compact: {\n positioner: 'max-medium:p-0',\n motion: [\n 'max-medium:size-full max-medium:[--m3-dialog-slide:0_48px]',\n 'max-medium:[--m3-dialog-open-clip:none] max-medium:[--m3-dialog-enter-clip:none]',\n 'max-medium:[--m3-dialog-exit-clip:none]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'max-medium:data-exiting:[transition-delay:0s]',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'max-medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n parts: [\n 'medium:motion-safe:*:starting:opacity-0 medium:motion-safe:data-exiting:*:opacity-0',\n 'medium:*:[transition-property:opacity]',\n 'medium:*:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'medium:*:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'medium:*:[transition-delay:var(--md-sys-motion-duration-short-1)]',\n 'medium:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'medium:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n 'medium:*:data-[slot=actions]:[transition-delay:var(--md-sys-motion-duration-short-3)]',\n 'medium:data-exiting:*:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'medium:data-exiting:*:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n 'medium:data-exiting:*:[transition-delay:0s]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-delay:0s]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-duration:var(--md-sys-motion-duration-short-2)]',\n 'medium:data-exiting:*:data-[slot=actions]:[transition-timing-function:var(--md-sys-motion-easing-linear)]',\n ],\n panel: [\n 'max-medium:size-full max-medium:max-h-none max-medium:max-w-none',\n 'max-medium:rounded-none max-medium:p-0 max-medium:shadow-none',\n 'max-medium:bg-surface-container-high',\n ],\n header: [\n 'max-medium:flex max-medium:h-[56px] max-medium:shrink-0 max-medium:items-center',\n 'max-medium:gap-[4px] max-medium:ps-[4px] max-medium:pe-[12px]',\n ],\n headerButton: 'medium:hidden',\n title: [\n 'max-medium:min-w-0 max-medium:flex-1 max-medium:truncate max-medium:ps-[4px]',\n 'max-medium:pb-0 max-medium:text-start max-medium:text-title-large',\n ],\n content: 'max-medium:mt-0 max-medium:px-[24px] max-medium:pt-[24px]',\n actions: 'max-medium:hidden',\n },\n },\n /** Full screen without a header action: the actions form a 56px bottom bar. */\n bottomBar: { true: {}, false: {} },\n /** A divider under the full-screen header. */\n divider: { true: {}, false: {} },\n /** The basic dialog's optional dividers above and below `DialogContent`. */\n dividers: { true: {}, false: {} },\n /** A container transform from a trigger (`origin`) into the full-screen dialog. */\n origin: { true: {}, false: {} },\n /**\n * The basic dialog's enter and exit: `reveal`, the M3 dialog motion above, or `scale`,\n * the original pop (see the compound variants). Full-screen dialogs ignore it.\n */\n transition: { reveal: {}, scale: {} },\n /** No enter or exit motion: the dialog, its parts and the scrim appear and go at once. */\n instant: {\n true: {\n scrim: '[transition-property:none]!',\n motion: '[transition-property:none]!',\n panel: '[transition-property:none]!',\n parts: '*:[transition-property:none]!',\n },\n false: {},\n },\n },\n compoundVariants: [\n {\n fullScreen: 'always',\n bottomBar: true,\n class: {\n actions: 'flex h-[56px] shrink-0 flex-nowrap px-[24px] [--m3-dialog-actions-stack:0]',\n },\n },\n {\n fullScreen: 'compact',\n bottomBar: true,\n class: {\n actions:\n 'max-medium:flex max-medium:h-[56px] max-medium:shrink-0 max-medium:flex-nowrap max-medium:px-[24px] max-medium:[--m3-dialog-actions-stack:0]',\n },\n },\n {\n fullScreen: 'always',\n divider: true,\n class: { header: 'border-b border-outline-variant' },\n },\n {\n fullScreen: 'compact',\n divider: true,\n class: { header: 'max-medium:border-b max-medium:border-outline-variant' },\n },\n /*\n * Dividers run the panel's full width, 1px `outline-variant`, with 8px between them and\n * the content; the body keeps 24px to the actions below the bottom one.\n */\n {\n fullScreen: 'never',\n dividers: true,\n class: {\n content: 'mt-0 -mx-[24px] mb-[24px] border-y border-outline-variant px-[24px] py-[8px]',\n },\n },\n {\n fullScreen: 'compact',\n dividers: true,\n class: {\n content: [\n 'medium:mt-0 medium:-mx-[24px] medium:mb-[24px] medium:border-y medium:border-outline-variant',\n 'medium:px-[24px] medium:py-[8px]',\n ],\n },\n },\n /*\n * `transition=\"scale\"`, the library's original pop (an extension beyond the M3 dialog\n * motion): the scrim fades on the default effects spring, and the dialog fades in while it\n * scales up from 90% on the default springs, then fades out while it scales to 95% on the\n * fast ones. No clip, no slide, no staggered parts. It scales from the edge it sits\n * against (`--m3-dialog-scale-origin`: the centre for `center`, the top, bottom, start or\n * end edge otherwise). Reduced motion keeps only the fades. Basic dialogs only (from 600px\n * for `compact`).\n */\n {\n fullScreen: 'never',\n transition: 'scale',\n class: {\n scrim: [\n '[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n motion: [\n '[--m3-dialog-slide:0_0] [--m3-dialog-open-clip:none]',\n '[--m3-dialog-enter-clip:none] [--m3-dialog-exit-clip:none]',\n 'origin-(--m3-dialog-scale-origin) scale-none starting:scale-90 data-exiting:scale-95',\n 'motion-reduce:data-exiting:scale-none',\n '[transition-property:opacity,scale] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-fast-duration)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-fast-easing)]',\n 'data-exiting:[transition-delay:0s]',\n ],\n },\n },\n {\n fullScreen: 'compact',\n transition: 'scale',\n class: {\n scrim: [\n 'medium:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'medium:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n 'medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing)]',\n ],\n motion: [\n 'medium:[--m3-dialog-slide:0_0] medium:[--m3-dialog-open-clip:none]',\n 'medium:[--m3-dialog-enter-clip:none] medium:[--m3-dialog-exit-clip:none]',\n 'medium:origin-(--m3-dialog-scale-origin) medium:scale-none',\n 'medium:starting:scale-90 medium:data-exiting:scale-95',\n 'medium:motion-reduce:data-exiting:scale-none',\n 'medium:[transition-property:opacity,scale]',\n 'medium:motion-reduce:[transition-property:opacity]',\n 'medium:[transition-duration:var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-spatial-default-duration)]',\n 'medium:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-spatial-default-easing)]',\n 'medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-fast-duration)]',\n 'medium:data-exiting:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-fast-easing)]',\n 'medium:data-exiting:[transition-delay:0s]',\n ],\n },\n },\n /*\n * Container transform (the spec: \"Use a container transform pattern to transition a FAB\n * into a full-screen dialog\"): the clip starts on the origin's box and corners\n * (`--m3-dialog-origin`, measured by the dialog) and opens to the window on the slow\n * spatial spring, while the container colour moves from the origin's\n * (`--m3-dialog-origin-color`) and the content fades in. Leaving collapses back into the\n * origin on emphasized-accelerate over 250ms (2026-10-15), as the basic exit avoids\n * springs: the fast spatial spring collapsed the clip past the origin to nothing and\n * regrew it while still visible. The container stays opaque for the first 60% and fades\n * over the last 100ms, linear, ending with the collapse (2026-10-17, after Material\n * Components' container transform, whose return fades from 60% to 90%), so it is seen going\n * back into the origin. Reduced motion keeps only the fades (the dialog's and its content's).\n */\n {\n fullScreen: 'always',\n origin: true,\n class: {\n motion: [\n '[--m3-dialog-slide:0_0] [--m3-dialog-open-clip:inset(0_round_0)]',\n '[--m3-dialog-enter-clip:var(--m3-dialog-origin)] [--m3-dialog-exit-clip:var(--m3-dialog-origin)]',\n '[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'data-exiting:[transition-duration:var(--md-sys-motion-duration-short-2),var(--md-sys-motion-duration-medium-1),var(--md-sys-motion-duration-medium-1)]',\n 'data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n // Full screen's exit starts every transition at once; the fade waits here.\n 'data-exiting:[transition-delay:var(--md-sys-motion-duration-short-3),0s,0s]',\n 'motion-reduce:data-exiting:[transition-delay:0s]',\n ],\n panel: [\n '[transition-property:background-color] motion-reduce:[transition-property:none]',\n '[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'starting:bg-(--m3-dialog-origin-color) motion-safe:data-exiting:bg-(--m3-dialog-origin-color)',\n 'data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n '*:[transition-property:opacity] *:starting:opacity-0 data-exiting:*:opacity-0',\n '*:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n '*:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n ],\n },\n },\n {\n fullScreen: 'compact',\n origin: true,\n class: {\n motion: [\n 'max-medium:[--m3-dialog-slide:0_0] max-medium:[--m3-dialog-open-clip:inset(0_round_0)]',\n 'max-medium:[--m3-dialog-enter-clip:var(--m3-dialog-origin)]',\n 'max-medium:[--m3-dialog-exit-clip:var(--m3-dialog-origin)]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration),var(--md-sys-motion-spring-spatial-slow-duration),var(--md-sys-motion-spring-spatial-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-fast-easing),var(--md-sys-motion-spring-spatial-slow-easing),var(--md-sys-motion-spring-spatial-slow-easing)]',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-2),var(--md-sys-motion-duration-medium-1),var(--md-sys-motion-duration-medium-1)]',\n 'max-medium:data-exiting:[transition-timing-function:var(--md-sys-motion-easing-linear),var(--md-sys-motion-easing-emphasized-accelerate),var(--md-sys-motion-easing-emphasized-accelerate)]',\n 'max-medium:data-exiting:[transition-delay:var(--md-sys-motion-duration-short-3),0s,0s]',\n // The breakpoint outranks the base reduced-motion exit: restate it, so the fade\n // keeps its duration and starts at once while the spatial springs are instant.\n 'max-medium:motion-reduce:data-exiting:[transition-duration:var(--md-sys-motion-duration-short-3)]',\n 'max-medium:motion-reduce:data-exiting:[transition-delay:0s]',\n ],\n panel: [\n 'max-medium:[transition-property:background-color]',\n 'max-medium:motion-reduce:[transition-property:none]',\n 'max-medium:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n 'max-medium:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n 'max-medium:starting:bg-(--m3-dialog-origin-color)',\n 'max-medium:motion-safe:data-exiting:bg-(--m3-dialog-origin-color)',\n 'max-medium:data-exiting:[transition-duration:var(--md-sys-motion-spring-effects-fast-duration)]',\n 'max-medium:*:[transition-property:opacity] max-medium:*:starting:opacity-0',\n 'max-medium:data-exiting:*:opacity-0',\n 'max-medium:*:[transition-duration:var(--md-sys-motion-spring-effects-slow-duration)]',\n 'max-medium:*:[transition-timing-function:var(--md-sys-motion-spring-effects-slow-easing)]',\n ],\n },\n },\n ],\n defaultVariants: {\n dividers: false,\n origin: false,\n instant: false,\n transition: 'reveal',\n hasIcon: false,\n fullScreen: 'never',\n placement: 'center',\n bottomBar: false,\n divider: false,\n },\n});\n\n/**\n * The variants of {@link dialogStyles}, for building on its styles. They are the recipe's keys, not\n * component props: their names (`hasIcon`, `isOpen`…) follow the classes and may change.\n */\nexport type DialogStyleProps = VariantProps<typeof dialogStyles>;\n"],"mappings":";;;AA6CA,MAAa,oBAAoB;CAAE,UAAU;CAAS,OAAO;AAAE;;AAG/D,MAAa,eAAe,GAAG;CAC7B,OAAO;EACL,OAAO;GACL;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAKA,MAAM;EACN,YAAY;EAeZ,QAAQ;GACN;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EAQA,OAAO;EACP,OAAO;GACL;GACA;GACA;GACA;GAEA;EACF;EACA,MAAM,CACJ,qDACA,0DACF;EACA,OAAO,CACL,4CACA,oDACF;EACA,QAAQ;EACR,cAAc;EACd,OAAO;EACP,SAAS;GAIP;GACA;GACA;EACF;EAKA,SAAS,CACP,2FACA,wBACF;CACF;CACA,UAAU;EACR,SAAS;GACP,MAAM,EAAE,OAAO,cAAc;GAC7B,OAAO,EAAE,OAAO,aAAa;EAC/B;EAQA,WAAW;GACT,QAAQ,EAAE,YAAY,8BAA8B;GACpD,KAAK;IACH,YAAY;IACZ,QAAQ;GACV;GACA,QAAQ;IACN,YAAY;IACZ,QAAQ;KACN;KACA;KACA;IACF;GACF;GACA,OAAO;IACL,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;IACF;GACF;GACA,KAAK;IACH,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA,YAAY;GACV,OAAO;IACL,cAAc;IACd,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;GAMA,QAAQ;IACN,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO,CACL,gEACA,2BACF;IACA,QAAQ;IACR,OAAO;IACP,SAAS;IACT,SAAS;GACX;GACA,SAAS;IACP,YAAY;IACZ,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;IACF;IACA,QAAQ,CACN,mFACA,+DACF;IACA,cAAc;IACd,OAAO,CACL,gFACA,mEACF;IACA,SAAS;IACT,SAAS;GACX;EACF;;EAEA,WAAW;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEjC,SAAS;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAE/B,UAAU;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEhC,QAAQ;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;;;;;EAK9B,YAAY;GAAE,QAAQ,CAAC;GAAG,OAAO,CAAC;EAAE;;EAEpC,SAAS;GACP,MAAM;IACJ,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;GACT;GACA,OAAO,CAAC;EACV;CACF;CACA,kBAAkB;EAChB;GACE,YAAY;GACZ,WAAW;GACX,OAAO,EACL,SAAS,6EACX;EACF;EACA;GACE,YAAY;GACZ,WAAW;GACX,OAAO,EACL,SACE,+IACJ;EACF;EACA;GACE,YAAY;GACZ,SAAS;GACT,OAAO,EAAE,QAAQ,kCAAkC;EACrD;EACA;GACE,YAAY;GACZ,SAAS;GACT,OAAO,EAAE,QAAQ,wDAAwD;EAC3E;EAKA;GACE,YAAY;GACZ,UAAU;GACV,OAAO,EACL,SAAS,+EACX;EACF;EACA;GACE,YAAY;GACZ,UAAU;GACV,OAAO,EACL,SAAS,CACP,gGACA,kCACF,EACF;EACF;EAUA;GACE,YAAY;GACZ,YAAY;GACZ,OAAO;IACL,OAAO;KACL;KACA;KACA;KACA;IACF;IACA,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA;GACE,YAAY;GACZ,YAAY;GACZ,OAAO;IACL,OAAO;KACL;KACA;KACA;KACA;IACF;IACA,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EAcA;GACE,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KAEA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;EACA;GACE,YAAY;GACZ,QAAQ;GACR,OAAO;IACL,QAAQ;KACN;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KAGA;KACA;IACF;IACA,OAAO;KACL;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;KACA;IACF;GACF;EACF;CACF;CACA,iBAAiB;EACf,UAAU;EACV,QAAQ;EACR,SAAS;EACT,YAAY;EACZ,SAAS;EACT,YAAY;EACZ,WAAW;EACX,WAAW;EACX,SAAS;CACX;AACF,CAAC"}
|
|
@@ -113,6 +113,9 @@ export type IconButtonProps = IconButtonActionProps | IconButtonLinkProps | Icon
|
|
|
113
113
|
* Shares `size`, `shape` and `disabled` with `ButtonContext`, so it fits in button groups,
|
|
114
114
|
* and takes its default variant from it (`iconButtonVariant`).
|
|
115
115
|
*
|
|
116
|
+
* To animate its size or position, put the transition on a wrapper: while pressed, the button's
|
|
117
|
+
* own motion replaces the timing of a transition added through `className`.
|
|
118
|
+
*
|
|
116
119
|
* @example
|
|
117
120
|
* <IconButton icon={<SearchIcon />} aria-label="Search" onPress={openSearch} />
|
|
118
121
|
* <IconButton variant="standard" icon={<MoreIcon />} aria-label="More options" />
|
|
@@ -24,6 +24,9 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
24
24
|
* Shares `size`, `shape` and `disabled` with `ButtonContext`, so it fits in button groups,
|
|
25
25
|
* and takes its default variant from it (`iconButtonVariant`).
|
|
26
26
|
*
|
|
27
|
+
* To animate its size or position, put the transition on a wrapper: while pressed, the button's
|
|
28
|
+
* own motion replaces the timing of a transition added through `className`.
|
|
29
|
+
*
|
|
27
30
|
* @example
|
|
28
31
|
* <IconButton icon={<SearchIcon />} aria-label="Search" onPress={openSearch} />
|
|
29
32
|
* <IconButton variant="standard" icon={<MoreIcon />} aria-label="More options" />
|