@mx-cartographer/experiences 9.6.14 → 9.6.15

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.6.15] - 10-15-2026
2
+
3
+ - **ADDED** - `debts_block` `debt_summary` variant for the Debt Payoff Strategies beat when it spans several accounts (the architecture doc's Debts "Debt Summary" branch): a `TransactionListCard` on a primary-tinted slot with one row per debt account from `instance_slot.data.series` (pre-localized `logo`, `primary_text` name, `secondary_text` rate, `amount` balance, in the order sent; a row without a name is dropped), an optional `header_text`, and the total owed (`amount`) as the footer under a new optional `insights_feed.debts_block.total_balance_label` caption. With no rows the block renders nothing. Stories, fixtures and tests (WEC-1311)
4
+ - **CHANGED** - `DebtsBlock` now resolves its card per `instance_slot.variant` through a `layout.ts` table and `resolveVariantConfig` (the `AccountBlock` pattern; an unknown variant warns and renders the payoff card). Each variant needs only its own copy keys, so a host that has shipped the payoff labels but not `total_balance_label` keeps the payoff card intact. `projected_payoff` still reads its facts flat on `instance_slot` and renders exactly as before (WEC-1311)
5
+
1
6
  ## [9.6.14] - 10-15-2026
2
7
 
3
8
  - **ADDED** - `onAnalyticsEvent` callback on `BeatActions` (WEC-1849)
@@ -251,6 +251,8 @@ export interface DebtsBlockCopy {
251
251
  payoff_date_label: string;
252
252
  monthly_payment_label: string;
253
253
  interest_rate_label: string;
254
+ /** Footer caption for the `debt_summary` total, e.g. "Total balance". Optional until the service ships it. */
255
+ total_balance_label?: string;
254
256
  }
255
257
  export interface InsightsFeedCopy {
256
258
  general: GeneralInsightsFeedCopy;
@@ -1,24 +1,28 @@
1
1
  import { InsightsPayload } from '../../../../core';
2
- import { DebtPayoffCardStyleProps } from '../../../components/DebtPayoffCard';
2
+ export { PAYOFF_STYLE } from './layout';
3
3
  interface DebtsBlockProps {
4
4
  payload: InsightsPayload;
5
5
  beatGuid?: string;
6
6
  }
7
- /** `projected_payoff` look: primary-tinted slot and pill. The card story mirrors it from here. */
8
- export declare const PAYOFF_STYLE: DebtPayoffCardStyleProps;
9
7
  /**
10
8
  * Debts component block — the content card for the Debt Payoff Strategies beat.
9
+ * `instance_slot.variant` picks the card from `./layout.ts` through `resolveVariantConfig`, as
10
+ * `AccountBlock` does:
11
11
  *
12
- * The debt account's facts arrive flat on `instance_slot` (V2 contract — no `instance_slot_data`):
13
- * the balance (`amount`), `payoff_date`, `monthly_payment`, `interest_rate`, plus the shared
14
- * account/institution fields. Row labels come from `insights_feed.debts_block` copy, which
15
- * ships separately: until it has, the card shows the account row only (never an unlabelled number)
16
- * and warns once per mount so the rollout gap is traceable.
12
+ * - `projected_payoff` — one account on the `DebtPayoffCard`. Its facts arrive flat on
13
+ * `instance_slot` (the shape it shipped with): the balance (`amount`), `payoff_date`,
14
+ * `monthly_payment`, `interest_rate`, plus the shared account/institution fields.
15
+ * - `debt_summary` — the beat's several debt accounts on a `TransactionListCard`, read from
16
+ * `instance_slot.data`: one row per account from `series` (pre-localized `logo`, `primary_text`
17
+ * name, `secondary_text` rate, `amount` balance, in the order sent), an optional `header_text`,
18
+ * and the total owed (`amount`) as the footer. With no rows there is nothing to summarize and the
19
+ * block renders nothing.
17
20
  *
18
- * `instance_slot.variant` is not read yet: the architecture doc's other Debts branches (Debt
19
- * Summary, Interest Summary) have no design, so there is one look. Introduce a per-variant
20
- * registry (`createVariantBlock` + a `layout.ts` table, as `AccountBlock` does) with the second
21
- * variant, not before.
21
+ * Captions and payoff row labels come from `insights_feed.debts_block` copy, which ships
22
+ * separately. Each variant needs only its own keys: until they have shipped, the card shows what
23
+ * needs no copy (the account row, the summary rows) but never an unlabelled figure, and warns once
24
+ * per mount so the rollout gap is traceable. A row with no value (or an unparseable date) is
25
+ * dropped rather than rendered blank.
22
26
  */
23
27
  declare const DebtsBlock: ({ payload }: DebtsBlockProps) => import("react/jsx-runtime").JSX.Element;
24
28
  export default DebtsBlock;
@@ -1,56 +1,77 @@
1
- import { DATE_FORMATS_INTL as y, formatDate as h } from "../../../../core/constants/DateFormats.es.js";
2
- import { useGlobalCopyStore as v } from "../../../../common/context/hooks.es.js";
3
- import { formatCurrency as _, formatPercentage as g } from "../../../../core/utils/NumberFormatting.es.js";
4
- import { DepositLogo as D } from "../../../components/ComponentBlocks/DepositLogo.es.js";
5
- import T from "../../../components/DebtPayoffCard.es.js";
6
- import { parseDueDate as C } from "../UpcomingBillBlock/UpcomingBillBlock.es.js";
7
- import L from "react";
8
- import { jsx as b } from "react/jsx-runtime";
9
- var A = {
10
- bgcolor: "primary.lighter",
11
- pill: {
12
- bgcolor: "primary.lighter",
13
- labelColor: "text.primary"
14
- }
15
- }, E = /* @__PURE__ */ new Set([
1
+ import { DATE_FORMATS_INTL as R, formatDate as k } from "../../../../core/constants/DateFormats.es.js";
2
+ import { useGlobalCopyStore as F } from "../../../../common/context/hooks.es.js";
3
+ import { slot as f } from "../../../../core/types/Insights.es.js";
4
+ import { formatCurrency as i, formatPercentage as N } from "../../../../core/utils/NumberFormatting.es.js";
5
+ import P from "../../../components/LogoFromGuid.es.js";
6
+ import { DepositLogo as B } from "../../../components/ComponentBlocks/DepositLogo.es.js";
7
+ import { resolveVariantConfig as Y } from "../../resolveVariantConfig.es.js";
8
+ import G from "../../../components/DebtPayoffCard.es.js";
9
+ import j from "../../../components/TransactionListCard.es.js";
10
+ import { parseDueDate as I } from "../UpcomingBillBlock/UpcomingBillBlock.es.js";
11
+ import { DEBTS_LAYOUT as H, debtsBlockVariant as M } from "./layout.es.js";
12
+ import V from "react";
13
+ import { jsx as l } from "react/jsx-runtime";
14
+ import { useTheme as z } from "@mui/material/styles";
15
+ var U = 32, W = /* @__PURE__ */ new Set([
16
16
  "credit card",
17
17
  "credit_card",
18
18
  "creditcard"
19
- ]), R = (e) => E.has((e ?? "").trim().toLowerCase()) ? "credit_card" : "account_balance", S = (e) => !!e?.balance_label && !!e.payoff_date_label && !!e.monthly_payment_label && !!e.interest_rate_label, B = ({ payload: e }) => {
20
- const a = v().insights_feed?.debts_block, t = S(a) ? a : void 0, { account_name: u, account_type: l, amount: r, institution_guid: f, institution_name: p, interest_rate: n, monthly_payment: i, payoff_date: s, status_text: d } = e.instance_slot;
21
- L.useEffect(() => {
22
- t || console.warn(`debts_block: ${a ? "copy incomplete" : "copy namespace missing"}; rendering the account row only`);
23
- }, [a, t]);
24
- const c = s ? C(s) : null, o = [];
25
- t && c && o.push({
26
- label: t.payoff_date_label,
27
- value: h(c, y.MONTH_SHORT_YEAR)
28
- }), t && i != null && o.push({
29
- label: t.monthly_payment_label,
30
- value: _(i, "0,0.00")
31
- }), t && n != null && o.push({
32
- label: t.interest_rate_label,
33
- value: g(n / 100)
34
- });
35
- const m = t !== void 0 && r != null;
36
- return /* @__PURE__ */ b(T, {
37
- ...A,
38
- balance: m ? _(r, "0,0.00") : void 0,
39
- balanceLabel: m ? t.balance_label : void 0,
40
- logo: /* @__PURE__ */ b(D, {
41
- iconName: R(l),
42
- institutionGuid: f ?? "",
43
- institutionName: p ?? ""
19
+ ]), Z = (t) => W.has((t ?? "").trim().toLowerCase()) ? "credit_card" : "account_balance", $ = (t) => typeof t == "object" && t !== null && typeof t.primary_text == "string", q = (t) => !!t?.balance_label && !!t.payoff_date_label && !!t.monthly_payment_label && !!t.interest_rate_label, ct = ({ payload: t }) => {
20
+ const T = z(), o = F().insights_feed?.debts_block, { instance_slot: u } = t, { data: s, variant: A } = u, _ = Y(H, A, M.ProjectedPayoff, "DebtsBlock"), p = _.card === "summary", e = q(o) ? o : void 0, m = o?.total_balance_label, b = p ? !!m : !!e;
21
+ if (V.useEffect(() => {
22
+ b || console.warn(`debts_block: ${o ? "copy incomplete" : "copy namespace missing"}; rendering without its labelled figures`);
23
+ }, [o, b]), p) {
24
+ const r = f(s, "series"), O = (Array.isArray(r) ? r : []).filter($).map((a) => ({
25
+ amount: typeof a.amount == "number" ? i(a.amount, "0,0.00") : "",
26
+ leading: /* @__PURE__ */ l(P, {
27
+ logo: a.logo,
28
+ size: U
29
+ }),
30
+ subtitle: typeof a.secondary_text == "string" ? a.secondary_text : "",
31
+ title: a.primary_text
32
+ })), L = f(s, "header_text"), c = f(s, "amount");
33
+ return /* @__PURE__ */ l(j, {
34
+ background: T.palette.primary.lighter,
35
+ footer: m && typeof c == "number" && Number.isFinite(c) ? {
36
+ amount: i(c, "0,0.00"),
37
+ label: m
38
+ } : void 0,
39
+ header: typeof L == "string" ? L : void 0,
40
+ rows: O
41
+ });
42
+ }
43
+ const { account_name: C, account_type: d, amount: y, institution_guid: S, institution_name: x, interest_rate: g, monthly_payment: h, payoff_date: v, status_text: E } = u, n = [];
44
+ if (e) {
45
+ const r = v ? I(v) : null;
46
+ r && n.push({
47
+ label: e.payoff_date_label,
48
+ value: k(r, R.MONTH_SHORT_YEAR)
49
+ }), h != null && n.push({
50
+ label: e.monthly_payment_label,
51
+ value: i(h, "0,0.00")
52
+ }), g != null && n.push({
53
+ label: e.interest_rate_label,
54
+ value: N(g / 100)
55
+ });
56
+ }
57
+ const D = e !== void 0 && y != null;
58
+ return /* @__PURE__ */ l(G, {
59
+ ..._.style,
60
+ balance: D ? i(y, "0,0.00") : void 0,
61
+ balanceLabel: D ? e.balance_label : void 0,
62
+ logo: /* @__PURE__ */ l(B, {
63
+ iconName: Z(d),
64
+ institutionGuid: S ?? "",
65
+ institutionName: x ?? ""
44
66
  }),
45
- name: u,
46
- stats: o,
47
- statusLabel: d,
48
- subtitle: l
67
+ name: C,
68
+ stats: n,
69
+ statusLabel: E,
70
+ subtitle: d
49
71
  });
50
72
  };
51
73
  export {
52
- A as PAYOFF_STYLE,
53
- B as default
74
+ ct as default
54
75
  };
55
76
 
56
77
  //# sourceMappingURL=DebtsBlock.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DebtsBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.tsx"],"sourcesContent":["import React from 'react'\n\nimport { useGlobalCopyStore } from '../../../../common'\nimport type { InsightsPayload } from '../../../../core'\nimport { DATE_FORMATS_INTL, formatDate } from '../../../../core/constants'\nimport type { DebtsBlockCopy } from '../../../../core/types/localization/InsightsFeedCopy'\nimport { formatCurrency, formatPercentage } from '../../../../core/utils/NumberFormatting'\n\nimport DepositLogo from '../../../components/ComponentBlocks/DepositLogo'\nimport DebtPayoffCard, {\n type DebtPayoffCardStyleProps,\n type DebtPayoffStat,\n} from '../../../components/DebtPayoffCard'\nimport { parseDueDate } from '../UpcomingBillBlock/UpcomingBillBlock'\n\ninterface DebtsBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\n/** `projected_payoff` look: primary-tinted slot and pill. The card story mirrors it from here. */\nexport const PAYOFF_STYLE: DebtPayoffCardStyleProps = {\n bgcolor: 'primary.lighter',\n pill: { bgcolor: 'primary.lighter', labelColor: 'text.primary' },\n}\n\n/** Account types drawn with the card glyph when there is no institution logo; the rest get the bank. */\nconst CREDIT_CARD_TYPES = new Set(['credit card', 'credit_card', 'creditcard'])\n\nconst iconFor = (accountType?: string) =>\n CREDIT_CARD_TYPES.has((accountType ?? '').trim().toLowerCase())\n ? 'credit_card'\n : 'account_balance'\n\n/** Every label the card renders; a partial namespace counts as missing. */\nconst hasAllLabels = (copy?: DebtsBlockCopy): copy is DebtsBlockCopy =>\n !!copy?.balance_label &&\n !!copy.payoff_date_label &&\n !!copy.monthly_payment_label &&\n !!copy.interest_rate_label\n\n/**\n * Debts component block — the content card for the Debt Payoff Strategies beat.\n *\n * The debt account's facts arrive flat on `instance_slot` (V2 contract — no `instance_slot_data`):\n * the balance (`amount`), `payoff_date`, `monthly_payment`, `interest_rate`, plus the shared\n * account/institution fields. Row labels come from `insights_feed.debts_block` copy, which\n * ships separately: until it has, the card shows the account row only (never an unlabelled number)\n * and warns once per mount so the rollout gap is traceable.\n *\n * `instance_slot.variant` is not read yet: the architecture doc's other Debts branches (Debt\n * Summary, Interest Summary) have no design, so there is one look. Introduce a per-variant\n * registry (`createVariantBlock` + a `layout.ts` table, as `AccountBlock` does) with the second\n * variant, not before.\n */\nconst DebtsBlock = ({ payload }: DebtsBlockProps) => {\n const copy = useGlobalCopyStore().insights_feed?.debts_block\n const labels = hasAllLabels(copy) ? copy : undefined\n const {\n account_name,\n account_type,\n amount,\n institution_guid,\n institution_name,\n interest_rate,\n monthly_payment,\n payoff_date,\n status_text,\n } = payload.instance_slot\n\n React.useEffect(() => {\n if (labels) return\n console.warn(\n `debts_block: ${copy ? 'copy incomplete' : 'copy namespace missing'}; rendering the account row only`,\n )\n }, [copy, labels])\n\n // A row with no value (or an unparseable date) is dropped rather than rendered blank.\n const payoffDate = payoff_date ? parseDueDate(payoff_date) : null\n const stats: DebtPayoffStat[] = []\n if (labels && payoffDate) {\n stats.push({\n label: labels.payoff_date_label,\n value: formatDate(payoffDate, DATE_FORMATS_INTL.MONTH_SHORT_YEAR),\n })\n }\n if (labels && monthly_payment != null) {\n stats.push({\n label: labels.monthly_payment_label,\n value: formatCurrency(monthly_payment, '0,0.00'),\n })\n }\n if (labels && interest_rate != null) {\n // `interest_rate` arrives as a percentage (19.99); Intl's percent style expects a fraction.\n stats.push({ label: labels.interest_rate_label, value: formatPercentage(interest_rate / 100) })\n }\n\n const hasBalance = labels !== undefined && amount != null\n\n return (\n <DebtPayoffCard\n {...PAYOFF_STYLE}\n balance={hasBalance ? formatCurrency(amount, '0,0.00') : undefined}\n balanceLabel={hasBalance ? labels.balance_label : undefined}\n logo={\n <DepositLogo\n iconName={iconFor(account_type)}\n institutionGuid={institution_guid ?? ''}\n institutionName={institution_name ?? ''}\n />\n }\n name={account_name}\n stats={stats}\n statusLabel={status_text}\n subtitle={account_type}\n />\n )\n}\n\nexport default DebtsBlock\n"],"mappings":";;;;;;;;AAqBA,IAAa,IAAyC;AAAA,EACpD,SAAS;AAAA,EACT,MAAM;AAAA,IAAE,SAAS;AAAA,IAAmB,YAAY;AAAA,EAAe;AACjE,GAGM,IAAoB,oBAAI,IAAI;AAAA,EAAC;AAAA,EAAe;AAAA,EAAe;AAAY,CAAC,GAExE,IAAA,CAAW,MACf,EAAkB,KAAK,KAAe,IAAI,KAAK,EAAE,YAAY,CAAC,IAC1D,gBACA,mBAGA,IAAA,CAAgB,MACpB,CAAC,CAAC,GAAM,iBACR,CAAC,CAAC,EAAK,qBACP,CAAC,CAAC,EAAK,yBACP,CAAC,CAAC,EAAK,qBAgBH,IAAA,CAAc,EAAE,SAAA,EAAA,MAA+B;AACnD,QAAM,IAAO,EAAmB,EAAE,eAAe,aAC3C,IAAS,EAAa,CAAI,IAAI,IAAO,QACrC,EACJ,cAAA,GACA,cAAA,GACA,QAAA,GACA,kBAAA,GACA,kBAAA,GACA,eAAA,GACA,iBAAA,GACA,aAAA,GACA,aAAA,EAAA,IACE,EAAQ;AAEZ,EAAA,EAAM,UAAA,MAAgB;AACpB,IAAI,KACJ,QAAQ,KACN,gBAAgB,IAAO,oBAAoB,wBAAA,kCAC7C;AAAA,EACF,GAAG,CAAC,GAAM,CAAM,CAAC;AAGjB,QAAM,IAAa,IAAc,EAAa,CAAW,IAAI,MACvD,IAA0B,CAAC;AACjC,EAAI,KAAU,KACZ,EAAM,KAAK;AAAA,IACT,OAAO,EAAO;AAAA,IACd,OAAO,EAAW,GAAY,EAAkB,gBAAgB;AAAA,EAClE,CAAC,GAEC,KAAU,KAAmB,QAC/B,EAAM,KAAK;AAAA,IACT,OAAO,EAAO;AAAA,IACd,OAAO,EAAe,GAAiB,QAAQ;AAAA,EACjD,CAAC,GAEC,KAAU,KAAiB,QAE7B,EAAM,KAAK;AAAA,IAAE,OAAO,EAAO;AAAA,IAAqB,OAAO,EAAiB,IAAgB,GAAG;AAAA,EAAE,CAAC;AAGhG,QAAM,IAAa,MAAW,UAAa,KAAU;AAErD,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,GAAI;AAAA,IACJ,SAAS,IAAa,EAAe,GAAQ,QAAQ,IAAI;AAAA,IACzD,cAAc,IAAa,EAAO,gBAAgB;AAAA,IAClD,MACE,gBAAA,EAAC,GAAD;AAAA,MACE,UAAU,EAAQ,CAAY;AAAA,MAC9B,iBAAiB,KAAoB;AAAA,MACrC,iBAAiB,KAAoB;AAAA,IACtC,CAAA;AAAA,IAEH,MAAM;AAAA,IACC,OAAA;AAAA,IACP,aAAa;AAAA,IACb,UAAU;AAAA,EACX,CAAA;AAEL"}
1
+ {"version":3,"file":"DebtsBlock.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/DebtsBlock/DebtsBlock.tsx"],"sourcesContent":["import React from 'react'\n\nimport { useTheme } from '@mui/material/styles'\n\nimport { useGlobalCopyStore } from '../../../../common'\nimport { slot, type InsightsPayload, type InstanceSlotRow } from '../../../../core'\nimport { DATE_FORMATS_INTL, formatDate } from '../../../../core/constants'\nimport type { DebtsBlockCopy } from '../../../../core/types/localization/InsightsFeedCopy'\nimport { formatCurrency, formatPercentage } from '../../../../core/utils/NumberFormatting'\n\nimport DepositLogo from '../../../components/ComponentBlocks/DepositLogo'\nimport DebtPayoffCard, { type DebtPayoffStat } from '../../../components/DebtPayoffCard'\nimport LogoFromGuid from '../../../components/LogoFromGuid'\nimport TransactionListCard from '../../../components/TransactionListCard'\nimport { resolveVariantConfig } from '../../resolveVariantConfig'\nimport { parseDueDate } from '../UpcomingBillBlock/UpcomingBillBlock'\n\nimport { DEBTS_LAYOUT, debtsBlockVariant } from './layout'\n\n// The card story reads the block's look from here.\nexport { PAYOFF_STYLE } from './layout'\n\ninterface DebtsBlockProps {\n payload: InsightsPayload\n beatGuid?: string\n}\n\nconst ROW_LOGO_SIZE = 32\n\n/** Account types drawn with the card glyph when there is no institution logo; the rest get the bank. */\nconst CREDIT_CARD_TYPES = new Set(['credit card', 'credit_card', 'creditcard'])\n\nconst iconFor = (accountType?: string) =>\n CREDIT_CARD_TYPES.has((accountType ?? '').trim().toLowerCase())\n ? 'credit_card'\n : 'account_balance'\n\n/** A summary row ditto can draw: an object with a name. Anything else in `series` is skipped. */\nconst isNamedRow = (row: unknown): row is InstanceSlotRow & { primary_text: string } =>\n typeof row === 'object' &&\n row !== null &&\n typeof (row as InstanceSlotRow).primary_text === 'string'\n\n/** Every label the payoff card renders; a partial namespace counts as missing. */\nconst hasAllLabels = (copy?: DebtsBlockCopy): copy is DebtsBlockCopy =>\n !!copy?.balance_label &&\n !!copy.payoff_date_label &&\n !!copy.monthly_payment_label &&\n !!copy.interest_rate_label\n\n/**\n * Debts component block — the content card for the Debt Payoff Strategies beat.\n * `instance_slot.variant` picks the card from `./layout.ts` through `resolveVariantConfig`, as\n * `AccountBlock` does:\n *\n * - `projected_payoff` — one account on the `DebtPayoffCard`. Its facts arrive flat on\n * `instance_slot` (the shape it shipped with): the balance (`amount`), `payoff_date`,\n * `monthly_payment`, `interest_rate`, plus the shared account/institution fields.\n * - `debt_summary` — the beat's several debt accounts on a `TransactionListCard`, read from\n * `instance_slot.data`: one row per account from `series` (pre-localized `logo`, `primary_text`\n * name, `secondary_text` rate, `amount` balance, in the order sent), an optional `header_text`,\n * and the total owed (`amount`) as the footer. With no rows there is nothing to summarize and the\n * block renders nothing.\n *\n * Captions and payoff row labels come from `insights_feed.debts_block` copy, which ships\n * separately. Each variant needs only its own keys: until they have shipped, the card shows what\n * needs no copy (the account row, the summary rows) but never an unlabelled figure, and warns once\n * per mount so the rollout gap is traceable. A row with no value (or an unparseable date) is\n * dropped rather than rendered blank.\n */\nconst DebtsBlock = ({ payload }: DebtsBlockProps) => {\n const theme = useTheme()\n const copy = useGlobalCopyStore().insights_feed?.debts_block\n const { instance_slot } = payload\n const { data, variant } = instance_slot\n\n const layout = resolveVariantConfig(\n DEBTS_LAYOUT,\n variant,\n debtsBlockVariant.ProjectedPayoff,\n 'DebtsBlock',\n )\n const isSummary = layout.card === 'summary'\n\n const labels = hasAllLabels(copy) ? copy : undefined\n const totalLabel = copy?.total_balance_label\n const hasCopy = isSummary ? !!totalLabel : !!labels\n\n React.useEffect(() => {\n if (hasCopy) return\n console.warn(\n `debts_block: ${copy ? 'copy incomplete' : 'copy namespace missing'}; rendering without its labelled figures`,\n )\n }, [copy, hasCopy])\n\n if (isSummary) {\n // `slot()` is an unchecked cast over backend data, so every value is narrowed before use.\n const series = slot<unknown[]>(data, 'series')\n const rows = (Array.isArray(series) ? series : []).filter(isNamedRow).map((row) => ({\n amount: typeof row.amount === 'number' ? formatCurrency(row.amount, '0,0.00') : '',\n leading: <LogoFromGuid logo={row.logo} size={ROW_LOGO_SIZE} />,\n subtitle: typeof row.secondary_text === 'string' ? row.secondary_text : '',\n title: row.primary_text,\n }))\n const header = slot<unknown>(data, 'header_text')\n const total = slot<unknown>(data, 'amount')\n\n return (\n <TransactionListCard\n background={theme.palette.primary.lighter}\n footer={\n totalLabel && typeof total === 'number' && Number.isFinite(total)\n ? { amount: formatCurrency(total, '0,0.00'), label: totalLabel }\n : undefined\n }\n header={typeof header === 'string' ? header : undefined}\n rows={rows}\n />\n )\n }\n\n const {\n account_name,\n account_type,\n amount,\n institution_guid,\n institution_name,\n interest_rate,\n monthly_payment,\n payoff_date,\n status_text,\n } = instance_slot\n\n const stats: DebtPayoffStat[] = []\n if (labels) {\n const payoffDate = payoff_date ? parseDueDate(payoff_date) : null\n if (payoffDate) {\n stats.push({\n label: labels.payoff_date_label,\n value: formatDate(payoffDate, DATE_FORMATS_INTL.MONTH_SHORT_YEAR),\n })\n }\n if (monthly_payment != null) {\n stats.push({\n label: labels.monthly_payment_label,\n value: formatCurrency(monthly_payment, '0,0.00'),\n })\n }\n if (interest_rate != null) {\n // `interest_rate` arrives as a percentage (19.99); Intl's percent style expects a fraction.\n stats.push({\n label: labels.interest_rate_label,\n value: formatPercentage(interest_rate / 100),\n })\n }\n }\n\n const hasBalance = labels !== undefined && amount != null\n\n return (\n <DebtPayoffCard\n {...layout.style}\n balance={hasBalance ? formatCurrency(amount, '0,0.00') : undefined}\n balanceLabel={hasBalance ? labels.balance_label : undefined}\n logo={\n <DepositLogo\n iconName={iconFor(account_type)}\n institutionGuid={institution_guid ?? ''}\n institutionName={institution_name ?? ''}\n />\n }\n name={account_name}\n stats={stats}\n statusLabel={status_text}\n subtitle={account_type}\n />\n )\n}\n\nexport default DebtsBlock\n"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { DebtPayoffCardStyleProps } from '../../../components/DebtPayoffCard';
2
+ export declare const debtsBlockVariant: {
3
+ /** Debt Payoff Strategies, one account: balance plus projected payoff / monthly payment / rate rows. */
4
+ readonly ProjectedPayoff: "projected_payoff";
5
+ /** Debt Payoff Strategies, several accounts: one row per debt (balance, rate) and the total owed. */
6
+ readonly DebtSummary: "debt_summary";
7
+ };
8
+ export type DebtsBlockVariant = (typeof debtsBlockVariant)[keyof typeof debtsBlockVariant];
9
+ export interface DebtsBlockLayoutConfig {
10
+ /** Which card the variant draws: the single-account payoff card or the multi-account summary list. */
11
+ card: 'payoff' | 'summary';
12
+ /** Payoff card slot + pill tokens. */
13
+ style?: DebtPayoffCardStyleProps;
14
+ }
15
+ /** `projected_payoff` look: primary-tinted slot and pill. The card story mirrors it from here. */
16
+ export declare const PAYOFF_STYLE: DebtPayoffCardStyleProps;
17
+ export declare const DEBTS_LAYOUT: Record<string, DebtsBlockLayoutConfig>;
@@ -0,0 +1,24 @@
1
+ var r = {
2
+ ProjectedPayoff: "projected_payoff",
3
+ DebtSummary: "debt_summary"
4
+ }, e = {
5
+ bgcolor: "primary.lighter",
6
+ pill: {
7
+ bgcolor: "primary.lighter",
8
+ labelColor: "text.primary"
9
+ }
10
+ }, a = {
11
+ card: "payoff",
12
+ style: e
13
+ }, o = {
14
+ [r.ProjectedPayoff]: a,
15
+ [r.DebtSummary]: { card: "summary" },
16
+ default: a
17
+ };
18
+ export {
19
+ o as DEBTS_LAYOUT,
20
+ e as PAYOFF_STYLE,
21
+ r as debtsBlockVariant
22
+ };
23
+
24
+ //# sourceMappingURL=layout.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.es.js","names":[],"sources":["../../../../../src/insights-v2/blocks/ComponentBlocks/DebtsBlock/layout.ts"],"sourcesContent":["import type { DebtPayoffCardStyleProps } from '../../../components/DebtPayoffCard'\n\nexport const debtsBlockVariant = {\n /** Debt Payoff Strategies, one account: balance plus projected payoff / monthly payment / rate rows. */\n ProjectedPayoff: 'projected_payoff',\n /** Debt Payoff Strategies, several accounts: one row per debt (balance, rate) and the total owed. */\n DebtSummary: 'debt_summary',\n} as const\n\nexport type DebtsBlockVariant = (typeof debtsBlockVariant)[keyof typeof debtsBlockVariant]\n\nexport interface DebtsBlockLayoutConfig {\n /** Which card the variant draws: the single-account payoff card or the multi-account summary list. */\n card: 'payoff' | 'summary'\n /** Payoff card slot + pill tokens. */\n style?: DebtPayoffCardStyleProps\n}\n\n/** `projected_payoff` look: primary-tinted slot and pill. The card story mirrors it from here. */\nexport const PAYOFF_STYLE: DebtPayoffCardStyleProps = {\n bgcolor: 'primary.lighter',\n pill: { bgcolor: 'primary.lighter', labelColor: 'text.primary' },\n}\n\nconst PROJECTED_PAYOFF: DebtsBlockLayoutConfig = { card: 'payoff', style: PAYOFF_STYLE }\n\nexport const DEBTS_LAYOUT: Record<string, DebtsBlockLayoutConfig> = {\n [debtsBlockVariant.ProjectedPayoff]: PROJECTED_PAYOFF,\n [debtsBlockVariant.DebtSummary]: { card: 'summary' },\n // Neutral fallback for an unknown variant: the payoff card. `resolveVariantConfig` warns first.\n default: PROJECTED_PAYOFF,\n}\n"],"mappings":"AAEA,IAAa,IAAoB;AAAA,EAE/B,iBAAiB;AAAA,EAEjB,aAAa;AACf,GAYa,IAAyC;AAAA,EACpD,SAAS;AAAA,EACT,MAAM;AAAA,IAAE,SAAS;AAAA,IAAmB,YAAY;AAAA,EAAe;AACjE,GAEM,IAA2C;AAAA,EAAE,MAAM;AAAA,EAAU,OAAO;AAAa,GAE1E,IAAuD;AAAA,EACjE,CAAA,EAAkB,eAAA,GAAkB;AAAA,EACpC,CAAA,EAAkB,WAAA,GAAc,EAAE,MAAM,UAAU;AAAA,EAEnD,SAAS;AACX"}
@@ -2,7 +2,7 @@ import C from "./InsightTransactionRow.es.js";
2
2
  import { Fragment as R } from "react";
3
3
  import t from "@mui/material/Stack";
4
4
  import { Text as h } from "@mxenabled/mxui";
5
- import { Fragment as x, jsx as r, jsxs as d } from "react/jsx-runtime";
5
+ import { Fragment as x, jsx as r, jsxs as a } from "react/jsx-runtime";
6
6
  import v from "@mui/material/Box";
7
7
  import p from "@mui/material/Divider";
8
8
  var w = (n) => n === "primary" ? {
@@ -29,9 +29,9 @@ var w = (n) => n === "primary" ? {
29
29
  px: 16,
30
30
  py: 2
31
31
  }
32
- }, H = ({ background: n, footer: l, header: i, rows: m, variant: g = "default", sx: b }) => {
32
+ }, H = ({ background: n, footer: l, header: d, rows: m, variant: g = "default", sx: b }) => {
33
33
  if (m.length === 0) return null;
34
- const e = w(g), a = !!n, o = a ? "8px" : e.radius, s = !!i && !a && e.headerInsideBorder, c = i ? /* @__PURE__ */ r(t, {
34
+ const e = w(g), i = !!n, o = i ? "8px" : e.radius, s = !!d && !i && e.headerInsideBorder, c = d ? /* @__PURE__ */ r(t, {
35
35
  sx: {
36
36
  bgcolor: e.headerBg,
37
37
  justifyContent: "center",
@@ -41,12 +41,12 @@ var w = (n) => n === "primary" ? {
41
41
  bold: e.headerBold,
42
42
  color: e.headerColor,
43
43
  variant: "caption",
44
- children: i
44
+ children: d
45
45
  })
46
- }) : null, f = l ? /* @__PURE__ */ d(x, { children: [/* @__PURE__ */ r(p, {}), /* @__PURE__ */ d(t, {
46
+ }) : null, f = l ? /* @__PURE__ */ a(x, { children: [/* @__PURE__ */ r(p, {}), /* @__PURE__ */ a(t, {
47
47
  sx: {
48
48
  alignItems: "center",
49
- bgcolor: a ? "background.paper" : "background.default",
49
+ bgcolor: i ? "background.paper" : "background.default",
50
50
  flexDirection: "row",
51
51
  justifyContent: "space-between",
52
52
  minHeight: 40,
@@ -66,14 +66,15 @@ var w = (n) => n === "primary" ? {
66
66
  })] }) : null, B = /* @__PURE__ */ r(t, {
67
67
  role: "list",
68
68
  sx: { width: "100%" },
69
- children: m.map((y, u) => /* @__PURE__ */ d(R, { children: [u > 0 && /* @__PURE__ */ r(p, { role: "presentation" }), /* @__PURE__ */ r(v, {
69
+ children: m.map((y, u) => /* @__PURE__ */ a(R, { children: [u > 0 && /* @__PURE__ */ r(p, { role: "presentation" }), /* @__PURE__ */ r(v, {
70
70
  role: "listitem",
71
71
  children: /* @__PURE__ */ r(C, { ...y })
72
72
  })] }, u))
73
73
  });
74
- return /* @__PURE__ */ d(t, {
74
+ return /* @__PURE__ */ a(t, {
75
+ "data-testid": "transaction-list-card",
75
76
  sx: {
76
- ...a ? {
77
+ ...i ? {
77
78
  background: n,
78
79
  p: 16
79
80
  } : {
@@ -90,21 +91,21 @@ var w = (n) => n === "primary" ? {
90
91
  overflow: "hidden"
91
92
  },
92
93
  children: c
93
- }), /* @__PURE__ */ d(t, {
94
+ }), /* @__PURE__ */ a(t, {
94
95
  sx: {
95
- ...a ? { bgcolor: "background.paper" } : {
96
+ ...i ? { bgcolor: "background.paper" } : {
96
97
  border: "1px solid",
97
98
  borderColor: e.borderColor
98
99
  },
99
100
  borderBottomLeftRadius: o,
100
101
  borderBottomRightRadius: o,
101
- borderTopLeftRadius: s || !i ? o : 0,
102
- borderTopRightRadius: s || !i ? o : 0,
102
+ borderTopLeftRadius: s || !d ? o : 0,
103
+ borderTopRightRadius: s || !d ? o : 0,
103
104
  overflow: "hidden",
104
105
  width: "100%"
105
106
  },
106
107
  children: [
107
- s && /* @__PURE__ */ d(x, { children: [c, /* @__PURE__ */ r(p, {})] }),
108
+ s && /* @__PURE__ */ a(x, { children: [c, /* @__PURE__ */ r(p, {})] }),
108
109
  B,
109
110
  f
110
111
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionListCard.es.js","names":[],"sources":["../../../src/insights-v2/components/TransactionListCard.tsx"],"sourcesContent":["import { Fragment, type ReactNode } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Divider from '@mui/material/Divider'\nimport Stack from '@mui/material/Stack'\nimport type { SxProps } from '@mui/material/styles'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport InsightTransactionRow, { type InsightTransactionRowProps } from './InsightTransactionRow'\n\nexport interface FooterRow {\n label: ReactNode\n amount: ReactNode\n amountColor?: string\n}\n\ntype TransactionListCardVariant = 'default' | 'primary'\n\ninterface TransactionListCardProps {\n /** Optional header label above the rows (e.g. \"{Date}\", \"3 transactions\"). */\n header?: ReactNode\n /** One or more transaction rows. */\n rows: InsightTransactionRowProps[]\n /** Optional summary/total row rendered beneath a divider. */\n footer?: FooterRow\n /**\n * Card style:\n * - `default` — grey utility header, hairline border, radius 4.\n * - `primary` — filled `primary.main` header with white text and a matching\n * border, radius 8 (Figma \"Multi\" variant).\n *\n * In both cases the header is borderless; the border wraps the content block\n * below it.\n */\n variant?: TransactionListCardVariant\n /**\n * Optional background applied to the Slot behind the card. Must be a valid CSS\n * background string (gradient or color in CSS format); MUI theme tokens are\n * not resolved here (this is the CSS `background` shorthand, not `bgcolor`), so\n * use a CSS color literal instead. When set, the inner card renders borderless\n * on a white surface inside the padded Slot (Figma HSA Deposit).\n */\n background?: string\n sx?: SxProps\n}\n\nconst getVariantStyles = (variant: TransactionListCardVariant) => {\n switch (variant) {\n case 'primary':\n // Borderless filled header on top of the bordered rows block.\n return {\n radius: '8px',\n borderColor: 'primary.main',\n headerBg: 'primary.main',\n headerColor: 'primary.contrastText',\n headerBold: false,\n headerInsideBorder: false,\n headerSx: { minHeight: 24, px: 12, py: 4 } as const,\n }\n default:\n // A single border wraps the card; the grey header sits inside it.\n return {\n radius: '8px',\n borderColor: 'divider',\n headerBg: 'background.default',\n headerColor: 'text.primary',\n headerBold: true,\n headerInsideBorder: true,\n headerSx: { minHeight: 36, px: 16, py: 2 } as const,\n }\n }\n}\n\n/**\n * List card composing an optional header label, one or more\n * `InsightTransactionRow`s (divided), and an optional footer/total row.\n * `variant` supplies the Figma design defaults for the two card styles.\n *\n * Scope is the Content section only; Header/Description are out of scope.\n */\nconst TransactionListCard = ({\n background,\n footer,\n header,\n rows,\n variant = 'default',\n sx,\n}: TransactionListCardProps) => {\n // rows usually comes from mapped API data, so an empty array is reachable and\n // would render a broken border shell; render nothing instead.\n if (rows.length === 0) return null\n\n const styles = getVariantStyles(variant)\n const hasBackground = Boolean(background)\n const radius = hasBackground ? '8px' : styles.radius\n // The header sits inside the border only for the bordered `default` variant;\n // for `primary`/backgrounded cards it sits above a separately-bordered body.\n const headerInsideBorder = Boolean(header) && !hasBackground && styles.headerInsideBorder\n\n const headerBlock = header ? (\n <Stack sx={{ bgcolor: styles.headerBg, justifyContent: 'center', ...styles.headerSx }}>\n <Text bold={styles.headerBold} color={styles.headerColor} variant=\"caption\">\n {header}\n </Text>\n </Stack>\n ) : null\n\n const footerBlock = footer ? (\n <>\n <Divider />\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: hasBackground ? 'background.paper' : 'background.default',\n flexDirection: 'row',\n justifyContent: 'space-between',\n minHeight: 40,\n px: 16,\n py: 2,\n }}\n >\n <Text color=\"text.secondary\" variant=\"caption\">\n {footer.label}\n </Text>\n <Text bold={true} color={footer.amountColor ?? 'text.primary'} variant=\"body2\">\n {footer.amount}\n </Text>\n </Stack>\n </>\n ) : null\n\n const rowsBlock = (\n <Stack role=\"list\" sx={{ width: '100%' }}>\n {rows.map((row, index) => (\n // Static, caller-ordered list that may contain identical rows, so the\n // array index is the correct key (a content-based key would collide).\n // eslint-disable-next-line react/no-array-index-key\n <Fragment key={index}>\n {index > 0 && <Divider role=\"presentation\" />}\n <Box role=\"listitem\">\n <InsightTransactionRow {...row} />\n </Box>\n </Fragment>\n ))}\n </Stack>\n )\n\n return (\n <Stack\n sx={{\n ...(hasBackground ? { background, p: 16 } : { pt: 8, px: 16 }),\n width: '100%',\n ...sx,\n }}\n >\n {/* Header above the border for `primary`/backgrounded cards; top-rounded. */}\n {!headerInsideBorder && headerBlock && (\n <Stack\n sx={{\n borderTopLeftRadius: radius,\n borderTopRightRadius: radius,\n overflow: 'hidden',\n }}\n >\n {headerBlock}\n </Stack>\n )}\n\n <Stack\n sx={{\n ...(hasBackground\n ? { bgcolor: 'background.paper' }\n : { border: '1px solid', borderColor: styles.borderColor }),\n borderBottomLeftRadius: radius,\n borderBottomRightRadius: radius,\n borderTopLeftRadius: headerInsideBorder || !header ? radius : 0,\n borderTopRightRadius: headerInsideBorder || !header ? radius : 0,\n overflow: 'hidden',\n width: '100%',\n }}\n >\n {/* Header inside the border for the `default` table variant. */}\n {headerInsideBorder && (\n <>\n {headerBlock}\n <Divider />\n </>\n )}\n {rowsBlock}\n {footerBlock}\n </Stack>\n </Stack>\n )\n}\n\nexport default TransactionListCard\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransactionListCard.es.js","names":[],"sources":["../../../src/insights-v2/components/TransactionListCard.tsx"],"sourcesContent":["import { Fragment, type ReactNode } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Divider from '@mui/material/Divider'\nimport Stack from '@mui/material/Stack'\nimport type { SxProps } from '@mui/material/styles'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport InsightTransactionRow, { type InsightTransactionRowProps } from './InsightTransactionRow'\n\nexport interface FooterRow {\n label: ReactNode\n amount: ReactNode\n amountColor?: string\n}\n\ntype TransactionListCardVariant = 'default' | 'primary'\n\ninterface TransactionListCardProps {\n /** Optional header label above the rows (e.g. \"{Date}\", \"3 transactions\"). */\n header?: ReactNode\n /** One or more transaction rows. */\n rows: InsightTransactionRowProps[]\n /** Optional summary/total row rendered beneath a divider. */\n footer?: FooterRow\n /**\n * Card style:\n * - `default` — grey utility header, hairline border, radius 4.\n * - `primary` — filled `primary.main` header with white text and a matching\n * border, radius 8 (Figma \"Multi\" variant).\n *\n * In both cases the header is borderless; the border wraps the content block\n * below it.\n */\n variant?: TransactionListCardVariant\n /**\n * Optional background applied to the Slot behind the card. Must be a valid CSS\n * background string (gradient or color in CSS format); MUI theme tokens are\n * not resolved here (this is the CSS `background` shorthand, not `bgcolor`), so\n * use a CSS color literal instead. When set, the inner card renders borderless\n * on a white surface inside the padded Slot (Figma HSA Deposit).\n */\n background?: string\n sx?: SxProps\n}\n\nconst getVariantStyles = (variant: TransactionListCardVariant) => {\n switch (variant) {\n case 'primary':\n // Borderless filled header on top of the bordered rows block.\n return {\n radius: '8px',\n borderColor: 'primary.main',\n headerBg: 'primary.main',\n headerColor: 'primary.contrastText',\n headerBold: false,\n headerInsideBorder: false,\n headerSx: { minHeight: 24, px: 12, py: 4 } as const,\n }\n default:\n // A single border wraps the card; the grey header sits inside it.\n return {\n radius: '8px',\n borderColor: 'divider',\n headerBg: 'background.default',\n headerColor: 'text.primary',\n headerBold: true,\n headerInsideBorder: true,\n headerSx: { minHeight: 36, px: 16, py: 2 } as const,\n }\n }\n}\n\n/**\n * List card composing an optional header label, one or more\n * `InsightTransactionRow`s (divided), and an optional footer/total row.\n * `variant` supplies the Figma design defaults for the two card styles.\n *\n * Scope is the Content section only; Header/Description are out of scope.\n */\nconst TransactionListCard = ({\n background,\n footer,\n header,\n rows,\n variant = 'default',\n sx,\n}: TransactionListCardProps) => {\n // rows usually comes from mapped API data, so an empty array is reachable and\n // would render a broken border shell; render nothing instead.\n if (rows.length === 0) return null\n\n const styles = getVariantStyles(variant)\n const hasBackground = Boolean(background)\n const radius = hasBackground ? '8px' : styles.radius\n // The header sits inside the border only for the bordered `default` variant;\n // for `primary`/backgrounded cards it sits above a separately-bordered body.\n const headerInsideBorder = Boolean(header) && !hasBackground && styles.headerInsideBorder\n\n const headerBlock = header ? (\n <Stack sx={{ bgcolor: styles.headerBg, justifyContent: 'center', ...styles.headerSx }}>\n <Text bold={styles.headerBold} color={styles.headerColor} variant=\"caption\">\n {header}\n </Text>\n </Stack>\n ) : null\n\n const footerBlock = footer ? (\n <>\n <Divider />\n <Stack\n sx={{\n alignItems: 'center',\n bgcolor: hasBackground ? 'background.paper' : 'background.default',\n flexDirection: 'row',\n justifyContent: 'space-between',\n minHeight: 40,\n px: 16,\n py: 2,\n }}\n >\n <Text color=\"text.secondary\" variant=\"caption\">\n {footer.label}\n </Text>\n <Text bold={true} color={footer.amountColor ?? 'text.primary'} variant=\"body2\">\n {footer.amount}\n </Text>\n </Stack>\n </>\n ) : null\n\n const rowsBlock = (\n <Stack role=\"list\" sx={{ width: '100%' }}>\n {rows.map((row, index) => (\n // Static, caller-ordered list that may contain identical rows, so the\n // array index is the correct key (a content-based key would collide).\n // eslint-disable-next-line react/no-array-index-key\n <Fragment key={index}>\n {index > 0 && <Divider role=\"presentation\" />}\n <Box role=\"listitem\">\n <InsightTransactionRow {...row} />\n </Box>\n </Fragment>\n ))}\n </Stack>\n )\n\n return (\n <Stack\n data-testid=\"transaction-list-card\"\n sx={{\n ...(hasBackground ? { background, p: 16 } : { pt: 8, px: 16 }),\n width: '100%',\n ...sx,\n }}\n >\n {/* Header above the border for `primary`/backgrounded cards; top-rounded. */}\n {!headerInsideBorder && headerBlock && (\n <Stack\n sx={{\n borderTopLeftRadius: radius,\n borderTopRightRadius: radius,\n overflow: 'hidden',\n }}\n >\n {headerBlock}\n </Stack>\n )}\n\n <Stack\n sx={{\n ...(hasBackground\n ? { bgcolor: 'background.paper' }\n : { border: '1px solid', borderColor: styles.borderColor }),\n borderBottomLeftRadius: radius,\n borderBottomRightRadius: radius,\n borderTopLeftRadius: headerInsideBorder || !header ? radius : 0,\n borderTopRightRadius: headerInsideBorder || !header ? radius : 0,\n overflow: 'hidden',\n width: '100%',\n }}\n >\n {/* Header inside the border for the `default` table variant. */}\n {headerInsideBorder && (\n <>\n {headerBlock}\n <Divider />\n </>\n )}\n {rowsBlock}\n {footerBlock}\n </Stack>\n </Stack>\n )\n}\n\nexport default TransactionListCard\n"],"mappings":"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"}
@@ -24,15 +24,15 @@ import X from "./components/DirectDepositCard.es.js";
24
24
  import Z from "./blocks/ComponentBlocks/DirectDepositBlock/DirectDepositBlock.es.js";
25
25
  import { BudgetBlock as oo } from "./blocks/ComponentBlocks/BudgetBlock/BudgetBlock.es.js";
26
26
  import to from "./components/DebtPayoffCard.es.js";
27
- import io from "./components/UpcomingBillCard.es.js";
28
- import po from "./blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js";
29
- import eo from "./blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js";
30
- import co from "./components/SaveAnExtraCard.es.js";
31
- import so from "./blocks/ComponentBlocks/SaveExtraBlock/SaveExtraBlock.es.js";
32
- import Co from "./components/SavingsOpportunityCard.es.js";
33
- import uo from "./blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js";
34
- import So from "./components/InsightTransactionRow.es.js";
35
- import Do from "./components/TransactionListCard.es.js";
27
+ import io from "./components/InsightTransactionRow.es.js";
28
+ import po from "./components/TransactionListCard.es.js";
29
+ import eo from "./components/UpcomingBillCard.es.js";
30
+ import co from "./blocks/ComponentBlocks/UpcomingBillBlock/UpcomingBillBlock.es.js";
31
+ import so from "./blocks/ComponentBlocks/DebtsBlock/DebtsBlock.es.js";
32
+ import Co from "./components/SaveAnExtraCard.es.js";
33
+ import uo from "./blocks/ComponentBlocks/SaveExtraBlock/SaveExtraBlock.es.js";
34
+ import So from "./components/SavingsOpportunityCard.es.js";
35
+ import Do from "./blocks/ComponentBlocks/SavingsOpportunityBlock/SavingsOpportunityBlock.es.js";
36
36
  import { transactionBlockVariant as Ao } from "./blocks/ComponentBlocks/TransactionBlock/layout.es.js";
37
37
  import { TransactionBlock as Io } from "./blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js";
38
38
  import vo from "./components/AmountPill.es.js";
@@ -72,7 +72,7 @@ export {
72
72
  k as CompactInsightCard,
73
73
  Go as ConnectionDetailDrillDown,
74
74
  to as DebtPayoffCard,
75
- eo as DebtsBlock,
75
+ so as DebtsBlock,
76
76
  _o as DesignateEmergencySavingsCard,
77
77
  Z as DirectDepositBlock,
78
78
  X as DirectDepositCard,
@@ -88,7 +88,7 @@ export {
88
88
  mr as HiddenConfirmationCard,
89
89
  h as InsightErrorCard,
90
90
  l as InsightOptionsMenu,
91
- So as InsightTransactionRow,
91
+ io as InsightTransactionRow,
92
92
  ar as LoadingCard,
93
93
  Cr as LogoClusterCard,
94
94
  d as LogoFromGuid,
@@ -98,10 +98,10 @@ export {
98
98
  n as OverflowMenu,
99
99
  Sr as P2PLogoStack,
100
100
  Vo as SVGImageBlock,
101
- co as SaveAnExtraCard,
102
- so as SaveExtraBlock,
103
- uo as SavingsOpportunityBlock,
104
- Co as SavingsOpportunityCard,
101
+ Co as SaveAnExtraCard,
102
+ uo as SaveExtraBlock,
103
+ Do as SavingsOpportunityBlock,
104
+ So as SavingsOpportunityCard,
105
105
  g as StatusBadge,
106
106
  lr as StatusMessageCard,
107
107
  r as StatusPill,
@@ -110,10 +110,10 @@ export {
110
110
  Oo as SubscriptionHeroCard,
111
111
  Qo as SurveyModal,
112
112
  Io as TransactionBlock,
113
- Do as TransactionListCard,
113
+ po as TransactionListCard,
114
114
  j as TransferLogoCard,
115
- po as UpcomingBillBlock,
116
- io as UpcomingBillCard,
115
+ co as UpcomingBillBlock,
116
+ eo as UpcomingBillCard,
117
117
  yo as UpcomingSubscriptionBlock,
118
118
  Ro as WithdrawalBlock,
119
119
  Po as WithdrawalCard,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mx-cartographer/experiences",
3
- "version": "9.6.14",
3
+ "version": "9.6.15",
4
4
  "description": "Library containing experience widgets",
5
5
  "author": "MX",
6
6
  "license": "MIT",