@mx-cartographer/experiences 9.4.46 → 9.4.47

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [9.4.47] - 09-30-2026
2
+
3
+ - **FIXED** - Confirmation dialogs now return screen reader focus to the row that opened them instead of stranding it (MEW-4016)
4
+
1
5
  ## [9.4.46] - 09-30-2026
2
6
 
3
7
  - **FIXED** - Tags drawer rows no longer nest a checkbox inside a `role="checkbox"` button (MEW-4124)
@@ -4,7 +4,8 @@ export type CopyObject = {
4
4
  close_aria?: string;
5
5
  title: string;
6
6
  };
7
- export interface DialogProps extends Omit<MuiDialogProps, 'open'> {
7
+ type OwnedMuiProps = 'disableRestoreFocus' | 'onFocus' | 'open' | 'slotProps' | 'slots' | 'TransitionComponent' | 'TransitionProps';
8
+ export interface DialogProps extends Omit<MuiDialogProps, OwnedMuiProps> {
8
9
  className?: string;
9
10
  copy: CopyObject;
10
11
  disablePrimaryButton?: boolean;
@@ -1,51 +1,72 @@
1
- import { useScreenSize as P } from "../../hooks/useScreenSize.es.js";
2
- import A from "react";
3
- import { DialogFooter as M, DialogHeader as H } from "@mxenabled/mxui";
4
- import { jsx as r, jsxs as j } from "react/jsx-runtime";
5
- import k from "@mui/material/Dialog";
6
- import v from "@mui/material/DialogContent";
7
- var N = ({ className: l, copy: a, disablePrimaryButton: s = !1, isOpen: n = !1, onClose: i, onPrimaryAction: c, primaryColor: m = "primary", primaryText: d = "Confirm", onSecondaryAction: e, secondaryColor: p = "primary", secondaryText: u = "Cancel", children: f, ...g }) => {
8
- const { sx: o, ...x } = g, h = a?.title ?? "", D = a?.close_aria ?? "Close", t = A.useId(), { isSmallMobile: y } = P(), b = () => {
9
- c?.(), i();
10
- }, S = () => {
11
- e && e(), i();
1
+ import { useScreenSize as T } from "../../hooks/useScreenSize.es.js";
2
+ import r from "react";
3
+ import { DialogFooter as k, DialogHeader as C } from "@mxenabled/mxui";
4
+ import { jsx as i, jsxs as L } from "react/jsx-runtime";
5
+ import j from "@mui/material/Dialog";
6
+ import w from "@mui/material/DialogContent";
7
+ var N = ({ className: p, copy: l, disablePrimaryButton: g = !1, isOpen: c = !1, onClose: n, onPrimaryAction: x, primaryColor: h = "primary", primaryText: y = "Confirm", onSecondaryAction: u, secondaryColor: D = "primary", secondaryText: b = "Cancel", children: R, ...E }) => {
8
+ const { sx: m, ...M } = E, S = l?.title ?? "", P = l?.close_aria ?? "Close", f = r.useId(), { isSmallMobile: v } = T(), a = r.useRef(null), o = r.useRef(null), s = r.useRef(null);
9
+ r.useLayoutEffect(() => {
10
+ if (!c) return;
11
+ o.current = null;
12
+ const e = document.activeElement;
13
+ s.current = e instanceof HTMLElement && e !== document.body && !a.current?.contains(e) ? e : null;
14
+ }, [c]);
15
+ const H = (e) => {
16
+ const { relatedTarget: t } = e;
17
+ o.current === null && t instanceof HTMLElement && !e.currentTarget.contains(t) && (o.current = t);
18
+ }, d = () => {
19
+ const e = o.current ?? s.current;
20
+ if (o.current = null, s.current = null, !e?.isConnected) return;
21
+ const t = e.ownerDocument.activeElement;
22
+ (!t || t === e.ownerDocument.body || a.current?.contains(t)) && e.focus();
12
23
  };
13
- return /* @__PURE__ */ r("div", {
14
- className: `mx-cmn-dialog ${l}`,
15
- children: /* @__PURE__ */ j(k, {
16
- "aria-labelledby": t,
24
+ r.useEffect(() => () => queueMicrotask(d), []);
25
+ const A = () => {
26
+ x?.(), n();
27
+ }, F = () => {
28
+ u && u(), n();
29
+ };
30
+ return /* @__PURE__ */ i("div", {
31
+ className: `mx-cmn-dialog ${p}`,
32
+ children: /* @__PURE__ */ L(j, {
33
+ "aria-labelledby": f,
17
34
  maxWidth: "xs",
18
- onClose: i,
19
- open: n,
35
+ onClose: n,
36
+ open: c,
20
37
  sx: [{
21
38
  "& .MuiDialog-paperScrollPaper": { backgroundColor: "background.default" },
22
- ...y && { "& .MuiDialog-paper": { minWidth: "100%" } },
39
+ ...v && { "& .MuiDialog-paper": { minWidth: "100%" } },
23
40
  height: "100%"
24
- }, ...o ? [o] : []],
25
- ...x,
41
+ }, ...m ? [m] : []],
42
+ ...M,
43
+ disableRestoreFocus: !0,
44
+ onFocus: H,
45
+ ref: a,
46
+ slotProps: { transition: { onExited: d } },
26
47
  children: [
27
- /* @__PURE__ */ r(H, {
48
+ /* @__PURE__ */ i(C, {
28
49
  ariaHidden: !0,
29
50
  copy: {
30
- title: h,
31
- close_aria: D
51
+ title: S,
52
+ close_aria: P
32
53
  },
33
- id: t,
34
- onClose: i,
54
+ id: f,
55
+ onClose: n,
35
56
  truncate: !0
36
57
  }),
37
- /* @__PURE__ */ r(v, {
58
+ /* @__PURE__ */ i(w, {
38
59
  sx: { lineHeight: 1.5 },
39
- children: f
60
+ children: R
40
61
  }),
41
- /* @__PURE__ */ r(M, {
42
- isPrimaryDisabled: s,
43
- onPrimaryAction: b,
44
- onSecondaryAction: S,
45
- primaryColor: m,
46
- primaryText: d,
47
- secondaryColor: p,
48
- secondaryText: u
62
+ /* @__PURE__ */ i(k, {
63
+ isPrimaryDisabled: g,
64
+ onPrimaryAction: A,
65
+ onSecondaryAction: F,
66
+ primaryColor: h,
67
+ primaryText: y,
68
+ secondaryColor: D,
69
+ secondaryText: b
49
70
  })
50
71
  ]
51
72
  })
@@ -1 +1 @@
1
- {"version":3,"file":"Dialog.es.js","names":[],"sources":["../../../../src/common/components/dialog/Dialog.tsx"],"sourcesContent":["import React from 'react'\n\nimport MuiDialog from '@mui/material/Dialog'\nimport { DialogProps as MuiDialogProps } from '@mui/material/Dialog'\nimport DialogContent from '@mui/material/DialogContent'\nimport type { SxProps } from '@mui/material/styles'\n\nimport { DialogFooter, DialogHeader } from '@mxenabled/mxui'\nimport { useScreenSize } from '../../hooks'\n\nexport type CopyObject = {\n close_aria?: string\n title: string\n}\n\nexport interface DialogProps extends Omit<MuiDialogProps, 'open'> {\n className?: string\n copy: CopyObject\n disablePrimaryButton?: boolean\n isOpen: boolean\n onClose: (event?: unknown, reason?: string) => void\n onPrimaryAction?: () => void\n onSecondaryAction?: () => void\n primaryColor?: 'primary' | 'inherit' | 'secondary' | 'success' | 'error' | 'info' | 'warning'\n primaryText?: string\n secondaryColor?: 'primary' | 'inherit' | 'secondary' | 'success' | 'error' | 'info' | 'warning'\n secondaryText?: string\n}\n\nconst Dialog: React.FC<React.PropsWithChildren<DialogProps>> = ({\n className,\n copy,\n disablePrimaryButton = false,\n isOpen = false,\n onClose,\n onPrimaryAction,\n primaryColor = 'primary',\n primaryText = 'Confirm',\n onSecondaryAction,\n secondaryColor = 'primary',\n secondaryText = 'Cancel',\n children,\n ...rest\n}) => {\n // Extract sx from rest to merge with Dialog's own styles instead of overwriting\n const { sx: restSx, ...restProps } = rest\n const title = copy?.title ?? ''\n const closeAria = copy?.close_aria ?? 'Close'\n\n // Label the dialog *by* its visible heading (WAI-ARIA APG) instead of a duplicate\n // aria-label, so screen readers announce the title once rather than name + heading.\n const titleId = React.useId()\n\n const { isSmallMobile } = useScreenSize()\n\n const handlePrimaryAction = () => {\n onPrimaryAction?.()\n onClose()\n }\n\n const handleSecondaryAction = () => {\n if (onSecondaryAction) {\n onSecondaryAction()\n }\n onClose()\n }\n\n return (\n <div className={`mx-cmn-dialog ${className}`}>\n <MuiDialog\n aria-labelledby={titleId}\n maxWidth=\"xs\"\n onClose={onClose}\n open={isOpen}\n sx={\n [\n {\n '& .MuiDialog-paperScrollPaper': { backgroundColor: 'background.default' },\n ...(isSmallMobile && { '& .MuiDialog-paper': { minWidth: '100%' } }),\n height: '100%',\n },\n ...(restSx ? [restSx] : []),\n ] as SxProps\n }\n {...restProps}\n >\n <DialogHeader\n ariaHidden={true}\n copy={{ title, close_aria: closeAria }}\n id={titleId}\n onClose={onClose}\n truncate={true}\n />\n\n <DialogContent sx={{ lineHeight: 1.5 }}>{children}</DialogContent>\n\n <DialogFooter\n isPrimaryDisabled={disablePrimaryButton}\n onPrimaryAction={handlePrimaryAction}\n onSecondaryAction={handleSecondaryAction}\n primaryColor={primaryColor}\n primaryText={primaryText}\n secondaryColor={secondaryColor}\n secondaryText={secondaryText}\n />\n </MuiDialog>\n </div>\n )\n}\n\nexport default Dialog\n"],"mappings":";;;;;;AA6BA,IAAM,IAAA,CAA0D,EAC9D,WAAA,GACA,MAAA,GACA,sBAAA,IAAuB,IACvB,QAAA,IAAS,IACT,SAAA,GACA,iBAAA,GACA,cAAA,IAAe,WACf,aAAA,IAAc,WACd,mBAAA,GACA,gBAAA,IAAiB,WACjB,eAAA,IAAgB,UAChB,UAAA,GACA,GAAG,EAAA,MACC;AAEJ,QAAM,EAAE,IAAI,GAAQ,GAAG,EAAA,IAAc,GAC/B,IAAQ,GAAM,SAAS,IACvB,IAAY,GAAM,cAAc,SAIhC,IAAU,EAAM,MAAM,GAEtB,EAAE,eAAA,EAAA,IAAkB,EAAc,GAElC,IAAA,MAA4B;AAChC,IAAA,IAAkB,GAClB,EAAQ;AAAA,EACV,GAEM,IAAA,MAA8B;AAClC,IAAI,KACF,EAAkB,GAEpB,EAAQ;AAAA,EACV;AAEA,SACE,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAW,iBAAiB,CAAA;AAAA,IAC/B,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,mBAAiB;AAAA,MACjB,UAAS;AAAA,MACA,SAAA;AAAA,MACT,MAAM;AAAA,MACN,IACE,CACE;AAAA,QACE,iCAAiC,EAAE,iBAAiB,qBAAqB;AAAA,QACzE,GAAI,KAAiB,EAAE,sBAAsB,EAAE,UAAU,OAAO,EAAE;AAAA,QAClE,QAAQ;AAAA,MACV,GACA,GAAI,IAAS,CAAC,CAAM,IAAI,CAAC,CAC3B;AAAA,MAEF,GAAI;AAAA,MAfN,UAAA;AAAA,QAiBE,gBAAA,EAAC,GAAD;AAAA,UACE,YAAY;AAAA,UACZ,MAAM;AAAA,YAAE,OAAA;AAAA,YAAO,YAAY;AAAA,UAAU;AAAA,UACrC,IAAI;AAAA,UACK,SAAA;AAAA,UACT,UAAU;AAAA,QACX,CAAA;AAAA,QAED,gBAAA,EAAC,GAAD;AAAA,UAAe,IAAI,EAAE,YAAY,IAAI;AAAA,UAAI,UAAA;AAAA,QAAwB,CAAA;AAAA,QAEjE,gBAAA,EAAC,GAAD;AAAA,UACE,mBAAmB;AAAA,UACnB,iBAAiB;AAAA,UACjB,mBAAmB;AAAA,UACL,cAAA;AAAA,UACD,aAAA;AAAA,UACG,gBAAA;AAAA,UACD,eAAA;AAAA,QAChB,CAAA;AAAA,MACQ;AAAA;EACR,CAAA;AAET"}
1
+ {"version":3,"file":"Dialog.es.js","names":[],"sources":["../../../../src/common/components/dialog/Dialog.tsx"],"sourcesContent":["import React from 'react'\n\nimport MuiDialog from '@mui/material/Dialog'\nimport { DialogProps as MuiDialogProps } from '@mui/material/Dialog'\nimport DialogContent from '@mui/material/DialogContent'\nimport type { SxProps } from '@mui/material/styles'\n\nimport { DialogFooter, DialogHeader } from '@mxenabled/mxui'\nimport { useScreenSize } from '../../hooks'\n\nexport type CopyObject = {\n close_aria?: string\n title: string\n}\n\ntype OwnedMuiProps =\n | 'disableRestoreFocus'\n | 'onFocus'\n | 'open'\n | 'slotProps'\n | 'slots'\n | 'TransitionComponent'\n | 'TransitionProps'\n\nexport interface DialogProps extends Omit<MuiDialogProps, OwnedMuiProps> {\n className?: string\n copy: CopyObject\n disablePrimaryButton?: boolean\n isOpen: boolean\n onClose: (event?: unknown, reason?: string) => void\n onPrimaryAction?: () => void\n onSecondaryAction?: () => void\n primaryColor?: 'primary' | 'inherit' | 'secondary' | 'success' | 'error' | 'info' | 'warning'\n primaryText?: string\n secondaryColor?: 'primary' | 'inherit' | 'secondary' | 'success' | 'error' | 'info' | 'warning'\n secondaryText?: string\n}\n\nconst Dialog: React.FC<React.PropsWithChildren<DialogProps>> = ({\n className,\n copy,\n disablePrimaryButton = false,\n isOpen = false,\n onClose,\n onPrimaryAction,\n primaryColor = 'primary',\n primaryText = 'Confirm',\n onSecondaryAction,\n secondaryColor = 'primary',\n secondaryText = 'Cancel',\n children,\n ...rest\n}) => {\n // Extract sx from rest to merge with Dialog's own styles instead of overwriting\n const { sx: restSx, ...restProps } = rest\n const title = copy?.title ?? ''\n const closeAria = copy?.close_aria ?? 'Close'\n\n // Label the dialog *by* its visible heading (WAI-ARIA APG) instead of a duplicate\n // aria-label, so screen readers announce the title once rather than name + heading.\n const titleId = React.useId()\n\n const { isSmallMobile } = useScreenSize()\n\n const rootRef = React.useRef<HTMLDivElement>(null)\n const openerRef = React.useRef<HTMLElement | null>(null)\n const openerSnapshotRef = React.useRef<HTMLElement | null>(null)\n\n React.useLayoutEffect(() => {\n if (!isOpen) return\n openerRef.current = null\n const active = document.activeElement\n openerSnapshotRef.current =\n active instanceof HTMLElement &&\n active !== document.body &&\n !rootRef.current?.contains(active)\n ? active\n : null\n }, [isOpen])\n\n const captureOpener = (event: React.FocusEvent<HTMLDivElement>) => {\n const { relatedTarget } = event\n if (\n openerRef.current === null &&\n relatedTarget instanceof HTMLElement &&\n !event.currentTarget.contains(relatedTarget)\n ) {\n openerRef.current = relatedTarget\n }\n }\n\n const restoreFocus = () => {\n const target = openerRef.current ?? openerSnapshotRef.current\n openerRef.current = null\n openerSnapshotRef.current = null\n if (!target?.isConnected) return\n\n const active = target.ownerDocument.activeElement\n const focusIsUnclaimed =\n !active || active === target.ownerDocument.body || Boolean(rootRef.current?.contains(active))\n if (focusIsUnclaimed) {\n target.focus()\n }\n }\n\n React.useEffect(() => () => queueMicrotask(restoreFocus), [])\n\n const handlePrimaryAction = () => {\n onPrimaryAction?.()\n onClose()\n }\n\n const handleSecondaryAction = () => {\n if (onSecondaryAction) {\n onSecondaryAction()\n }\n onClose()\n }\n\n return (\n <div className={`mx-cmn-dialog ${className}`}>\n <MuiDialog\n aria-labelledby={titleId}\n maxWidth=\"xs\"\n onClose={onClose}\n open={isOpen}\n sx={\n [\n {\n '& .MuiDialog-paperScrollPaper': { backgroundColor: 'background.default' },\n ...(isSmallMobile && { '& .MuiDialog-paper': { minWidth: '100%' } }),\n height: '100%',\n },\n ...(restSx ? [restSx] : []),\n ] as SxProps\n }\n {...restProps}\n disableRestoreFocus={true}\n onFocus={captureOpener}\n ref={rootRef}\n slotProps={{ transition: { onExited: restoreFocus } }}\n >\n <DialogHeader\n ariaHidden={true}\n copy={{ title, close_aria: closeAria }}\n id={titleId}\n onClose={onClose}\n truncate={true}\n />\n\n <DialogContent sx={{ lineHeight: 1.5 }}>{children}</DialogContent>\n\n <DialogFooter\n isPrimaryDisabled={disablePrimaryButton}\n onPrimaryAction={handlePrimaryAction}\n onSecondaryAction={handleSecondaryAction}\n primaryColor={primaryColor}\n primaryText={primaryText}\n secondaryColor={secondaryColor}\n secondaryText={secondaryText}\n />\n </MuiDialog>\n </div>\n )\n}\n\nexport default Dialog\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.4.46",
3
+ "version": "9.4.47",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",