@mx-cartographer/experiences 9.4.21 → 9.4.22

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,8 @@
1
+ ## [9.4.22] - 09-12-2026
2
+
3
+ - **FIXED** - The category-change confirmation dialog (and all `common` `Dialog` modals) read their title twice on screen readers: the title was both the dialog's accessible name and a separate visible heading node. The dialog now labels itself via `aria-labelledby` pointing at the heading, and passes `ariaHidden` so the heading is removed from the a11y tree, so the title is announced once
4
+ - **CHANGED** - Bumped `@mxenabled/mxui` to `^2.9.2` (for `DialogHeader`'s `id` + `ariaHidden` props) and `@mxenabled/mx-icons` to `^2.3.0` to satisfy the mxui peer requirement
5
+
1
6
  ## [9.4.21] - 09-15-2026
2
7
 
3
8
  - **FIXED** - Investments widget showed a false 100% gain on holdings with a null `cost_basis` (exposed once MEW-4073 enriched `market_value`), because gain/loss treated an unknown basis as `0`. Basis now resolves via a shared helper (`getHoldingGainLoss`): `cost_basis` when set (including a real `0`), else `purchase_price`, else "—" instead of a fabricated 0/100% — applied to the holding rows, Cost Basis column, account rollup, the Overview total-portfolio gain/loss, and the Allocation donut (including its center) so an all-unknown-basis portfolio shows "—" rather than a fabricated $0.00. The inline editor still seeds from the raw `cost_basis` so an untouched edit never persists `purchase_price` back to Abacus, and editing a basis on mobile now re-derives the drawer's gain/loss instead of leaving it stale (MEW-3791)
@@ -24,6 +29,7 @@
24
29
  - **FIXED** - `FeedbackDialog` props made non-optional: `primaryText`, `secondaryText`, and `closeAriaLabel` are now required (previously optional), and `multiline={true}` is now explicit on the TextField. All callers (BaseLayout, stories, tests) updated to provide required props (WEC-1766)
25
30
  - **FIXED** - `DismissInsightDialog` spacing restored: `sx` overrides for content padding and header alignment re-added after being accidentally removed during refactor (WEC-1766)
26
31
 
32
+
27
33
  ## [9.4.17] - 09-04-2026
28
34
 
29
35
  - **ADDED** - insights-v2 feedback UI screens (WEC-1781): `FeedbackDialog` (generic feedback survey with radio options + optional detail field), `DismissInsightDialog` (dismiss beat with Once/Always choices + confirmation), `FeedbackBar` (compact inline helpful/not-helpful reactions), `HiddenConfirmationCard` (visual confirmation of hidden insight). All presentational, data-agnostic; parent owns copy, options, and callback logic. Wired to `beatActions` context for parent handler dispatch (WEC-1781)
@@ -95,7 +101,6 @@
95
101
  - **CHANGED** - Moved ActionBlock from `blocks/ComponentBlocks/ActionBlock` to `src/insights-v2/actionBlocks`; drilldown figures/copy now sourced from `insights_payload.instance_slot_data` (WEC-1705)
96
102
  - **CHANGED** - `InsightsV2Store.closeActionDrawer` preserves `trigger` so the drawer keeps its title/content through the slide-out animation (WEC-1705)
97
103
  - **FIXED** - Action drawer first-open animation: `ActionBlockLayer` stays mounted for null-block CTAs so the slide-in transition plays on the first open (WEC-1705)
98
-
99
104
  ## [9.4.7] - 08-27-2026
100
105
 
101
106
  - **ADDED** - `CategoryTransactionsBlock` component block supporting `SameHeaderDesign` variant for single fee and large transactions in Insights v2 (MEW2-3237)
@@ -1,51 +1,51 @@
1
1
  import { useScreenSize as P } from "../../hooks/useScreenSize.es.js";
2
- import "react";
3
- import { DialogFooter as S, DialogHeader as A } from "@mxenabled/mxui";
4
- import { jsx as a, jsxs as M } from "react/jsx-runtime";
5
- import v from "@mui/material/Dialog";
6
- import j from "@mui/material/DialogContent";
7
- var N = ({ className: t, copy: o, disablePrimaryButton: s = !1, isOpen: n = !1, onClose: r, onPrimaryAction: c, primaryColor: m = "primary", primaryText: p = "Confirm", onSecondaryAction: e, secondaryColor: d = "primary", secondaryText: f = "Cancel", children: g, ...u }) => {
8
- const { sx: l, ...x } = u, i = o?.title ?? "", h = o?.close_aria ?? "Close", { isSmallMobile: b } = P(), D = () => {
9
- c?.(), r();
10
- }, y = () => {
11
- e && e(), r();
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();
12
12
  };
13
- return /* @__PURE__ */ a("div", {
14
- className: `mx-cmn-dialog ${t}`,
15
- children: /* @__PURE__ */ M(v, {
16
- "aria-label": i,
17
- "aria-labelledby": void 0,
13
+ return /* @__PURE__ */ r("div", {
14
+ className: `mx-cmn-dialog ${l}`,
15
+ children: /* @__PURE__ */ j(k, {
16
+ "aria-labelledby": t,
18
17
  maxWidth: "xs",
19
- onClose: r,
18
+ onClose: i,
20
19
  open: n,
21
- slotProps: { paper: { "aria-label": i } },
22
20
  sx: [{
23
21
  "& .MuiDialog-paperScrollPaper": { backgroundColor: "background.default" },
24
- ...b && { "& .MuiDialog-paper": { minWidth: "100%" } },
22
+ ...y && { "& .MuiDialog-paper": { minWidth: "100%" } },
25
23
  height: "100%"
26
- }, ...l ? [l] : []],
24
+ }, ...o ? [o] : []],
27
25
  ...x,
28
26
  children: [
29
- /* @__PURE__ */ a(A, {
27
+ /* @__PURE__ */ r(H, {
28
+ ariaHidden: !0,
30
29
  copy: {
31
- title: i,
32
- close_aria: h
30
+ title: h,
31
+ close_aria: D
33
32
  },
34
- onClose: r,
33
+ id: t,
34
+ onClose: i,
35
35
  truncate: !0
36
36
  }),
37
- /* @__PURE__ */ a(j, {
37
+ /* @__PURE__ */ r(v, {
38
38
  sx: { lineHeight: 1.5 },
39
- children: g
39
+ children: f
40
40
  }),
41
- /* @__PURE__ */ a(S, {
41
+ /* @__PURE__ */ r(M, {
42
42
  isPrimaryDisabled: s,
43
- onPrimaryAction: D,
44
- onSecondaryAction: y,
43
+ onPrimaryAction: b,
44
+ onSecondaryAction: S,
45
45
  primaryColor: m,
46
- primaryText: p,
47
- secondaryColor: d,
48
- secondaryText: f
46
+ primaryText: d,
47
+ secondaryColor: p,
48
+ secondaryText: u
49
49
  })
50
50
  ]
51
51
  })
@@ -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 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-label={title}\n aria-labelledby={undefined}\n maxWidth=\"xs\"\n onClose={onClose}\n open={isOpen}\n slotProps={{\n paper: { 'aria-label': title },\n }}\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 copy={{ title, close_aria: closeAria }} onClose={onClose} truncate={true} />\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,SAEhC,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,cAAY;AAAA,MACZ,mBAAiB;AAAA,MACjB,UAAS;AAAA,MACA,SAAA;AAAA,MACT,MAAM;AAAA,MACN,WAAW,EACT,OAAO,EAAE,cAAc,EAAM,EAC/B;AAAA,MACA,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,MAnBN,UAAA;AAAA,QAqBE,gBAAA,EAAC,GAAD;AAAA,UAAc,MAAM;AAAA,YAAE,OAAA;AAAA,YAAO,YAAY;AAAA,UAAU;AAAA,UAAY,SAAA;AAAA,UAAS,UAAU;AAAA,QAAO,CAAA;AAAA,QAEzF,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\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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.4.21",
3
+ "version": "9.4.22",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",
@@ -219,8 +219,8 @@
219
219
  "@mui/x-date-pickers": "^7.29.4",
220
220
  "@mui/x-date-pickers-pro": "^7.29.4",
221
221
  "@mxenabled/cssinjs": "^0.6.0",
222
- "@mxenabled/mx-icons": "^2.2.0",
223
- "@mxenabled/mxui": "2.7.1",
222
+ "@mxenabled/mx-icons": "^2.3.0",
223
+ "@mxenabled/mxui": "^2.9.2",
224
224
  "@mxenabled/web-widget-sdk": "^0.0.15",
225
225
  "@tanstack/react-virtual": "^3.14.9",
226
226
  "bowser": "^2.14.1",