@mx-cartographer/experiences 9.4.3 → 9.4.5
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 +16 -0
- package/dist/core/constants/Investments.d.ts +3 -0
- package/dist/core/constants/Investments.es.js +34 -11
- package/dist/core/constants/Investments.es.js.map +1 -1
- package/dist/core/stores/HoldingStore.d.ts +3 -0
- package/dist/core/stores/HoldingStore.es.js +39 -29
- package/dist/core/stores/HoldingStore.es.js.map +1 -1
- package/dist/core/utils/InvestmentUtil.d.ts +4 -0
- package/dist/core/utils/InvestmentUtil.es.js +71 -58
- package/dist/core/utils/InvestmentUtil.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js +20 -19
- package/dist/insights-v2/blocks/ChartBlocks/BarchartBlock/utils.es.js.map +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.d.ts +8 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js +24 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js.map +1 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/comparisonUtils.d.ts +9 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/comparisonUtils.es.js +43 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/comparisonUtils.es.js.map +1 -0
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/index.d.ts +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.es.js +1 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.es.js.map +1 -1
- package/dist/insights-v2/{blocks/ChartBlocks/DoubleBarChartBlock → components/chartblocks}/ChartLegend.d.ts +1 -1
- package/dist/insights-v2/{blocks/ChartBlocks/DoubleBarChartBlock → components/chartblocks}/ChartLegend.es.js +12 -12
- package/dist/insights-v2/components/chartblocks/ChartLegend.es.js.map +1 -0
- package/dist/insights-v2/{blocks/ChartBlocks/DoubleBarChartBlock → components/chartblocks}/CustomDoubleBar.d.ts +1 -1
- package/dist/insights-v2/components/chartblocks/CustomDoubleBar.es.js.map +1 -0
- package/dist/insights-v2/components/chartblocks/DoubleBarChart.d.ts +17 -0
- package/dist/insights-v2/components/chartblocks/DoubleBarChart.es.js +118 -0
- package/dist/insights-v2/components/chartblocks/DoubleBarChart.es.js.map +1 -0
- package/dist/insights-v2/index.es.js +1 -1
- package/dist/insights-v2/mappings/blocks.es.js +1 -1
- package/dist/investments/InvestmentsWidget.es.js +100 -66
- package/dist/investments/InvestmentsWidget.es.js.map +1 -1
- package/dist/investments/components/allocation/util/createInvestementsAllocationData.es.js +50 -59
- package/dist/investments/components/allocation/util/createInvestementsAllocationData.es.js.map +1 -1
- package/package.json +8 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/ChartLegend.es.js.map +0 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/CustomDoubleBar.es.js.map +0 -1
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChart.d.ts +0 -2
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChart.es.js +0 -125
- package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChart.es.js.map +0 -1
- /package/dist/insights-v2/{blocks/ChartBlocks/DoubleBarChartBlock → components/chartblocks}/CustomDoubleBar.es.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DoubleBarChartBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.tsx"],"sourcesContent":["import { useTheme } from '@mui/material/styles'\n\nimport { useInsightsV2Store } from '../../../../common'\nimport type { DataSeries } from '../../../../core'\nimport { DoubleBarChart } from '../../../components/chartblocks/DoubleBarChart'\n\nimport type { BlockProps } from '../../types'\n\nimport { buildComparisonSeries } from './comparisonUtils'\nimport { getLayoutConfig } from './layout'\n\n/**\n * Card block for the double-bar chart. Mirrors BarchartBlock: it builds the shaped series\n * (buildComparisonSeries) and resolves the card palette (getLayoutConfig), then renders the reusable\n * DoubleBarChart and injects the card click behavior \\u2014 open the shared drawer scoped to this beat\n * (chartBarIndex = clicked column, tabIndex = clicked sub-series).\n */\nexport const DoubleBarChartBlock = ({\n payload: { instance_slot, instance_slot_data, widget_type },\n beatGuid = '',\n}: BlockProps) => {\n const theme = useTheme()\n const { openChartDrilldown } = useInsightsV2Store()\n const { variant } = instance_slot\n const { ariaLabel = '', data_series, legends } = instance_slot_data\n const bars = buildComparisonSeries(data_series as DataSeries, ariaLabel)\n // getLayoutConfig returns undefined for an unknown/unsupported variant; fall back to an empty\n // palette so an unregistered beat can't throw on mount.\n const colors = getLayoutConfig(theme, variant)?.color ?? []\n\n return (\n <DoubleBarChart\n bars={bars}\n colors={colors}\n isMini={widget_type === 'mini'}\n legends={legends}\n onBarClick={(columnIndex, subIndex) =>\n openChartDrilldown(beatGuid, { chartBarIndex: columnIndex, tabIndex: subIndex })\n }\n />\n )\n}\n"],"mappings":";;;;;;AAiBA,IAAa,IAAA,CAAuB,EAClC,SAAS,EAAE,eAAA,GAAe,oBAAA,GAAoB,aAAA,EAAA,GAC9C,UAAA,IAAW,GAAA,MACK;AAChB,QAAM,IAAQ,EAAS,GACjB,EAAE,oBAAA,EAAA,IAAuB,EAAmB,GAC5C,EAAE,SAAA,EAAA,IAAY,GACd,EAAE,WAAA,IAAY,IAAI,aAAA,GAAa,SAAA,EAAA,IAAY,GAC3C,IAAO,EAAsB,GAA2B,CAAS,GAGjE,IAAS,EAAgB,GAAO,CAAO,GAAG,SAAS,CAAC;AAE1D,SACE,gBAAA,EAAC,GAAD;AAAA,IACQ,MAAA;AAAA,IACE,QAAA;AAAA,IACR,QAAQ,MAAgB;AAAA,IACf,SAAA;AAAA,IACT,YAAA,CAAa,GAAa,MACxB,EAAmB,GAAU;AAAA,MAAE,eAAe;AAAA,MAAa,UAAU;AAAA,IAAS,CAAC;AAAA,EAElF,CAAA;AAEL"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DataSeries } from '../../../../core';
|
|
2
|
+
import { DataSet } from '../../../../core/types/InsightsInstanceSlotData';
|
|
3
|
+
/**
|
|
4
|
+
* Reshapes a flat comparison data_series into one shaped bar per month, sorted ascending by date —
|
|
5
|
+
* the double-bar equivalent of buildChartData. Each month has exactly two contiguous rows; the
|
|
6
|
+
* Income row becomes the comparison series and the other becomes main, regardless of wire order.
|
|
7
|
+
* Months are then sorted ascending so the chart's bar index and the axis line up.
|
|
8
|
+
*/
|
|
9
|
+
export declare const buildComparisonSeries: (data: DataSeries | undefined, ariaLabel?: string) => DataSet[];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { buildDynamicCopy as c } from "../../../../core/utils/Localization.es.js";
|
|
2
|
+
import { DATE_FORMATS_INTL as p, formatDate as u } from "../../../../core/constants/DateFormats.es.js";
|
|
3
|
+
import { formatCurrency as i } from "../../../../core/utils/NumberFormatting.es.js";
|
|
4
|
+
import { buildDataSeries as h } from "../BarchartBlock/utils.es.js";
|
|
5
|
+
import { parseISO as n } from "date-fns/parseISO";
|
|
6
|
+
import { isValid as N } from "date-fns/isValid";
|
|
7
|
+
var S = "income", T = (e) => String(e?.label ?? "").toLowerCase() === S, y = (e) => typeof e?.date == "string" && N(n(e.date)), b = (e) => String(e?.localized_label ?? e?.label ?? ""), g = (e) => {
|
|
8
|
+
const o = typeof e == "number" ? e : Number(e);
|
|
9
|
+
return Number.isFinite(o) ? o : 0;
|
|
10
|
+
}, v = (e, o = "") => {
|
|
11
|
+
const l = h(e).filter(y);
|
|
12
|
+
if (l.length === 0) return [];
|
|
13
|
+
const m = /* @__PURE__ */ new Map();
|
|
14
|
+
for (const t of l) {
|
|
15
|
+
const r = String(t.date).slice(0, 7), a = m.get(r);
|
|
16
|
+
a ? a.push(t) : m.set(r, [t]);
|
|
17
|
+
}
|
|
18
|
+
const f = [...m.values()].filter((t) => t.length === 2);
|
|
19
|
+
return f.length === 0 ? [] : f.map((t) => {
|
|
20
|
+
const r = t.find(T) ?? t[t.length - 1];
|
|
21
|
+
return {
|
|
22
|
+
mainRow: t.find((a) => a !== r) ?? t[0],
|
|
23
|
+
comparisonRow: r
|
|
24
|
+
};
|
|
25
|
+
}).sort(({ mainRow: t }, { mainRow: r }) => n(t.date).getTime() - n(r.date).getTime()).map(({ mainRow: t, comparisonRow: r }) => {
|
|
26
|
+
const a = g(t.amount), s = g(r.amount), d = u(n(t.date), p.MONTH_LONG);
|
|
27
|
+
return {
|
|
28
|
+
ariaLabelMain: c(o, d, i(a, "0,0.00"), b(t)),
|
|
29
|
+
ariaLabelComparison: c(o, d, i(s, "0,0.00"), b(r)),
|
|
30
|
+
comparison: s,
|
|
31
|
+
date: t.date,
|
|
32
|
+
formattedComparison: i(s, "0,0"),
|
|
33
|
+
formattedMain: i(a, "0,0"),
|
|
34
|
+
label: u(n(t.date), p.MONTH_SHORT),
|
|
35
|
+
main: a
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
export {
|
|
40
|
+
v as buildComparisonSeries
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=comparisonUtils.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparisonUtils.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/comparisonUtils.ts"],"sourcesContent":["import { isValid } from 'date-fns/isValid'\nimport { parseISO } from 'date-fns/parseISO'\n\nimport { DATE_FORMATS_INTL, formatDate } from '../../../../core/constants'\nimport type { DataSeries } from '../../../../core'\nimport type { DataSet } from '../../../../core/types/InsightsInstanceSlotData'\nimport { buildDynamicCopy } from '../../../../core/utils/Localization'\nimport { formatCurrency } from '../../../../core/utils/NumberFormatting'\nimport { buildDataSeries } from '../BarchartBlock/utils'\n\n// The comparison (second) series across every double-bar variant is Income (spend/savings/debt/\n// cost-of-living are all \"X to Income\"). `label` is the stable, non-localized category key, so we\n// key off it rather than row position — the wire lists income first within some months.\nconst INCOME_LABEL = 'income'\nconst isIncomeRow = (row: { label?: string }): boolean =>\n String(row?.label ?? '').toLowerCase() === INCOME_LABEL\n\n// A date-only wire string ('2026-03-01') is a valid ISO date; anything the backend sends that\n// parseISO can't turn into a real Date is dropped before it can poison the ascending sort with a\n// NaN comparator (which would scramble column order — and the chartBarIndex the card forwards to the\n// drilldown on click).\nconst hasValidDate = (row: { date?: string }): boolean =>\n typeof row?.date === 'string' && isValid(parseISO(row.date))\n\n// The series name shown to screen readers. `localized_label` should be coming from the backend's already-localized\n// display name; Document the backend contract inline so the fallback intent is explicit:\n// `localized_label` is expected on every beat whose ariaLabel template uses _3{}.\n// `label` ('income'/'spend') is an English-only fallback for dev/error scenarios.\nconst seriesName = (row: { localized_label?: string; label?: string }): string =>\n String(row?.localized_label ?? row?.label ?? '')\n\n// `amount` is wire data and only loosely typed. `?? 0` guards a missing value but not a non-numeric\n// one (a stray string/null would render as NaN in the bar and the aria label), so coerce and fall\n// back to 0 unless the result is a finite number.\nconst toAmount = (value: unknown): number => {\n const parsed = typeof value === 'number' ? value : Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n}\n\n/**\n * Reshapes a flat comparison data_series into one shaped bar per month, sorted ascending by date —\n * the double-bar equivalent of buildChartData. Each month has exactly two contiguous rows; the\n * Income row becomes the comparison series and the other becomes main, regardless of wire order.\n * Months are then sorted ascending so the chart's bar index and the axis line up.\n */\nexport const buildComparisonSeries = (data: DataSeries | undefined, ariaLabel = ''): DataSet[] => {\n // Guard the wire data before shaping it: `data_series` is type-asserted upstream, not validated, so\n // drop any row without a parseable date rather than let it flow into the sort/group logic.\n const flat = buildDataSeries(data).filter(hasValidDate)\n if (flat.length === 0) {\n return []\n }\n\n // Bucket rows by calendar month (YYYY-MM), not the exact date string, so a month whose rows carry\n // different day-of-month values (e.g. 2026-01-01 vs 2026-01-15) still groups into one bar rather\n // than two size-1 groups that are then dropped as malformed. First-seen order is preserved so the\n // ascending date sort below is stable.\n const byDate = new Map<string, any[]>()\n for (const row of flat) {\n const monthKey = String(row.date).slice(0, 7)\n const group = byDate.get(monthKey)\n if (group) group.push(row)\n else byDate.set(monthKey, [row])\n }\n\n // Keep only well-formed months (exactly one main + one comparison row). A month that lost a row to\n // the date guard above, or arrived malformed, is dropped on its own instead of blanking the whole\n // chart; return [] only when no valid month remains.\n const groups = [...byDate.values()].filter((group) => group.length === 2)\n if (groups.length === 0) {\n return []\n }\n\n return groups\n .map((group) => {\n // Income is always the comparison series; the remaining row is the main category. Fall back to\n // wire order (first = main, last = comparison) if no row is labeled income.\n const comparisonRow = group.find(isIncomeRow) ?? group[group.length - 1]\n const mainRow = group.find((row) => row !== comparisonRow) ?? group[0]\n return { mainRow, comparisonRow }\n })\n .sort(\n ({ mainRow: a }, { mainRow: b }) => parseISO(a.date).getTime() - parseISO(b.date).getTime(),\n )\n .map(({ mainRow, comparisonRow }) => {\n const main = toAmount(mainRow.amount)\n const comparison = toAmount(comparisonRow.amount)\n const monthLong = formatDate(parseISO(mainRow.date), DATE_FORMATS_INTL.MONTH_LONG)\n\n return {\n // The series name is passed as a third copy slot (_3{}) so a screen-reader user can tell the\n // main bar from the comparison bar. The backend template controls whether/where it renders;\n // when the template only has _1{}/_2{} the extra arg is ignored (no invented text).\n ariaLabelMain: buildDynamicCopy(\n ariaLabel,\n monthLong,\n formatCurrency(main, '0,0.00'),\n seriesName(mainRow),\n ) as string,\n ariaLabelComparison: buildDynamicCopy(\n ariaLabel,\n monthLong,\n formatCurrency(comparison, '0,0.00'),\n seriesName(comparisonRow),\n ) as string,\n comparison,\n date: mainRow.date,\n formattedComparison: formatCurrency(comparison, '0,0'),\n formattedMain: formatCurrency(main, '0,0'),\n label: formatDate(parseISO(mainRow.date), DATE_FORMATS_INTL.MONTH_SHORT),\n main,\n }\n })\n}\n"],"mappings":";;;;;;AAaA,IAAM,IAAe,UACf,IAAA,CAAe,MACnB,OAAO,GAAK,SAAS,EAAE,EAAE,YAAY,MAAM,GAMvC,IAAA,CAAgB,MACpB,OAAO,GAAK,QAAS,YAAY,EAAQ,EAAS,EAAI,IAAI,CAAC,GAMvD,IAAA,CAAc,MAClB,OAAO,GAAK,mBAAmB,GAAK,SAAS,EAAE,GAK3C,IAAA,CAAY,MAA2B;AAC3C,QAAM,IAAS,OAAO,KAAU,WAAW,IAAQ,OAAO,CAAK;AAC/D,SAAO,OAAO,SAAS,CAAM,IAAI,IAAS;AAC5C,GAQa,IAAA,CAAyB,GAA8B,IAAY,OAAkB;AAGhG,QAAM,IAAO,EAAgB,CAAI,EAAE,OAAO,CAAY;AACtD,MAAI,EAAK,WAAW,EAClB,QAAO,CAAC;AAOV,QAAM,IAAS,oBAAI,IAAmB;AACtC,aAAW,KAAO,GAAM;AACtB,UAAM,IAAW,OAAO,EAAI,IAAI,EAAE,MAAM,GAAG,CAAC,GACtC,IAAQ,EAAO,IAAI,CAAQ;AACjC,IAAI,IAAO,EAAM,KAAK,CAAG,IACpB,EAAO,IAAI,GAAU,CAAC,CAAG,CAAC;AAAA,EACjC;AAKA,QAAM,IAAS,CAAC,GAAG,EAAO,OAAO,CAAC,EAAE,OAAA,CAAQ,MAAU,EAAM,WAAW,CAAC;AACxE,SAAI,EAAO,WAAW,IACb,CAAC,IAGH,EACJ,IAAA,CAAK,MAAU;AAGd,UAAM,IAAgB,EAAM,KAAK,CAAW,KAAK,EAAM,EAAM,SAAS,CAAA;AAEtE,WAAO;AAAA,MAAE,SADO,EAAM,KAAA,CAAM,MAAQ,MAAQ,CAAa,KAAK,EAAM,CAAA;AAAA,MAClD,eAAA;AAAA,IAAc;AAAA,EAClC,CAAC,EACA,KAAA,CACE,EAAE,SAAS,EAAA,GAAK,EAAE,SAAS,EAAA,MAAQ,EAAS,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAS,EAAE,IAAI,EAAE,QAAQ,CAC5F,EACC,IAAA,CAAK,EAAE,SAAA,GAAS,eAAA,EAAA,MAAoB;AACnC,UAAM,IAAO,EAAS,EAAQ,MAAM,GAC9B,IAAa,EAAS,EAAc,MAAM,GAC1C,IAAY,EAAW,EAAS,EAAQ,IAAI,GAAG,EAAkB,UAAU;AAEjF,WAAO;AAAA,MAIL,eAAe,EACb,GACA,GACA,EAAe,GAAM,QAAQ,GAC7B,EAAW,CAAO,CACpB;AAAA,MACA,qBAAqB,EACnB,GACA,GACA,EAAe,GAAY,QAAQ,GACnC,EAAW,CAAa,CAC1B;AAAA,MACA,YAAA;AAAA,MACA,MAAM,EAAQ;AAAA,MACd,qBAAqB,EAAe,GAAY,KAAK;AAAA,MACrD,eAAe,EAAe,GAAM,KAAK;AAAA,MACzC,OAAO,EAAW,EAAS,EAAQ,IAAI,GAAG,EAAkB,WAAW;AAAA,MACvE,MAAA;AAAA,IACF;AAAA,EACF,CAAC;AACL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './DoubleBarChartBlock';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var a = (t, o) => ({
|
|
2
2
|
SpendToIncome: { color: [t.palette.categories.billsUtilities, t.palette.chart.chart1] },
|
|
3
|
-
DebtToIncome: { color: [t.palette.chart.
|
|
3
|
+
DebtToIncome: { color: [t.palette.chart.chart5, t.palette.chart.chart1] },
|
|
4
4
|
SavingsToIncome: { color: [t.palette.chartMono.chartMono5, t.palette.chartMono.chartMono3] }
|
|
5
5
|
})[o];
|
|
6
6
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles'\n\nexport const getLayoutConfig = (theme: Theme, variant: string | null) => {\n const config = {\n SpendToIncome: {\n color: [theme.palette.categories.billsUtilities, theme.palette.chart.chart1] as string[],\n },\n DebtToIncome: {\n color: [theme.palette.chart.
|
|
1
|
+
{"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.ts"],"sourcesContent":["import type { Theme } from '@mui/material/styles'\n\nexport const getLayoutConfig = (theme: Theme, variant: string | null) => {\n const config = {\n SpendToIncome: {\n color: [theme.palette.categories.billsUtilities, theme.palette.chart.chart1] as string[],\n },\n DebtToIncome: {\n color: [theme.palette.chart.chart5, theme.palette.chart.chart1] as string[],\n },\n SavingsToIncome: {\n color: [theme.palette.chartMono.chartMono5, theme.palette.chartMono.chartMono3] as string[],\n },\n }\n return config[variant as keyof typeof config]\n}\n"],"mappings":"AAEA,IAAa,IAAA,CAAmB,GAAc,OAYrC;AAAA,EAVL,eAAe,EACb,OAAO,CAAC,EAAM,QAAQ,WAAW,gBAAgB,EAAM,QAAQ,MAAM,MAAM,EAC7E;AAAA,EACA,cAAc,EACZ,OAAO,CAAC,EAAM,QAAQ,MAAM,QAAQ,EAAM,QAAQ,MAAM,MAAM,EAChE;AAAA,EACA,iBAAiB,EACf,OAAO,CAAC,EAAM,QAAQ,UAAU,YAAY,EAAM,QAAQ,UAAU,UAAU,EAChF;AAEK,GAAO,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SxProps } from '@mui/material/styles';
|
|
2
|
-
import { LegendProps } from '
|
|
2
|
+
import { LegendProps } from '../../../core/types/InsightsInstanceSlotData';
|
|
3
3
|
export interface LegendComponentProps {
|
|
4
4
|
legendItems: LegendProps[];
|
|
5
5
|
legendStyle?: SxProps;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Text as
|
|
3
|
-
import { jsx as t, jsxs as
|
|
4
|
-
var f = ({ legendItems: h, legendStyle:
|
|
1
|
+
import n from "@mui/material/Stack";
|
|
2
|
+
import { Text as l } from "@mxenabled/mxui";
|
|
3
|
+
import { jsx as t, jsxs as a } from "react/jsx-runtime";
|
|
4
|
+
var f = ({ legendItems: h, legendStyle: o }) => /* @__PURE__ */ t(n, {
|
|
5
5
|
sx: {
|
|
6
6
|
alignItems: "flex-start",
|
|
7
7
|
flexDirection: "row",
|
|
@@ -9,9 +9,9 @@ var f = ({ legendItems: h, legendStyle: l }) => /* @__PURE__ */ t(a, {
|
|
|
9
9
|
justifyContent: "flex-start",
|
|
10
10
|
py: 4,
|
|
11
11
|
width: "100%",
|
|
12
|
-
...
|
|
12
|
+
...o
|
|
13
13
|
},
|
|
14
|
-
children: h.map(({ color:
|
|
14
|
+
children: h.map(({ color: c, label: r, formattedAmount: i }, e) => r && /* @__PURE__ */ a(n, {
|
|
15
15
|
sx: {
|
|
16
16
|
alignItems: "center",
|
|
17
17
|
flexDirection: "row",
|
|
@@ -19,27 +19,27 @@ var f = ({ legendItems: h, legendStyle: l }) => /* @__PURE__ */ t(a, {
|
|
|
19
19
|
},
|
|
20
20
|
children: [/* @__PURE__ */ t("svg", {
|
|
21
21
|
"aria-hidden": "true",
|
|
22
|
-
"aria-labelledby":
|
|
22
|
+
"aria-labelledby": e === 0 ? "chartLegendLabel" : r,
|
|
23
23
|
fill: "none",
|
|
24
24
|
height: "12",
|
|
25
25
|
role: "figure",
|
|
26
26
|
width: "12",
|
|
27
27
|
children: /* @__PURE__ */ t("rect", {
|
|
28
|
-
fill:
|
|
28
|
+
fill: c,
|
|
29
29
|
height: "12",
|
|
30
30
|
rx: "2",
|
|
31
31
|
width: "12"
|
|
32
32
|
})
|
|
33
|
-
}), /* @__PURE__ */
|
|
34
|
-
id:
|
|
33
|
+
}), /* @__PURE__ */ a(l, {
|
|
34
|
+
id: e === 0 ? "chartLegendLabel" : r,
|
|
35
35
|
variant: "caption",
|
|
36
36
|
children: [
|
|
37
|
-
|
|
37
|
+
r,
|
|
38
38
|
" ",
|
|
39
39
|
i ? `: ${i}` : ""
|
|
40
40
|
]
|
|
41
41
|
})]
|
|
42
|
-
}, r))
|
|
42
|
+
}, r ?? e))
|
|
43
43
|
});
|
|
44
44
|
export {
|
|
45
45
|
f as Legend
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChartLegend.es.js","names":[],"sources":["../../../../src/insights-v2/components/chartblocks/ChartLegend.tsx"],"sourcesContent":["import { Text } from '@mxenabled/mxui'\n\nimport Stack from '@mui/material/Stack'\n\nimport type { SxProps } from '@mui/material/styles'\nimport type { LegendProps } from '../../../core/types/InsightsInstanceSlotData'\n\nexport interface LegendComponentProps {\n legendItems: LegendProps[]\n legendStyle?: SxProps\n}\n\nexport const Legend = ({ legendItems, legendStyle }: LegendComponentProps) => {\n return (\n <Stack\n sx={{\n alignItems: 'flex-start',\n flexDirection: 'row',\n gap: 24,\n justifyContent: 'flex-start',\n py: 4,\n width: '100%',\n ...legendStyle,\n }}\n >\n {legendItems.map(\n ({ color, label, formattedAmount }, index) =>\n label && (\n <Stack key={label ?? index} sx={{ alignItems: 'center', flexDirection: 'row', gap: 8 }}>\n <svg\n aria-hidden=\"true\"\n aria-labelledby={index === 0 ? 'chartLegendLabel' : label}\n fill=\"none\"\n height=\"12\"\n role=\"figure\"\n width=\"12\"\n >\n <rect fill={color} height=\"12\" rx=\"2\" width=\"12\" />\n </svg>\n <Text id={index === 0 ? 'chartLegendLabel' : label} variant=\"caption\">\n {label} {formattedAmount ? `: ${formattedAmount}` : ''}\n </Text>\n </Stack>\n ),\n )}\n </Stack>\n )\n}\n"],"mappings":";;;AAYA,IAAa,IAAA,CAAU,EAAE,aAAA,GAAa,aAAA,EAAA,MAElC,gBAAA,EAAC,GAAD;AAAA,EACE,IAAI;AAAA,IACF,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,KAAK;AAAA,IACL,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,GAAG;AAAA,EACL;AAAA,EAEC,UAAA,EAAY,IAAA,CACV,EAAE,OAAA,GAAO,OAAA,GAAO,iBAAA,EAAA,GAAmB,MAClC,KACE,gBAAA,EAAC,GAAD;AAAA,IAA4B,IAAI;AAAA,MAAE,YAAY;AAAA,MAAU,eAAe;AAAA,MAAO,KAAK;AAAA,IAAE;AAAA,IAArF,UAAA,CACE,gBAAA,EAAC,OAAD;AAAA,MACE,eAAY;AAAA,MACZ,mBAAiB,MAAU,IAAI,qBAAqB;AAAA,MACpD,MAAK;AAAA,MACL,QAAO;AAAA,MACP,MAAK;AAAA,MACL,OAAM;AAAA,MAEN,UAAA,gBAAA,EAAC,QAAD;AAAA,QAAM,MAAM;AAAA,QAAO,QAAO;AAAA,QAAK,IAAG;AAAA,QAAI,OAAM;AAAA,MAAM,CAAA;AAAA,IAC/C,CAAA,GACL,gBAAA,EAAC,GAAD;AAAA,MAAM,IAAI,MAAU,IAAI,qBAAqB;AAAA,MAAO,SAAQ;AAAA,MAA5D,UAAA;AAAA,QACG;AAAA,QAAM;AAAA,QAAE,IAAkB,KAAK,CAAA,KAAoB;AAAA,MAChD;AAAA,IACD,CAAA,CAAA;AAAA,EAdK,GAAA,KAAS,CAcd,CAEb;AACK,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import { DataSet } from '
|
|
2
|
+
import { DataSet } from '../../../core/types/InsightsInstanceSlotData';
|
|
3
3
|
interface BarStyleProps extends React.CSSProperties {
|
|
4
4
|
x?: number;
|
|
5
5
|
y?: number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomDoubleBar.es.js","names":[],"sources":["../../../../src/insights-v2/components/chartblocks/CustomDoubleBar.tsx"],"sourcesContent":["import React from 'react'\nimport type { DataSet } from '../../../core/types/InsightsInstanceSlotData'\n\ninterface BarStyleProps extends React.CSSProperties {\n x?: number\n y?: number\n}\n\ninterface CustomDoubleBarPlotMXUIProps {\n color: string\n data: DataSet[]\n series: Series\n style: BarStyleProps\n}\n\ninterface Series {\n index: number\n type: number\n}\n\nexport const CustomDoubleBarPlotMXUI = ({\n color,\n data,\n series,\n style,\n ...restProps\n}: CustomDoubleBarPlotMXUIProps) => {\n const rectRef = React.useRef<SVGRectElement>(null)\n\n React.useLayoutEffect(() => {\n const resizeObserver = new ResizeObserver(() => {\n window.requestAnimationFrame(() => {\n if (rectRef.current) {\n const { width } = rectRef.current.getBoundingClientRect()\n\n const xValue = width / 2\n const textElement = rectRef.current.querySelector('text')\n if (textElement) {\n textElement.setAttribute('transform', `translate(${xValue}, -8)`)\n }\n }\n })\n })\n\n if (rectRef.current) resizeObserver.observe(rectRef.current)\n return () => {\n if (rectRef.current) resizeObserver.unobserve(rectRef.current)\n }\n }, [])\n\n const { ariaLabelComparison, ariaLabelMain } = data[series.index]\n\n const ariaLabel = series.type === 0 ? ariaLabelMain : ariaLabelComparison\n\n const rectStyle = {\n ...style,\n transition: 'all 0.3s ease-in-out',\n }\n\n // Create path with rounded top corners (10px radius) and square bottom corners\n const pathBarWidth = (style.width as number) || 0\n const pathBarHeight = (style.height as number) || 0\n const pathX = (style.x as number) || 0\n const pathY = (style.y as number) || 0\n const radius = 4\n\n const pathData = `\n M ${pathX + radius},${pathY}\n L ${pathX + pathBarWidth - radius},${pathY}\n Q ${pathX + pathBarWidth},${pathY} ${pathX + pathBarWidth},${pathY + radius}\n L ${pathX + pathBarWidth},${pathY + pathBarHeight}\n L ${pathX},${pathY + pathBarHeight}\n L ${pathX},${pathY + radius}\n Q ${pathX},${pathY} ${pathX + radius},${pathY}\n Z\n `.trim()\n\n return (\n <g aria-label={ariaLabel}>\n <path {...restProps} d={pathData} fill={color} style={rectStyle} />\n </g>\n )\n}\n"],"mappings":";;AAoBA,IAAa,IAAA,CAA2B,EACtC,OAAA,GACA,MAAA,GACA,QAAA,GACA,OAAA,GACA,GAAG,EAAA,MAC+B;AAClC,QAAM,IAAU,EAAM,OAAuB,IAAI;AAEjD,EAAA,EAAM,gBAAA,MAAsB;AAC1B,UAAM,IAAiB,IAAI,eAAA,MAAqB;AAC9C,aAAO,sBAAA,MAA4B;AACjC,YAAI,EAAQ,SAAS;AACnB,gBAAM,EAAE,OAAA,EAAA,IAAU,EAAQ,QAAQ,sBAAsB,GAElD,IAAS,IAAQ,GACjB,IAAc,EAAQ,QAAQ,cAAc,MAAM;AACxD,UAAI,KACF,EAAY,aAAa,aAAa,aAAa,CAAA,OAAa;AAAA,QAEpE;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,WAAI,EAAQ,WAAS,EAAe,QAAQ,EAAQ,OAAO,GAC3D,MAAa;AACX,MAAI,EAAQ,WAAS,EAAe,UAAU,EAAQ,OAAO;AAAA,IAC/D;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,EAAE,qBAAA,GAAqB,eAAA,EAAA,IAAkB,EAAK,EAAO,KAAA,GAErD,IAAY,EAAO,SAAS,IAAI,IAAgB,GAEhD,IAAY;AAAA,IAChB,GAAG;AAAA,IACH,YAAY;AAAA,EACd,GAGM,IAAgB,EAAM,SAAoB,GAC1C,IAAiB,EAAM,UAAqB,GAC5C,IAAS,EAAM,KAAgB,GAC/B,IAAS,EAAM,KAAgB,GAC/B,IAAS,GAET,IAAW;AAAA,QACX,IAAQ,CAAA,IAAU,CAAA;AAAA,QAClB,IAAQ,IAAe,CAAA,IAAU,CAAA;AAAA,QACjC,IAAQ,CAAA,IAAgB,CAAA,IAAS,IAAQ,CAAA,IAAgB,IAAQ,CAAA;AAAA,QACjE,IAAQ,CAAA,IAAgB,IAAQ,CAAA;AAAA,QAChC,CAAA,IAAS,IAAQ,CAAA;AAAA,QACjB,CAAA,IAAS,IAAQ,CAAA;AAAA,QACjB,CAAA,IAAS,CAAA,IAAS,IAAQ,CAAA,IAAU,CAAA;AAAA;AAAA,IAExC,KAAK;AAEP,SACE,gBAAA,EAAC,KAAD;AAAA,IAAG,cAAY;AAAA,IACb,UAAA,gBAAA,EAAC,QAAD;AAAA,MAAM,GAAI;AAAA,MAAW,GAAG;AAAA,MAAU,MAAM;AAAA,MAAO,OAAO;AAAA,IAAY,CAAA;AAAA,EACjE,CAAA;AAEP"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Legends } from '../../../core';
|
|
2
|
+
import { DataSet, LegendProps } from '../../../core/types/InsightsInstanceSlotData';
|
|
3
|
+
interface DoubleBarChartProps {
|
|
4
|
+
bars: DataSet[];
|
|
5
|
+
colors: string[];
|
|
6
|
+
legends?: (Legends | LegendProps)[];
|
|
7
|
+
isMini?: boolean;
|
|
8
|
+
onBarClick: (columnIndex: number, subIndex: number) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Pure double-bar chart (month columns x main/comparison). Presentational and self-contained \u2014 it
|
|
12
|
+
* receives shaped data + palette as props and reports clicks via onBarClick, holding no store,
|
|
13
|
+
* selection, or data-shaping of its own. This mirrors BarChartV2; the DoubleBarChartBlock card
|
|
14
|
+
* wrapper builds the data and injects the store behavior, exactly as BarchartBlock wraps BarChartV2.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DoubleBarChart: ({ bars, colors, legends, isMini, onBarClick, }: DoubleBarChartProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { EmptyBarChart as b } from "./EmptyBarChart.es.js";
|
|
2
|
+
import { useContainerDimensions as C } from "../../hooks/useContainerDimensions.es.js";
|
|
3
|
+
import { CustomDoubleBarPlotMXUI as k } from "./CustomDoubleBar.es.js";
|
|
4
|
+
import { Legend as w } from "./ChartLegend.es.js";
|
|
5
|
+
import S from "react";
|
|
6
|
+
import A from "@mui/material/Stack";
|
|
7
|
+
import { jsx as o, jsxs as m } from "react/jsx-runtime";
|
|
8
|
+
import I from "@mui/material/Box";
|
|
9
|
+
import { BarPlot as B } from "@mui/x-charts/BarChart";
|
|
10
|
+
import { ChartContainer as R } from "@mui/x-charts/ChartContainer";
|
|
11
|
+
import { ChartsXAxis as L } from "@mui/x-charts/ChartsXAxis";
|
|
12
|
+
var E = ({ bars: r, colors: n, legends: d, isMini: l = !1, onBarClick: h }) => {
|
|
13
|
+
const s = r.length - 1, p = 5e-3, f = 0.16, c = S.useRef(null), { height: y, width: x } = C(c), g = ({ dataIndex: e, seriesId: t }) => {
|
|
14
|
+
h(e, Number(t.split("-").pop()));
|
|
15
|
+
}, i = d?.map((e, t) => ({
|
|
16
|
+
color: n[t] ?? "transparent",
|
|
17
|
+
...e
|
|
18
|
+
}));
|
|
19
|
+
return r.length > 0 ? /* @__PURE__ */ m(A, {
|
|
20
|
+
sx: {
|
|
21
|
+
mb: 0,
|
|
22
|
+
width: "100%",
|
|
23
|
+
p: 0
|
|
24
|
+
},
|
|
25
|
+
children: [/* @__PURE__ */ o(I, {
|
|
26
|
+
ref: c,
|
|
27
|
+
sx: {
|
|
28
|
+
height: l ? 120 : 172,
|
|
29
|
+
touchAction: "pan-y",
|
|
30
|
+
width: "100%",
|
|
31
|
+
p: 0,
|
|
32
|
+
m: 0,
|
|
33
|
+
"& svg": {
|
|
34
|
+
touchAction: "pan-y",
|
|
35
|
+
userSelect: "none"
|
|
36
|
+
},
|
|
37
|
+
"& .recharts-wrapper": { touchAction: "pan-y" }
|
|
38
|
+
},
|
|
39
|
+
children: /* @__PURE__ */ m(R, {
|
|
40
|
+
colors: n,
|
|
41
|
+
dataset: r,
|
|
42
|
+
height: y,
|
|
43
|
+
margin: {
|
|
44
|
+
bottom: 16,
|
|
45
|
+
left: 24,
|
|
46
|
+
right: 24,
|
|
47
|
+
top: 0
|
|
48
|
+
},
|
|
49
|
+
series: [{
|
|
50
|
+
dataKey: "main",
|
|
51
|
+
type: "bar"
|
|
52
|
+
}, {
|
|
53
|
+
dataKey: "comparison",
|
|
54
|
+
type: "bar"
|
|
55
|
+
}],
|
|
56
|
+
width: x,
|
|
57
|
+
xAxis: [{
|
|
58
|
+
barGapRatio: p,
|
|
59
|
+
categoryGapRatio: f,
|
|
60
|
+
dataKey: "label",
|
|
61
|
+
scaleType: "band"
|
|
62
|
+
}],
|
|
63
|
+
yAxis: [{ width: 0 }],
|
|
64
|
+
children: [/* @__PURE__ */ o(L, {
|
|
65
|
+
disableTicks: !1,
|
|
66
|
+
slots: { axisTickLabel: ({ text: e, ...t }) => {
|
|
67
|
+
const a = r[s]?.label;
|
|
68
|
+
return /* @__PURE__ */ o("text", {
|
|
69
|
+
...t,
|
|
70
|
+
style: {
|
|
71
|
+
...t.style,
|
|
72
|
+
fontWeight: a === e ? 700 : 400
|
|
73
|
+
},
|
|
74
|
+
children: e
|
|
75
|
+
});
|
|
76
|
+
} },
|
|
77
|
+
sx: { ".MuiChartsAxis-line": { stroke: "border.darker" } },
|
|
78
|
+
tickLabelStyle: {
|
|
79
|
+
fontSize: 11,
|
|
80
|
+
fill: "text.secondary",
|
|
81
|
+
fontWeight: 400
|
|
82
|
+
}
|
|
83
|
+
}), /* @__PURE__ */ o(B, {
|
|
84
|
+
onItemClick: (e, { dataIndex: t, seriesId: a }) => g({
|
|
85
|
+
dataIndex: t,
|
|
86
|
+
seriesId: a.toString()
|
|
87
|
+
}),
|
|
88
|
+
slots: { bar: (e) => {
|
|
89
|
+
const { ownerState: t, ...a } = e, u = s === t.dataIndex ? t.color : `${t.color}50`;
|
|
90
|
+
return /* @__PURE__ */ o(k, {
|
|
91
|
+
...a,
|
|
92
|
+
color: u,
|
|
93
|
+
data: r,
|
|
94
|
+
series: {
|
|
95
|
+
index: t.dataIndex,
|
|
96
|
+
type: Number(t.id?.toString().split("-").pop() ?? 0)
|
|
97
|
+
},
|
|
98
|
+
style: {
|
|
99
|
+
height: e.height,
|
|
100
|
+
x: e.x,
|
|
101
|
+
y: e.y,
|
|
102
|
+
width: e.width
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
} }
|
|
106
|
+
})]
|
|
107
|
+
})
|
|
108
|
+
}), i && !l && i.length > 0 && /* @__PURE__ */ o(w, {
|
|
109
|
+
legendItems: i,
|
|
110
|
+
legendStyle: { ml: 24 }
|
|
111
|
+
})]
|
|
112
|
+
}) : /* @__PURE__ */ o(b, {});
|
|
113
|
+
};
|
|
114
|
+
export {
|
|
115
|
+
E as DoubleBarChart
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=DoubleBarChart.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DoubleBarChart.es.js","names":[],"sources":["../../../../src/insights-v2/components/chartblocks/DoubleBarChart.tsx"],"sourcesContent":["import React from 'react'\n\nimport Box from '@mui/material/Box'\nimport Stack from '@mui/material/Stack'\n\nimport { BarPlot } from '@mui/x-charts/BarChart'\nimport { ChartContainer } from '@mui/x-charts/ChartContainer'\nimport { ChartsXAxis } from '@mui/x-charts/ChartsXAxis'\n\nimport { useContainerDimensions } from '../../hooks/useContainerDimensions'\nimport type { Legends } from '../../../core'\nimport type { DataSet, LegendProps } from '../../../core/types/InsightsInstanceSlotData'\n\nimport { CustomDoubleBarPlotMXUI } from './CustomDoubleBar'\nimport { Legend } from './ChartLegend'\nimport { EmptyBarChart } from './EmptyBarChart'\n\ninterface DoubleBarChartProps {\n // Shaped comparison series (one entry per month column), built by the caller (buildComparisonSeries)\n // \\u2014 mirroring how BarchartBlock builds `data` for BarChartV2.\n bars: DataSet[]\n // Two-entry palette [main, comparison]. Resolved by the caller (the card via getLayoutConfig). This\n // prop is the only color hook \\u2014 getLayoutConfig itself is never modified.\n colors: string[]\n // Same shape as instance_slot_data.legends; mapped onto the palette below.\n legends?: (Legends | LegendProps)[]\n isMini?: boolean\n // Called on a bar click with the clicked column and its sub-series (0 = main, 1 = comparison); the\n // caller decides what a click does (card opens the drawer, drill-down updates its selection).\n onBarClick: (columnIndex: number, subIndex: number) => void\n}\n\n/**\n * Pure double-bar chart (month columns x main/comparison). Presentational and self-contained \\u2014 it\n * receives shaped data + palette as props and reports clicks via onBarClick, holding no store,\n * selection, or data-shaping of its own. This mirrors BarChartV2; the DoubleBarChartBlock card\n * wrapper builds the data and injects the store behavior, exactly as BarchartBlock wraps BarChartV2.\n */\nexport const DoubleBarChart = ({\n bars,\n colors,\n legends,\n isMini = false,\n onBarClick,\n}: DoubleBarChartProps) => {\n // The most recent (last) column is emphasized; the others are dimmed.\n const selectedTabIndex = bars.length - 1\n const barGapRatio = 0.005\n const categoryGapRatio = 0.16\n\n const containerRef = React.useRef<HTMLDivElement>(null)\n const { height, width } = useContainerDimensions(containerRef)\n\n const handleBarClick = ({ dataIndex, seriesId }: { dataIndex: number; seriesId: string }) => {\n const seriesType = Number(seriesId.split('-').pop())\n onBarClick(dataIndex, seriesType)\n }\n\n // colors can be empty for an unregistered variant (getLayoutConfig miss); fall back to transparent\n // so a swatch never renders as default-black.\n const legendItems = legends?.map((legend, index) => ({\n color: colors[index] ?? 'transparent',\n ...legend,\n })) as LegendProps[]\n\n return bars.length > 0 ? (\n <Stack sx={{ mb: 0, width: '100%', p: 0 }}>\n <Box\n ref={containerRef}\n sx={{\n height: isMini ? 120 : 172,\n touchAction: 'pan-y',\n width: '100%',\n p: 0,\n m: 0,\n '& svg': {\n touchAction: 'pan-y',\n userSelect: 'none',\n },\n '& .recharts-wrapper': {\n touchAction: 'pan-y',\n },\n }}\n >\n <ChartContainer\n colors={colors}\n dataset={bars as any[]}\n height={height}\n margin={{\n bottom: 16,\n left: 24,\n right: 24,\n top: 0,\n }}\n series={[\n { dataKey: 'main', type: 'bar' },\n { dataKey: 'comparison', type: 'bar' },\n ]}\n width={width}\n xAxis={[\n {\n barGapRatio,\n categoryGapRatio,\n dataKey: 'label',\n scaleType: 'band',\n },\n ]}\n yAxis={[{ width: 0 }]}\n >\n <ChartsXAxis\n disableTicks={false}\n slots={{\n axisTickLabel: ({ text, ...restProps }) => {\n const selectedLabel = bars[selectedTabIndex]?.label\n return (\n <text\n {...restProps}\n style={\n {\n ...restProps.style,\n fontWeight: selectedLabel === text ? 700 : 400,\n } as React.CSSProperties\n }\n >\n {text}\n </text>\n )\n },\n }}\n sx={{\n '.MuiChartsAxis-line': {\n stroke: 'border.darker',\n },\n }}\n tickLabelStyle={{\n fontSize: 11,\n fill: 'text.secondary',\n fontWeight: 400,\n }}\n />\n <BarPlot\n onItemClick={(_, { dataIndex, seriesId }) =>\n handleBarClick({ dataIndex, seriesId: seriesId.toString() })\n }\n slots={{\n bar: (props) => {\n const { ownerState, ...defaultProps } = props\n const isSelected = selectedTabIndex === ownerState.dataIndex\n const barColor = isSelected ? ownerState.color : `${ownerState.color}50`\n\n return (\n <CustomDoubleBarPlotMXUI\n {...defaultProps}\n color={barColor}\n data={bars}\n series={{\n index: ownerState.dataIndex,\n type: Number(ownerState.id?.toString().split('-').pop() ?? 0),\n }}\n style={{\n height: props.height,\n x: props.x,\n y: props.y,\n width: props.width,\n }}\n />\n )\n },\n }}\n />\n </ChartContainer>\n </Box>\n\n {legendItems && !isMini && legendItems.length > 0 && (\n <Legend legendItems={legendItems} legendStyle={{ ml: 24 }} />\n )}\n </Stack>\n ) : (\n <EmptyBarChart />\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BAR_CHART_VARIANTS as o, barChartVariant as t, buildChartData as m, buildDataSeries as i } from "./blocks/ChartBlocks/BarchartBlock/utils.es.js";
|
|
2
2
|
import { BarchartBlock as p } from "./blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js";
|
|
3
|
-
import { DoubleBarChartBlock as e } from "./blocks/ChartBlocks/DoubleBarChartBlock/
|
|
3
|
+
import { DoubleBarChartBlock as e } from "./blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js";
|
|
4
4
|
import n from "./blocks/ChartBlocks/DonutChartBlock/DonutChartBlock.es.js";
|
|
5
5
|
import s from "./blocks/ChartBlocks/DoubleProgressBarBlock/DoubleProgressBarBlock.es.js";
|
|
6
6
|
import g from "./blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BarchartBlock as o } from "../blocks/ChartBlocks/BarchartBlock/BarchartBlock.es.js";
|
|
2
|
-
import { DoubleBarChartBlock as r } from "../blocks/ChartBlocks/DoubleBarChartBlock/
|
|
2
|
+
import { DoubleBarChartBlock as r } from "../blocks/ChartBlocks/DoubleBarChartBlock/DoubleBarChartBlock.es.js";
|
|
3
3
|
import t from "../blocks/ChartBlocks/DonutChartBlock/DonutChartBlock.es.js";
|
|
4
4
|
import c from "../blocks/ChartBlocks/DoubleProgressBarBlock/DoubleProgressBarBlock.es.js";
|
|
5
5
|
import l from "../blocks/ComponentBlocks/AccountBlock/AccountBlock.es.js";
|
|
@@ -1,72 +1,106 @@
|
|
|
1
|
-
import { useAccountStore as
|
|
2
|
-
import { useScreenSize as
|
|
3
|
-
import { useWidgetLoadTimer as
|
|
4
|
-
import { ANALYTICS_EVENTS as
|
|
5
|
-
import { AccountType as
|
|
6
|
-
import
|
|
7
|
-
import { WidgetContainer as
|
|
8
|
-
import { EmptyState as
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import { TabTitle as
|
|
14
|
-
import
|
|
15
|
-
import { observer as
|
|
16
|
-
import
|
|
17
|
-
import { Fragment as
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { useAccountStore as O, useEvent as k, useGlobalCopyStore as F, useGlobalUiStore as K, useHoldingStore as y } from "../common/context/hooks.es.js";
|
|
2
|
+
import { useScreenSize as V } from "../common/hooks/useScreenSize.es.js";
|
|
3
|
+
import { useWidgetLoadTimer as H } from "../common/hooks/useWidgetLoadTimer.es.js";
|
|
4
|
+
import { ANALYTICS_EVENTS as s } from "../common/constants/Analytics.es.js";
|
|
5
|
+
import { AccountType as U } from "../core/types/Account.es.js";
|
|
6
|
+
import j from "../common/components/Loader.es.js";
|
|
7
|
+
import { WidgetContainer as z } from "../common/components/WidgetContainer.es.js";
|
|
8
|
+
import { EmptyState as B } from "../common/components/EmptyState.es.js";
|
|
9
|
+
import R from "../accounts/components/ConnectionsDrawer.es.js";
|
|
10
|
+
import Y from "./components/Allocation.es.js";
|
|
11
|
+
import $ from "./components/Analysis.es.js";
|
|
12
|
+
import q from "./components/Overview.es.js";
|
|
13
|
+
import { TabTitle as J } from "./components/TabTitle.es.js";
|
|
14
|
+
import l from "react";
|
|
15
|
+
import { observer as P } from "mobx-react-lite";
|
|
16
|
+
import Q from "@mui/material/Stack";
|
|
17
|
+
import { Fragment as X, jsx as t, jsxs as T } from "react/jsx-runtime";
|
|
18
|
+
import Z from "@mui/material/Tab";
|
|
19
|
+
import tt from "@mui/material/Tabs";
|
|
20
|
+
import et from "@mui/material/Tooltip";
|
|
21
|
+
var It = P(({ onBackClick: I, onMenuClick: S, sx: g }) => {
|
|
22
|
+
const { onEvent: c } = k(), { isMobile: v } = V(), { isAccountDataLoaded: A, loadAccountData: N, visibleInvestmentAccounts: L } = O(), { visibleHoldings: x, hasAllocationData: m, hasAnalysisData: d, setShowConnectionsWidget: _, showConnectionsWidget: D } = y(), { investments: e, accounts: W } = F(), { isInitialized: p } = K(), [o, f] = l.useState(0), { loadHoldings: w, holdingsLoaded: n } = y();
|
|
23
|
+
H({
|
|
23
24
|
widgetName: "InvestmentsWidget",
|
|
24
|
-
isLoaded:
|
|
25
|
-
}),
|
|
26
|
-
|
|
27
|
-
}, []),
|
|
28
|
-
|
|
29
|
-
}, [
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
isLoaded: n
|
|
26
|
+
}), l.useEffect(() => {
|
|
27
|
+
A || N().finally();
|
|
28
|
+
}, []), l.useEffect(() => {
|
|
29
|
+
p && w().finally();
|
|
30
|
+
}, [p]), l.useEffect(() => {
|
|
31
|
+
n && (o === 1 && !m && f(0), o === 2 && !d && f(0));
|
|
32
|
+
}, [
|
|
33
|
+
o,
|
|
34
|
+
m,
|
|
35
|
+
d,
|
|
36
|
+
n
|
|
37
|
+
]);
|
|
38
|
+
const M = () => {
|
|
39
|
+
c(s.INVESTMENT_WIDGET_ACCOUNT_FILTER_CLICK);
|
|
32
40
|
};
|
|
33
|
-
if (!
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
],
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
if (!p || !n) return /* @__PURE__ */ t(j, {});
|
|
42
|
+
const G = [
|
|
43
|
+
s.INVESTMENT_WIDGET_DETAILS_CLICK,
|
|
44
|
+
s.INVESTMENT_WIDGET_ALLOCATION_CLICK,
|
|
45
|
+
s.INVESTMENT_WIDGET_ANALYSIS_CLICK
|
|
46
|
+
], i = L.length === 0 && x.length === 0, b = [
|
|
47
|
+
{
|
|
48
|
+
title: e.tab_overview_title,
|
|
49
|
+
disabled: !1,
|
|
50
|
+
tooltip: ""
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: e.tab_allocation_title,
|
|
54
|
+
disabled: !m,
|
|
55
|
+
tooltip: e.allocation.empty_data
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: e.tab_analysis_title,
|
|
59
|
+
disabled: !d,
|
|
60
|
+
tooltip: e.analysis.empty_data
|
|
61
|
+
}
|
|
42
62
|
];
|
|
43
|
-
return /* @__PURE__ */
|
|
44
|
-
allowedAccountTypes: [
|
|
45
|
-
onAccountsFilterClick:
|
|
46
|
-
onBackClick:
|
|
47
|
-
onMenuClick:
|
|
48
|
-
sx:
|
|
63
|
+
return /* @__PURE__ */ T(z, {
|
|
64
|
+
allowedAccountTypes: [U.INVESTMENT],
|
|
65
|
+
onAccountsFilterClick: M,
|
|
66
|
+
onBackClick: I,
|
|
67
|
+
onMenuClick: S,
|
|
68
|
+
sx: g,
|
|
49
69
|
title: e.title,
|
|
50
|
-
children: [/* @__PURE__ */
|
|
51
|
-
mx:
|
|
70
|
+
children: [/* @__PURE__ */ T(Q, {
|
|
71
|
+
mx: v ? 0 : 48,
|
|
52
72
|
my: 24,
|
|
53
|
-
children: [/* @__PURE__ */ t(
|
|
54
|
-
onChange: (
|
|
55
|
-
|
|
73
|
+
children: [/* @__PURE__ */ t(tt, {
|
|
74
|
+
onChange: (r, a) => {
|
|
75
|
+
i || b[a]?.disabled || (f(a), c(G[a]));
|
|
56
76
|
},
|
|
57
77
|
sx: { bgcolor: "background.paper" },
|
|
58
78
|
textColor: "primary",
|
|
59
|
-
value:
|
|
79
|
+
value: i ? !1 : o,
|
|
60
80
|
variant: "fullWidth",
|
|
61
|
-
children:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
children: b.map(({ title: r, disabled: a, tooltip: C }) => {
|
|
82
|
+
const u = i || a, E = u && !i && !!C, h = /* @__PURE__ */ t(Z, {
|
|
83
|
+
"aria-disabled": u || void 0,
|
|
84
|
+
label: /* @__PURE__ */ t(J, { title: r }),
|
|
85
|
+
sx: {
|
|
86
|
+
...E && { flex: 1 },
|
|
87
|
+
...u && {
|
|
88
|
+
opacity: 0.38,
|
|
89
|
+
cursor: "default"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}, r);
|
|
93
|
+
return E ? /* @__PURE__ */ t(et, {
|
|
94
|
+
describeChild: !0,
|
|
95
|
+
title: C,
|
|
96
|
+
children: h
|
|
97
|
+
}, r) : h;
|
|
98
|
+
})
|
|
99
|
+
}), i ? /* @__PURE__ */ t(B, {
|
|
66
100
|
header: e.empty_state_header,
|
|
67
101
|
icon: "bid_landscape",
|
|
68
102
|
onClick: () => {
|
|
69
|
-
|
|
103
|
+
_(!0), c(s.ACCOUNTS_CLICK_CONNECT);
|
|
70
104
|
},
|
|
71
105
|
primaryButton: e.overview.connect_accounts,
|
|
72
106
|
subText: e.empty_state_description,
|
|
@@ -79,20 +113,20 @@ var ut = R(({ onBackClick: u, onMenuClick: T, sx: _ }) => {
|
|
|
79
113
|
},
|
|
80
114
|
px: 16
|
|
81
115
|
}
|
|
82
|
-
}) : /* @__PURE__ */
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
116
|
+
}) : /* @__PURE__ */ T(X, { children: [
|
|
117
|
+
o === 0 && /* @__PURE__ */ t(q, {}),
|
|
118
|
+
o === 1 && /* @__PURE__ */ t(Y, {}),
|
|
119
|
+
o === 2 && /* @__PURE__ */ t($, {})
|
|
86
120
|
] })]
|
|
87
|
-
}), /* @__PURE__ */ t(
|
|
88
|
-
onClose: () =>
|
|
89
|
-
showConnectionsWidget:
|
|
90
|
-
title:
|
|
121
|
+
}), /* @__PURE__ */ t(R, {
|
|
122
|
+
onClose: () => _(!1),
|
|
123
|
+
showConnectionsWidget: D,
|
|
124
|
+
title: W.manage_connections
|
|
91
125
|
})]
|
|
92
126
|
});
|
|
93
127
|
});
|
|
94
128
|
export {
|
|
95
|
-
|
|
129
|
+
It as InvestmentsWidget
|
|
96
130
|
};
|
|
97
131
|
|
|
98
132
|
//# sourceMappingURL=InvestmentsWidget.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InvestmentsWidget.es.js","names":[],"sources":["../../src/investments/InvestmentsWidget.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Stack from '@mui/material/Stack'\nimport Tab from '@mui/material/Tab'\nimport Tabs from '@mui/material/Tabs'\n\nimport {\n ANALYTICS_EVENTS,\n EmptyState,\n Loader,\n useAccountStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalUiStore,\n useHoldingStore,\n useScreenSize,\n useWidgetLoadTimer,\n WidgetContainer,\n} from '../common'\nimport { AccountType, WidgetProps } from '../core'\n\nimport ConnectionsDrawer from '../accounts/components/ConnectionsDrawer'\nimport Allocation from './components/Allocation'\nimport Analysis from './components/Analysis'\nimport Overview from './components/Overview'\nimport { TabTitle } from './components/TabTitle'\n\nexport const InvestmentsWidget = observer(({ onBackClick, onMenuClick, sx }: WidgetProps) => {\n const { onEvent } = useEvent()\n const { isMobile } = useScreenSize()\n const {\n isAccountDataLoaded,\n loadAccountData,\n visibleInvestmentAccounts: accounts,\n } = useAccountStore()\n const {\n visibleHoldings: holdings,\n setShowConnectionsWidget,\n showConnectionsWidget,\n } = useHoldingStore()\n const { investments: copy, accounts: accountsCopy } = useGlobalCopyStore()\n\n const { isInitialized } = useGlobalUiStore()\n\n const [selectedTab, setSelectedTab] = React.useState(0)\n\n const { loadHoldings, holdingsLoaded } = useHoldingStore()\n\n useWidgetLoadTimer({\n widgetName: 'InvestmentsWidget',\n isLoaded: holdingsLoaded,\n })\n\n React.useEffect(() => {\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n }, [])\n\n React.useEffect(() => {\n if (isInitialized) {\n loadHoldings().finally()\n }\n }, [isInitialized])\n\n const handleAccountFilterClick = () => {\n onEvent(ANALYTICS_EVENTS.INVESTMENT_WIDGET_ACCOUNT_FILTER_CLICK)\n }\n\n if (!isInitialized || !holdingsLoaded) return <Loader />\n\n const events = [\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_DETAILS_CLICK,\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_ALLOCATION_CLICK,\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_ANALYSIS_CLICK,\n ]\n const isEmptyState = accounts.length === 0 && holdings.length === 0\n const investmentTabs = [\n copy.tab_overview_title,\n copy.tab_allocation_title,\n copy.tab_analysis_title,\n ]\n return (\n <WidgetContainer\n allowedAccountTypes={[AccountType.INVESTMENT]}\n onAccountsFilterClick={handleAccountFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack mx={isMobile ? 0 : 48} my={24}>\n <Tabs\n onChange={(_, newValue) => {\n setSelectedTab(newValue)\n onEvent(events[newValue])\n }}\n sx={{ bgcolor: 'background.paper' }}\n textColor=\"primary\"\n value={!isEmptyState ? selectedTab : false}\n variant=\"fullWidth\"\n >\n {investmentTabs.map((title) => (\n <Tab
|
|
1
|
+
{"version":3,"file":"InvestmentsWidget.es.js","names":[],"sources":["../../src/investments/InvestmentsWidget.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Stack from '@mui/material/Stack'\nimport Tab from '@mui/material/Tab'\nimport Tabs from '@mui/material/Tabs'\nimport Tooltip from '@mui/material/Tooltip'\n\nimport {\n ANALYTICS_EVENTS,\n EmptyState,\n Loader,\n useAccountStore,\n useEvent,\n useGlobalCopyStore,\n useGlobalUiStore,\n useHoldingStore,\n useScreenSize,\n useWidgetLoadTimer,\n WidgetContainer,\n} from '../common'\nimport { AccountType, WidgetProps } from '../core'\n\nimport ConnectionsDrawer from '../accounts/components/ConnectionsDrawer'\nimport Allocation from './components/Allocation'\nimport Analysis from './components/Analysis'\nimport Overview from './components/Overview'\nimport { TabTitle } from './components/TabTitle'\n\nexport const InvestmentsWidget = observer(({ onBackClick, onMenuClick, sx }: WidgetProps) => {\n const { onEvent } = useEvent()\n const { isMobile } = useScreenSize()\n const {\n isAccountDataLoaded,\n loadAccountData,\n visibleInvestmentAccounts: accounts,\n } = useAccountStore()\n const {\n visibleHoldings: holdings,\n hasAllocationData,\n hasAnalysisData,\n setShowConnectionsWidget,\n showConnectionsWidget,\n } = useHoldingStore()\n const { investments: copy, accounts: accountsCopy } = useGlobalCopyStore()\n\n const { isInitialized } = useGlobalUiStore()\n\n const [selectedTab, setSelectedTab] = React.useState(0)\n\n const { loadHoldings, holdingsLoaded } = useHoldingStore()\n\n useWidgetLoadTimer({\n widgetName: 'InvestmentsWidget',\n isLoaded: holdingsLoaded,\n })\n\n React.useEffect(() => {\n if (!isAccountDataLoaded) {\n loadAccountData().finally()\n }\n }, [])\n\n React.useEffect(() => {\n if (isInitialized) {\n loadHoldings().finally()\n }\n }, [isInitialized])\n\n // Reset to Overview if the active tab becomes disabled. Only act once holdings\n // are loaded so a mid-refetch (getters briefly false) doesn't eject the user.\n // Depend only on the boolean getters, never `visibleHoldings` (new array each\n // access → render loop).\n React.useEffect(() => {\n if (!holdingsLoaded) return\n if (selectedTab === 1 && !hasAllocationData) setSelectedTab(0)\n if (selectedTab === 2 && !hasAnalysisData) setSelectedTab(0)\n }, [selectedTab, hasAllocationData, hasAnalysisData, holdingsLoaded])\n\n const handleAccountFilterClick = () => {\n onEvent(ANALYTICS_EVENTS.INVESTMENT_WIDGET_ACCOUNT_FILTER_CLICK)\n }\n\n if (!isInitialized || !holdingsLoaded) return <Loader />\n\n const events = [\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_DETAILS_CLICK,\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_ALLOCATION_CLICK,\n ANALYTICS_EVENTS.INVESTMENT_WIDGET_ANALYSIS_CLICK,\n ]\n const isEmptyState = accounts.length === 0 && holdings.length === 0\n const investmentTabs = [\n { title: copy.tab_overview_title, disabled: false, tooltip: '' },\n {\n title: copy.tab_allocation_title,\n disabled: !hasAllocationData,\n tooltip: copy.allocation.empty_data,\n },\n {\n title: copy.tab_analysis_title,\n disabled: !hasAnalysisData,\n tooltip: copy.analysis.empty_data,\n },\n ]\n return (\n <WidgetContainer\n allowedAccountTypes={[AccountType.INVESTMENT]}\n onAccountsFilterClick={handleAccountFilterClick}\n onBackClick={onBackClick}\n onMenuClick={onMenuClick}\n sx={sx}\n title={copy.title}\n >\n <Stack mx={isMobile ? 0 : 48} my={24}>\n <Tabs\n onChange={(_, newValue) => {\n // aria-disabled tabs stay clickable; block their selection here.\n if (isEmptyState || investmentTabs[newValue]?.disabled) return\n setSelectedTab(newValue)\n onEvent(events[newValue])\n }}\n sx={{ bgcolor: 'background.paper' }}\n textColor=\"primary\"\n value={!isEmptyState ? selectedTab : false}\n variant=\"fullWidth\"\n >\n {investmentTabs.map(({ title, disabled, tooltip }) => {\n const isDisabled = isEmptyState || disabled\n const isTooltipTab = isDisabled && !isEmptyState && Boolean(tooltip)\n // aria-disabled (not native disabled) keeps the Tab focusable and in\n // the a11y tree; describeChild adds the reason without stealing the name.\n const tab = (\n <Tab\n aria-disabled={isDisabled || undefined}\n key={title}\n label={<TabTitle title={title} />}\n sx={{\n ...(isTooltipTab && { flex: 1 }),\n ...(isDisabled && {\n opacity: 0.38,\n cursor: 'default',\n }),\n }}\n />\n )\n\n return isTooltipTab ? (\n <Tooltip describeChild key={title} title={tooltip}>\n {tab}\n </Tooltip>\n ) : (\n tab\n )\n })}\n </Tabs>\n {isEmptyState ? (\n <EmptyState\n header={copy.empty_state_header}\n icon=\"bid_landscape\"\n onClick={() => {\n setShowConnectionsWidget(true)\n onEvent(ANALYTICS_EVENTS.ACCOUNTS_CLICK_CONNECT)\n }}\n primaryButton={copy.overview.connect_accounts}\n subText={copy.empty_state_description}\n sx={{\n width: { sm: 432 },\n '.buttons-footer': {\n width: 167,\n },\n '.MuiTypography-h2': {\n mt: 20,\n mb: 4,\n },\n px: 16,\n }}\n />\n ) : (\n <>\n {selectedTab === 0 && <Overview />}\n {selectedTab === 1 && <Allocation />}\n {selectedTab === 2 && <Analysis />}\n </>\n )}\n </Stack>\n <ConnectionsDrawer\n onClose={() => setShowConnectionsWidget(false)}\n showConnectionsWidget={showConnectionsWidget}\n title={accountsCopy.manage_connections}\n />\n </WidgetContainer>\n )\n})\n"],"mappings":"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"}
|