@mx-cartographer/experiences 9.4.29 → 9.4.30
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.30] - 09-17-2026
|
|
2
|
+
|
|
3
|
+
- **FIXED** - Budgets bubble tooltip is hidden from assistive tech so it is no longer announced out of focus order or left undismissable by mobile screen readers (MEW-3715)
|
|
4
|
+
|
|
1
5
|
## [9.4.29] - 09-17-2026
|
|
2
6
|
|
|
3
7
|
- **FIXED** - Investments Allocation donut misrepresented holdings with no Morningstar asset-class data as ~100% cash, because the ring's denominator was the sum of buckets-with-data instead of total portfolio value. The ring now uses total portfolio value and surfaces the gap as an explicit "Unclassified" slice (expandable into its real holdings), so ring, center total, and legend agree
|
|
@@ -26,14 +26,17 @@ function U({ bubble: t, isDraggable: v, onClick: f = () => {
|
|
|
26
26
|
]);
|
|
27
27
|
if (!t) return;
|
|
28
28
|
const { budgetColors: { background: k, text: l }, category: { icon: C, name: m }, guid: i, description: n, radius: o, x: E, y: M } = t, g = p < 400 ? -8 : -12;
|
|
29
|
-
let
|
|
30
|
-
o > r ? (
|
|
31
|
-
let
|
|
32
|
-
o <= r && (
|
|
33
|
-
const S = `${t.category.name}: ${n}`, _ = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
let h = g, a = g;
|
|
30
|
+
o > r ? (h = -14, a = -45) : o > u && (a = -32);
|
|
31
|
+
let y = 32;
|
|
32
|
+
o <= r && (y = p < 400 ? 16 : 24);
|
|
33
|
+
const S = `${t.category.name}: ${n}`, _ = {
|
|
34
|
+
"aria-hidden": !0,
|
|
35
|
+
modifiers: [{
|
|
36
|
+
name: "offset",
|
|
37
|
+
options: { offset: [0, 15] }
|
|
38
|
+
}]
|
|
39
|
+
}, w = (c) => {
|
|
37
40
|
(c.key === "Enter" || c.key === " ") && (c.preventDefault(), f(t));
|
|
38
41
|
}, B = () => {
|
|
39
42
|
s(!0);
|
|
@@ -83,11 +86,11 @@ function U({ bubble: t, isDraggable: v, onClick: f = () => {
|
|
|
83
86
|
})
|
|
84
87
|
}),
|
|
85
88
|
/* @__PURE__ */ e("svg", {
|
|
86
|
-
x:
|
|
89
|
+
x: h,
|
|
87
90
|
y: a,
|
|
88
91
|
children: /* @__PURE__ */ e(A, {
|
|
89
92
|
name: C,
|
|
90
|
-
size:
|
|
93
|
+
size: y,
|
|
91
94
|
sx: { fill: l }
|
|
92
95
|
})
|
|
93
96
|
}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Bubble.es.js","names":[],"sources":["../../../../src/budgets/components/bubblechart/Bubble.tsx"],"sourcesContent":["import React from 'react'\n\nimport Tooltip from '@mui/material/Tooltip'\nimport { useTheme } from '@mui/material/styles'\n\nimport { Icon, Text } from '@mxenabled/mxui'\n\nimport Mercury from './Mercury'\n\nimport { useWidgetContainerProvider } from '../../../common'\nimport { type DetailedBudget } from '../../../core'\nimport type { BubbleData } from '../BubbleChart'\n\nconst LARGE_THRESHOLD = 75\nconst MEDIUM_THRESHOLD = 50\n\ninterface BubbleProps {\n bubble: BubbleData\n isDraggable: boolean\n onClick?: (budget: DetailedBudget) => void\n}\n\nexport function Bubble({ bubble, isDraggable, onClick = () => {} }: BubbleProps) {\n const [showTooltip, setShowTooltip] = React.useState(false)\n const theme = useTheme()\n\n const { availableWidth } = useWidgetContainerProvider()\n\n const budgetBubble = React.useMemo(() => {\n if (!bubble) return undefined\n return {\n amount: bubble.amount,\n budgetColors: bubble.budgetColors,\n guid: bubble.guid,\n radius: bubble.radius,\n transaction_total: bubble.transaction_total,\n }\n }, [bubble.amount, bubble.budgetColors, bubble.guid, bubble.radius, bubble.transaction_total])\n\n if (!bubble) return undefined\n\n const {\n budgetColors: { background, text: textColor },\n category: { icon, name },\n guid,\n description,\n radius,\n x,\n y,\n } = bubble\n\n const defaultSvgOffset = availableWidth < 400 ? -8 : -12\n\n let iconX = defaultSvgOffset\n let iconY = defaultSvgOffset\n\n if (radius > LARGE_THRESHOLD) {\n iconX = -14\n iconY = -45\n } else if (radius > MEDIUM_THRESHOLD) {\n iconY = -32\n }\n\n let iconDimension = 32\n\n if (radius <= LARGE_THRESHOLD) {\n iconDimension = availableWidth < 400 ? 16 : 24\n }\n\n const tooltipText = `${bubble.category.name}: ${description}`\n const tooltipPopperSlot = {\n modifiers: [\n {\n name: 'offset',\n options: { offset: [0, 15] },\n },\n ],\n }\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick(bubble)\n }\n }\n\n const handleFocus = () => {\n setShowTooltip(true)\n }\n\n const handleBlur = () => {\n setShowTooltip(false)\n }\n\n return (\n <g\n aria-label={`${name} - ${description}`}\n className=\"bubble\"\n id={`bubble-${guid}`}\n key={guid}\n onBlur={handleBlur}\n onClick={() => onClick(bubble)}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n role=\"button\"\n style={{ cursor: isDraggable ? 'pointer' : 'default', touchAction: 'manipulation' }}\n tabIndex={0}\n textAnchor=\"middle\"\n x={x}\n y={y}\n >\n <style>\n {`\n .bubble:focus,\n .bubble:focus-visible {\n outline: none;\n }\n .bubble:focus circle,\n .bubble:focus-visible circle {\n stroke: ${theme.palette.primary.main};\n stroke-width: 3;\n stroke-opacity: 0.8;\n }\n `}\n </style>\n <Tooltip open={showTooltip} slotProps={{ popper: tooltipPopperSlot }} title={tooltipText}>\n <circle fill={background} id={`circle-${guid}`} r={radius} />\n </Tooltip>\n\n <svg x={iconX} y={iconY}>\n <Icon name={icon} size={iconDimension} sx={{ fill: textColor }} />\n </svg>\n\n {radius > LARGE_THRESHOLD && (\n <Text\n bold={true}\n component=\"text\"\n id={`budget-category-${guid}`}\n sx={{ fill: textColor }}\n variant=\"body2\"\n /* @ts-expect-error Property doesn't exist on type */\n y={4}\n >\n {name}\n </Text>\n )}\n\n {radius > MEDIUM_THRESHOLD && (\n <Text\n bold={true}\n component=\"text\"\n id={`budget-description-${guid}-1`}\n sx={{ fill: textColor }}\n variant=\"body1\"\n /* @ts-expect-error Property doesn't exist on type */\n y={radius <= LARGE_THRESHOLD ? 12 : 24}\n >\n {radius <= LARGE_THRESHOLD ? description.split(' ')[0] : description}\n </Text>\n )}\n\n {radius <= LARGE_THRESHOLD && radius > MEDIUM_THRESHOLD && (\n <Text\n component=\"text\"\n id={`budget-description-${guid}-2`}\n sx={{ fill: textColor }}\n variant=\"caption\"\n /* @ts-expect-error Property doesn't exist on type */\n y={28}\n >\n {description.split(' ')[1]}\n </Text>\n )}\n\n <Mercury bubble={budgetBubble as BubbleData} />\n </g>\n )\n}\n"],"mappings":";;;;;;;AAaA,IAAM,IAAkB,IAClB,IAAmB;AAQzB,SAAgB,EAAO,EAAE,QAAA,GAAQ,aAAA,GAAa,SAAA,IAAA,MAAgB;AAAC,EAAA,GAAkB;AAC/E,QAAM,CAAC,GAAa,CAAA,IAAkB,EAAM,SAAS,EAAK,GACpD,IAAQ,EAAS,GAEjB,EAAE,gBAAA,EAAA,IAAmB,EAA2B,GAEhD,IAAe,EAAM,QAAA,MAAc;AACvC,QAAK;AACL,aAAO;AAAA,QACL,QAAQ,EAAO;AAAA,QACf,cAAc,EAAO;AAAA,QACrB,MAAM,EAAO;AAAA,QACb,QAAQ,EAAO;AAAA,QACf,mBAAmB,EAAO;AAAA,MAC5B;AAAA,EACF,GAAG;AAAA,IAAC,EAAO;AAAA,IAAQ,EAAO;AAAA,IAAc,EAAO;AAAA,IAAM,EAAO;AAAA,IAAQ,EAAO;AAAA,EAAiB,CAAC;AAE7F,MAAI,CAAC,EAAQ;AAEb,QAAM,EACJ,cAAc,EAAE,YAAA,GAAY,MAAM,EAAA,GAClC,UAAU,EAAE,MAAA,GAAM,MAAA,EAAA,GAClB,MAAA,GACA,aAAA,GACA,QAAA,GACA,GAAA,GACA,GAAA,EAAA,IACE,GAEE,IAAmB,IAAiB,MAAM,KAAK;AAErD,MAAI,IAAQ,GACR,IAAQ;AAEZ,EAAI,IAAS,KACX,IAAQ,KACR,IAAQ,OACC,IAAS,MAClB,IAAQ;AAGV,MAAI,IAAgB;AAEpB,EAAI,KAAU,MACZ,IAAgB,IAAiB,MAAM,KAAK;AAG9C,QAAM,IAAc,GAAG,EAAO,SAAS,IAAA,KAAS,CAAA,IAC1C,IAAoB,
|
|
1
|
+
{"version":3,"file":"Bubble.es.js","names":[],"sources":["../../../../src/budgets/components/bubblechart/Bubble.tsx"],"sourcesContent":["import React from 'react'\n\nimport Tooltip from '@mui/material/Tooltip'\nimport { useTheme } from '@mui/material/styles'\n\nimport { Icon, Text } from '@mxenabled/mxui'\n\nimport Mercury from './Mercury'\n\nimport { useWidgetContainerProvider } from '../../../common'\nimport { type DetailedBudget } from '../../../core'\nimport type { BubbleData } from '../BubbleChart'\n\nconst LARGE_THRESHOLD = 75\nconst MEDIUM_THRESHOLD = 50\n\ninterface BubbleProps {\n bubble: BubbleData\n isDraggable: boolean\n onClick?: (budget: DetailedBudget) => void\n}\n\nexport function Bubble({ bubble, isDraggable, onClick = () => {} }: BubbleProps) {\n const [showTooltip, setShowTooltip] = React.useState(false)\n const theme = useTheme()\n\n const { availableWidth } = useWidgetContainerProvider()\n\n const budgetBubble = React.useMemo(() => {\n if (!bubble) return undefined\n return {\n amount: bubble.amount,\n budgetColors: bubble.budgetColors,\n guid: bubble.guid,\n radius: bubble.radius,\n transaction_total: bubble.transaction_total,\n }\n }, [bubble.amount, bubble.budgetColors, bubble.guid, bubble.radius, bubble.transaction_total])\n\n if (!bubble) return undefined\n\n const {\n budgetColors: { background, text: textColor },\n category: { icon, name },\n guid,\n description,\n radius,\n x,\n y,\n } = bubble\n\n const defaultSvgOffset = availableWidth < 400 ? -8 : -12\n\n let iconX = defaultSvgOffset\n let iconY = defaultSvgOffset\n\n if (radius > LARGE_THRESHOLD) {\n iconX = -14\n iconY = -45\n } else if (radius > MEDIUM_THRESHOLD) {\n iconY = -32\n }\n\n let iconDimension = 32\n\n if (radius <= LARGE_THRESHOLD) {\n iconDimension = availableWidth < 400 ? 16 : 24\n }\n\n const tooltipText = `${bubble.category.name}: ${description}`\n const tooltipPopperSlot = {\n // Screen readers already get this content in focus order from the <g>\n // aria-label. The tooltip is purely visual, so hide its portaled node from\n // assistive tech to keep it from being announced detached from its trigger\n // (and with nothing for mobile screenreader users to dismiss).\n 'aria-hidden': true,\n modifiers: [\n {\n name: 'offset',\n options: { offset: [0, 15] },\n },\n ],\n }\n\n const handleKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onClick(bubble)\n }\n }\n\n const handleFocus = () => {\n setShowTooltip(true)\n }\n\n const handleBlur = () => {\n setShowTooltip(false)\n }\n\n return (\n <g\n aria-label={`${name} - ${description}`}\n className=\"bubble\"\n id={`bubble-${guid}`}\n key={guid}\n onBlur={handleBlur}\n onClick={() => onClick(bubble)}\n onFocus={handleFocus}\n onKeyDown={handleKeyDown}\n onMouseEnter={() => setShowTooltip(true)}\n onMouseLeave={() => setShowTooltip(false)}\n role=\"button\"\n style={{ cursor: isDraggable ? 'pointer' : 'default', touchAction: 'manipulation' }}\n tabIndex={0}\n textAnchor=\"middle\"\n x={x}\n y={y}\n >\n <style>\n {`\n .bubble:focus,\n .bubble:focus-visible {\n outline: none;\n }\n .bubble:focus circle,\n .bubble:focus-visible circle {\n stroke: ${theme.palette.primary.main};\n stroke-width: 3;\n stroke-opacity: 0.8;\n }\n `}\n </style>\n <Tooltip open={showTooltip} slotProps={{ popper: tooltipPopperSlot }} title={tooltipText}>\n <circle fill={background} id={`circle-${guid}`} r={radius} />\n </Tooltip>\n\n <svg x={iconX} y={iconY}>\n <Icon name={icon} size={iconDimension} sx={{ fill: textColor }} />\n </svg>\n\n {radius > LARGE_THRESHOLD && (\n <Text\n bold={true}\n component=\"text\"\n id={`budget-category-${guid}`}\n sx={{ fill: textColor }}\n variant=\"body2\"\n /* @ts-expect-error Property doesn't exist on type */\n y={4}\n >\n {name}\n </Text>\n )}\n\n {radius > MEDIUM_THRESHOLD && (\n <Text\n bold={true}\n component=\"text\"\n id={`budget-description-${guid}-1`}\n sx={{ fill: textColor }}\n variant=\"body1\"\n /* @ts-expect-error Property doesn't exist on type */\n y={radius <= LARGE_THRESHOLD ? 12 : 24}\n >\n {radius <= LARGE_THRESHOLD ? description.split(' ')[0] : description}\n </Text>\n )}\n\n {radius <= LARGE_THRESHOLD && radius > MEDIUM_THRESHOLD && (\n <Text\n component=\"text\"\n id={`budget-description-${guid}-2`}\n sx={{ fill: textColor }}\n variant=\"caption\"\n /* @ts-expect-error Property doesn't exist on type */\n y={28}\n >\n {description.split(' ')[1]}\n </Text>\n )}\n\n <Mercury bubble={budgetBubble as BubbleData} />\n </g>\n )\n}\n"],"mappings":"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"}
|