@mx-cartographer/experiences 9.7.89 → 9.7.91

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/core/types/Insights.d.ts +4 -0
  3. package/dist/core/types/Insights.es.js.map +1 -1
  4. package/dist/insights-v2/actionBlocks/SubscriptionStatusModalBlock.es.js +80 -70
  5. package/dist/insights-v2/actionBlocks/SubscriptionStatusModalBlock.es.js.map +1 -1
  6. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js +43 -42
  7. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js.map +1 -1
  8. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.d.ts +2 -0
  9. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js +4 -3
  10. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/layout.es.js.map +1 -1
  11. package/dist/insights-v2/components/CompactInsightCard.es.js +176 -127
  12. package/dist/insights-v2/components/CompactInsightCard.es.js.map +1 -1
  13. package/dist/insights-v2/components/TransactionListCard.d.ts +1 -1
  14. package/dist/insights-v2/components/TransactionListCard.es.js +30 -26
  15. package/dist/insights-v2/components/TransactionListCard.es.js.map +1 -1
  16. package/dist/insights-v2/components/shared/StatusSnackbar.d.ts +5 -1
  17. package/dist/insights-v2/components/shared/StatusSnackbar.es.js +31 -11
  18. package/dist/insights-v2/components/shared/StatusSnackbar.es.js.map +1 -1
  19. package/dist/insights-v2/components/shared/elevation.d.ts +7 -0
  20. package/dist/insights-v2/components/shared/elevation.es.js +9 -0
  21. package/dist/insights-v2/components/shared/elevation.es.js.map +1 -0
  22. package/dist/insights-v2/ctaActions/ctaConfig.es.js +16 -8
  23. package/dist/insights-v2/ctaActions/ctaConfig.es.js.map +1 -1
  24. package/dist/insights-v2/ctaActions/index.d.ts +1 -1
  25. package/dist/insights-v2/ctaActions/runCtaAction.d.ts +6 -0
  26. package/dist/insights-v2/ctaActions/runCtaAction.es.js +1 -0
  27. package/dist/insights-v2/ctaActions/runCtaAction.es.js.map +1 -1
  28. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CompactInsightCard.es.js","names":[],"sources":["../../../src/insights-v2/components/CompactInsightCard.tsx"],"sourcesContent":["import type { KeyboardEvent, MouseEvent } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { useInsightsV2Store } from '../../common'\nimport { TinyBarChart } from '../../common/components/TinyBarChart'\nimport { slot } from '../../core'\nimport type {\n Beat,\n DataSeries,\n InsightsPayload,\n InstanceSlotData,\n LogoRef,\n PrimaryCTA,\n} from '../../core'\nimport type { ActionDrawerTrigger } from '../../core/stores'\nimport type { AccountSwitchBlockV2Data } from '../../core/types/InsightsInstanceSlotData'\nimport { getCategoryColor } from '../../core/utils/CategoryUtil'\nimport {\n BAR_ARIA_LABEL,\n buildChartData,\n buildDataSeries,\n} from '../blocks/ChartBlocks/BarchartBlock/utils'\nimport { ActionBlockLayer } from '../actionBlocks/ActionBlockLayer'\nimport { createVariantBlock } from '../blocks/createVariantBlock'\nimport BadgedTile from './BadgedTile'\nimport InsightOptionsMenu from './InsightOptionsMenu'\nimport LogoFromGuid from './LogoFromGuid'\nimport { ReactComponent as FeeDetectedIllustration } from './shared/images/FeeDetected.svg'\nimport { ThemedSVGImage } from './chartblocks/ThemedSVGImage'\nimport StatusBadge from './StatusBadge'\n\n/** Figma 1941:111897: the tile the logo fills is 44px (rows are 32, the notification row 33). */\nconst ICON_SIZE = 44\n\ninterface InsightVisualProps {\n /** The slot's `logo`, when ditto's variant declares and fills one. */\n logo?: LogoRef | null\n /** The slot's whole `data`, for a visual drawn from more than the logo (`category_color`, `linked_logos`). */\n data?: InstanceSlotData\n}\n\n// Figma 1943:219189: 36px logos at opposite corners of a 75×74 box, the badge and rings centred.\nconst LINKED_LOGO_SIZE = 36\nconst LINKED_BOX_WIDTH = 75\nconst LINKED_BOX_HEIGHT = 74\n\nconst CENTRED = {\n left: '50%',\n position: 'absolute',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n} as const\n\n/** Figma 222:33404 (Embedded | Bill Amount Not Standard) shows the latest three bars. */\nconst BAR_CHART_BAR_COUNT = 3\n\n/** The slot's logo, or the neutral insight glyph when the slot carries none. */\nconst LogoOrFallback = ({ logo }: InsightVisualProps) =>\n logo ? (\n <LogoFromGuid logo={logo} size={ICON_SIZE} />\n ) : (\n <Box\n data-testid=\"compact-insight-card-fallback-icon\"\n sx={{\n alignItems: 'center',\n bgcolor: 'primary.lighter',\n display: 'flex',\n height: ICON_SIZE,\n justifyContent: 'center',\n width: ICON_SIZE,\n }}\n >\n <Icon color=\"primary\" fill={true} name=\"lightbulb\" size={24} />\n </Box>\n )\n\n/** Micro, and any variant not registered below: the logo alone. */\nconst PlainVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile center={<LogoOrFallback logo={logo} />} size={ICON_SIZE} sx={{ flexShrink: 0 }} />\n)\n\n/** ditto `with_warning_badge`: the logo badged with a status glyph (Figma 1941:111897). */\nconst WarningBadgeVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile\n center={<LogoOrFallback logo={logo} />}\n size={ICON_SIZE}\n sx={{ flexShrink: 0 }}\n topRight={<StatusBadge tone=\"warning\" />}\n />\n)\n\n/**\n * ditto `with_illustration`: artwork in place of the logo tile (Fee Detected's search illustration).\n * A single SVG themed at runtime by `ThemedSVGImage`: its `brand300` elements are recolored to the\n * theme's `primary.main` (so it follows dark mode), while `fill=\"white\"` areas stay white. The\n * slot's `logo` is deliberately unused: the illustration replaces the tile.\n */\nconst IllustrationVisual = () => {\n return (\n <ThemedSVGImage\n divProps={{ style: { flexShrink: 0, lineHeight: 0, width: 'max-content' } }}\n image={FeeDetectedIllustration}\n />\n )\n}\n\n/**\n * ditto `linked_logos` (Figma 1943:219189, Embedded | Discovered Accounts): the two institutions at\n * opposite corners of a 75×74 box — `from_logo` top-left, `to_logo` bottom-right — meeting on the\n * diagonal, with a link badge over two rings at the centre. The rings and badge are decorative (`aria-hidden`); each\n * logo's accessible name is its `alt`.\n */\nconst LinkedLogosVisual = ({ data }: InsightVisualProps) => {\n const { from_logo, to_logo } = (data ?? {}) as AccountSwitchBlockV2Data\n\n return (\n <Box\n sx={{\n flexShrink: 0,\n height: LINKED_BOX_HEIGHT,\n position: 'relative',\n width: LINKED_BOX_WIDTH,\n }}\n >\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-ring\"\n sx={{ ...CENTRED, bgcolor: 'primary.light', borderRadius: '50%', height: 36, width: 36 }}\n />\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-ring\"\n sx={{\n ...CENTRED,\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: '50%',\n height: 48,\n width: 48,\n }}\n />\n <Box sx={{ borderRadius: '4px', left: 0, overflow: 'hidden', position: 'absolute', top: 0 }}>\n <LogoFromGuid logo={from_logo} size={LINKED_LOGO_SIZE} />\n </Box>\n <Box\n sx={{ borderRadius: '4px', bottom: 0, overflow: 'hidden', position: 'absolute', right: 0 }}\n >\n <LogoFromGuid logo={to_logo} size={LINKED_LOGO_SIZE} />\n </Box>\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-badge\"\n sx={{\n ...CENTRED,\n alignItems: 'center',\n bgcolor: 'primary.main',\n border: '2px solid',\n borderColor: 'primary.contrastText',\n borderRadius: '12px',\n display: 'flex',\n justifyContent: 'center',\n p: 2,\n zIndex: 1,\n }}\n >\n <Icon name=\"link\" size={16} sx={{ color: 'primary.contrastText' }} />\n </Box>\n </Box>\n )\n}\n\n/**\n * ditto `category_color`: a tiny bar chart of the latest bars in place of the logo tile, tinted by\n * the slot's category, the newest bar solid (Figma 222:33404). Draws nothing without a series.\n */\nconst BarChartVisual = ({ data }: InsightVisualProps) => {\n const series = buildDataSeries(slot<DataSeries>(data, 'series'))\n if (!series.length) return null\n\n const categoryGuid = slot<string>(data, 'category_guid')\n const bars = buildChartData(series, BAR_ARIA_LABEL).slice(-BAR_CHART_BAR_COUNT)\n\n return (\n <Box data-testid=\"compact-insight-card-bar-chart\" sx={{ flexShrink: 0 }}>\n <TinyBarChart\n color={(theme) =>\n categoryGuid ? getCategoryColor(categoryGuid, theme) : theme.palette.primary.main\n }\n data={bars}\n />\n </Box>\n )\n}\n\n/**\n * The card's right-hand visual, one component per ditto layout variant.\n *\n * A variant names a rendering *shape*, not an insight or a surface — `with_header` already serves\n * both Large Transaction and Fee Detected — so an insight wanting the badged logo reuses\n * `with_warning_badge`. Only a genuinely different visual registers a new entry, and existing ones\n * are never touched.\n *\n * `minimal` draws the plain logo and is registered explicitly even though it matches the fallback:\n * micro and notification resolve it on every render, and an unregistered variant warns. The\n * fallback is for variants we genuinely do not know.\n */\nconst InsightVisual = createVariantBlock<InsightVisualProps>({\n variants: {\n category_color: BarChartVisual,\n linked_logos: LinkedLogosVisual,\n minimal: PlainVisual,\n with_illustration: IllustrationVisual,\n with_warning_badge: WarningBadgeVisual,\n },\n fallback: PlainVisual,\n name: 'InsightVisual',\n})\n\n/**\n * Beats whose embedded CTA the card reads from its own envelope key and opens in this card's\n * `ActionBlockLayer`, as a bar click does on the full card. The trigger names that key, so the layer\n * resolves the same CTA. Every other beat keeps `primary_cta` and hands it to the host's `onCtaClick`\n * (e.g. `contact_support_block`). A new beat adds its template here.\n */\nconst BEAT_CTA_CONFIG: Record<\n string,\n { key: 'primary_cta' | 'in_description_cta'; trigger: ActionDrawerTrigger }\n> = {\n BillAmountNotStandard: { key: 'in_description_cta', trigger: 'inDescriptionCta' },\n ConnectDiscoveredAccountsV2: { key: 'in_description_cta', trigger: 'inDescriptionCta' },\n}\n\nexport interface CompactInsightCardProps {\n /** A `micro` or `embedded` envelope. */\n payload: InsightsPayload\n /** The envelope's beat; when given, the card mounts its `ActionBlockLayer` for CTA drawers. */\n beat?: Beat\n /**\n * Makes the whole card the tap target. What a tap does is the host's decision (post to the\n * host app, open a drawer, …); the card never opens anything itself. Omit for a static card.\n */\n onTap?: () => void\n /** Receives the primary CTA when tapped. The card does not resolve the CTA's block itself. */\n onCtaClick?: (cta: PrimaryCTA) => void\n /**\n * Renders the CTA disabled — label shown, `aria-disabled`, not tappable — for a host that cannot\n * honour it (e.g. `contact_support_block` when the client's `enable_support_requests` is off).\n */\n isCtaDisabled?: boolean\n}\n\nconst stopPropagation = (event: MouseEvent) => event.stopPropagation()\n\n/**\n * The one compact renderer the micro and embedded envelopes share (`insights_v2.2.md` §8.3).\n *\n * Figma 1941:111897 (Embedded | Large Transaction): a title row with the overflow slot, the HTML\n * description with the primary CTA under it, and on the right the slot's `logo` in a\n * `<BadgedTile>`. Under ditto's `with_warning_badge` variant the tile takes a status badge; under\n * `minimal` it draws the logo alone. The card lays out from the envelope alone and never reads\n * `widget_type`.\n *\n * The icon falls back to the neutral insight glyph **here**, not in `LogoFromGuid`, when the slot\n * carries no logo. The `pill` on the same envelope is the transaction row's, not the card's.\n */\nconst CompactInsightCard = ({\n beat,\n isCtaDisabled = false,\n onCtaClick,\n onTap,\n payload,\n}: CompactInsightCardProps) => {\n const { openActionDrawer } = useInsightsV2Store()\n const { description, instance_slot, primary_cta, title } = payload\n const beatCta = BEAT_CTA_CONFIG[payload.template ?? '']\n const cta = beatCta ? payload[beatCta.key] : primary_cta\n // Reduced variants (`minimal`, `with_warning_badge`) declare a bare `logo` slot.\n const rowLogo = slot<LogoRef>(instance_slot.data, 'logo')\n\n const handleCtaClick = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation()\n if (isCtaDisabled || !cta) return\n\n if (beatCta) {\n if (beat) openActionDrawer({ guid: beat.guid, trigger: beatCta.trigger })\n return\n }\n if (primary_cta) onCtaClick?.(primary_cta)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n // Only the card itself: Enter on the CTA button is the button's own click.\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onTap?.()\n }\n }\n\n const interactiveProps = onTap\n ? { onClick: onTap, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 }\n : {}\n\n return (\n <>\n <Card\n data-testid=\"compact-insight-card\"\n {...interactiveProps}\n sx={{\n minWidth: 288,\n pb: 12,\n pl: 8,\n pr: 16,\n pt: 8,\n ...(onTap && { cursor: 'pointer' }),\n }}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n gap: 8,\n justifyContent: 'space-between',\n pl: 8,\n pt: 4,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {title ?? ''}\n </Text>\n {/* The menu renders only when the host wired `onMenuAction` (BeatActionsProvider). */}\n <Box onClick={stopPropagation} sx={{ display: 'flex' }}>\n <InsightOptionsMenu />\n </Box>\n </Stack>\n\n <Stack sx={{ flexDirection: 'row', gap: 16, pl: 8, pt: 4 }}>\n <Stack sx={{ flex: 1, gap: 8, minWidth: 0 }}>\n {/* `html_text` is rendered server-side by mrs_content from the ditto copy template (bold\n amount / merchant), not user-authored input; painted the same way `BaseLayout` paints\n the full card's description. */}\n <P\n dangerouslySetInnerHTML={{ __html: description.html_text }}\n data-testid=\"compact-insight-card-description\"\n sx={{ fontWeight: 'fontWeightRegular' }}\n variant=\"subtitle2\"\n />\n {cta?.label && (\n <Button\n aria-disabled={isCtaDisabled}\n onClick={handleCtaClick}\n size=\"small\"\n sx={{\n alignSelf: 'flex-start',\n // Figma 1941:111897 lines the CTA label up with the description's left edge. The\n // column already pads 8, so the button's own 8 is pulled back out — padding kept so\n // the tap target does not shrink.\n mt: 5,\n ml: -8,\n px: 8,\n ...(isCtaDisabled && {\n color: 'text.disabled',\n cursor: 'default',\n }),\n }}\n variant=\"text\"\n >\n <Text bold={true} variant=\"body2\">\n {cta.label}\n </Text>\n </Button>\n )}\n </Stack>\n\n <InsightVisual data={instance_slot.data} logo={rowLogo} variant={instance_slot.variant} />\n </Stack>\n </Card>\n {/* Outside the Card: the drawer is a portal, and its clicks would otherwise bubble to `onTap`. */}\n {beat && <ActionBlockLayer beat={beat} />}\n </>\n )\n}\n\nexport default CompactInsightCard\n"],"mappings":"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"}
1
+ {"version":3,"file":"CompactInsightCard.es.js","names":[],"sources":["../../../src/insights-v2/components/CompactInsightCard.tsx"],"sourcesContent":["import type { KeyboardEvent, MouseEvent } from 'react'\n\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Card from '@mui/material/Card'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { P, Text } from '@mxenabled/mxui'\n\nimport { useGlobalStore, useInsightsV2Store } from '../../common'\nimport { TinyBarChart } from '../../common/components/TinyBarChart'\nimport { slot } from '../../core'\nimport type {\n Beat,\n DataSeries,\n InsightsPayload,\n InstanceSlotData,\n LogoRef,\n PrimaryCTA,\n} from '../../core'\nimport type { ActionDrawerTrigger } from '../../core/stores'\nimport type { AccountSwitchBlockV2Data } from '../../core/types/InsightsInstanceSlotData'\nimport { getCategoryColor } from '../../core/utils/CategoryUtil'\nimport {\n BAR_ARIA_LABEL,\n buildChartData,\n buildDataSeries,\n} from '../blocks/ChartBlocks/BarchartBlock/utils'\nimport { ActionBlockLayer } from '../actionBlocks/ActionBlockLayer'\nimport { createVariantBlock } from '../blocks/createVariantBlock'\nimport { postCtaMessage } from '../ctaActions'\nimport BadgedTile from './BadgedTile'\nimport InsightOptionsMenu from './InsightOptionsMenu'\nimport LogoFromGuid from './LogoFromGuid'\nimport { ReactComponent as FeeDetectedIllustration } from './shared/images/FeeDetected.svg'\nimport { ThemedSVGImage } from './chartblocks/ThemedSVGImage'\nimport StatusBadge from './StatusBadge'\n\nconst DESCRIPTION_MAX_LINES = 2\n\n/** Figma 1941:111897: the tile the logo fills is 44px (rows are 32, the notification row 33). */\nconst ICON_SIZE = 44\n\ninterface InsightVisualProps {\n /** The slot's `logo`, when ditto's variant declares and fills one. */\n logo?: LogoRef | null\n /** The slot's whole `data`, for a visual drawn from more than the logo (`category_color`, `linked_logos`). */\n data?: InstanceSlotData\n /** The envelope's template, for a beat's own badge on `linked_logos`. */\n template?: string\n}\n\n// Figma 1943:219189: 36px logos at opposite corners of a 75×74 box, the badge and rings centred.\nconst LINKED_LOGO_SIZE = 36\nconst LINKED_BOX_WIDTH = 75\nconst LINKED_BOX_HEIGHT = 74\n\nconst CENTRED = {\n left: '50%',\n position: 'absolute',\n top: '50%',\n transform: 'translate(-50%, -50%)',\n} as const\n\n/** Figma 222:33404 (Embedded | Bill Amount Not Standard) shows the latest three bars. */\nconst BAR_CHART_BAR_COUNT = 3\n\n/** The slot's logo, or the neutral insight glyph when the slot carries none. */\nconst LogoOrFallback = ({ logo }: InsightVisualProps) =>\n logo ? (\n <LogoFromGuid logo={logo} size={ICON_SIZE} />\n ) : (\n <Box\n data-testid=\"compact-insight-card-fallback-icon\"\n sx={{\n alignItems: 'center',\n bgcolor: 'primary.lighter',\n display: 'flex',\n height: ICON_SIZE,\n justifyContent: 'center',\n width: ICON_SIZE,\n }}\n >\n <Icon color=\"primary\" fill={true} name=\"lightbulb\" size={24} />\n </Box>\n )\n\n/** Micro, and any variant not registered below: the logo alone. */\nconst PlainVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile center={<LogoOrFallback logo={logo} />} size={ICON_SIZE} sx={{ flexShrink: 0 }} />\n)\n\n/** ditto `with_warning_badge`: the logo badged with a status glyph (Figma 1941:111897). */\nconst WarningBadgeVisual = ({ logo }: InsightVisualProps) => (\n <BadgedTile\n center={<LogoOrFallback logo={logo} />}\n size={ICON_SIZE}\n sx={{ flexShrink: 0 }}\n topRight={<StatusBadge tone=\"warning\" />}\n />\n)\n\n/**\n * ditto `with_illustration`: artwork in place of the logo tile (Fee Detected's search illustration).\n * A single SVG themed at runtime by `ThemedSVGImage`: its `brand300` elements are recolored to the\n * theme's `primary.main` (so it follows dark mode), while `fill=\"white\"` areas stay white. The\n * slot's `logo` is deliberately unused: the illustration replaces the tile.\n */\nconst IllustrationVisual = () => {\n return (\n <ThemedSVGImage\n divProps={{ style: { flexShrink: 0, lineHeight: 0, width: 'max-content' } }}\n image={FeeDetectedIllustration}\n />\n )\n}\n\nconst SWAP_BADGE_SIZE = 24\n\nconst LinkBadge = () => (\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-badge\"\n sx={{\n ...CENTRED,\n alignItems: 'center',\n bgcolor: 'primary.main',\n border: '2px solid',\n borderColor: 'primary.contrastText',\n borderRadius: '12px',\n display: 'flex',\n justifyContent: 'center',\n p: 2,\n zIndex: 1,\n }}\n >\n <Icon name=\"link\" size={16} sx={{ color: 'primary.contrastText' }} />\n </Box>\n)\n\n/**\n * Switch Direct Deposit (Figma 1941:167601): the outlined `swap_vertical_circle`, turned horizontal,\n * over a contrast disc: a primary ring and arrows on white. Drawn 1.2× so its circle fills 24px.\n */\nconst SwapBadge = () => (\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-badge\"\n sx={{\n ...CENTRED,\n alignItems: 'center',\n bgcolor: 'primary.contrastText',\n borderRadius: '50%',\n display: 'flex',\n height: SWAP_BADGE_SIZE,\n justifyContent: 'center',\n overflow: 'hidden',\n width: SWAP_BADGE_SIZE,\n zIndex: 1,\n }}\n >\n <Icon\n name=\"swap_vertical_circle\"\n size={SWAP_BADGE_SIZE * 1.2}\n sx={{ color: 'primary.main', flexShrink: 0, transform: 'rotate(-90deg)' }}\n />\n </Box>\n)\n\n/**\n * ditto `linked_logos` (Figma 1943:219189, Embedded | Discovered Accounts): the two institutions at\n * opposite corners of a 75×74 box — `from_logo` top-left, `to_logo` bottom-right — meeting on the\n * diagonal, with a badge over two rings at the centre (Switch Direct Deposit: the swap badge on an\n * outlined inner ring). The rings and badge are decorative (`aria-hidden`); each logo's accessible\n * name is its `alt`.\n */\nconst LinkedLogosVisual = ({ data, template }: InsightVisualProps) => {\n const { from_logo, to_logo } = (data ?? {}) as AccountSwitchBlockV2Data\n const isSwap = template === 'SwitchDirectDeposit'\n\n return (\n <Box\n sx={{\n flexShrink: 0,\n height: LINKED_BOX_HEIGHT,\n position: 'relative',\n width: LINKED_BOX_WIDTH,\n }}\n >\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-ring\"\n sx={{\n ...CENTRED,\n borderRadius: '50%',\n height: 36,\n width: 36,\n ...(isSwap\n ? { border: '2px solid', borderColor: 'primary.light' }\n : { bgcolor: 'primary.light' }),\n }}\n />\n <Box\n aria-hidden={true}\n data-testid=\"linked-logos-ring\"\n sx={{\n ...CENTRED,\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: '50%',\n height: 48,\n width: 48,\n }}\n />\n <Box sx={{ borderRadius: '4px', left: 0, overflow: 'hidden', position: 'absolute', top: 0 }}>\n <LogoFromGuid logo={from_logo} size={LINKED_LOGO_SIZE} />\n </Box>\n <Box\n sx={{ borderRadius: '4px', bottom: 0, overflow: 'hidden', position: 'absolute', right: 0 }}\n >\n <LogoFromGuid logo={to_logo} size={LINKED_LOGO_SIZE} />\n </Box>\n {isSwap ? <SwapBadge /> : <LinkBadge />}\n </Box>\n )\n}\n\n/**\n * ditto `category_color`: a tiny bar chart of the latest bars in place of the logo tile, tinted by\n * the slot's category, the newest bar solid (Figma 222:33404). Draws nothing without a series.\n */\nconst BarChartVisual = ({ data }: InsightVisualProps) => {\n const series = buildDataSeries(slot<DataSeries>(data, 'series'))\n if (!series.length) return null\n\n const categoryGuid = slot<string>(data, 'category_guid')\n const bars = buildChartData(series, BAR_ARIA_LABEL).slice(-BAR_CHART_BAR_COUNT)\n\n return (\n <Box data-testid=\"compact-insight-card-bar-chart\" sx={{ flexShrink: 0 }}>\n <TinyBarChart\n color={(theme) =>\n categoryGuid ? getCategoryColor(categoryGuid, theme) : theme.palette.primary.main\n }\n data={bars}\n />\n </Box>\n )\n}\n\n/**\n * The card's right-hand visual, one component per ditto layout variant.\n *\n * A variant names a rendering *shape*, not an insight or a surface — `with_header` already serves\n * both Large Transaction and Fee Detected — so an insight wanting the badged logo reuses\n * `with_warning_badge`. Only a genuinely different visual registers a new entry, and existing ones\n * are never touched.\n *\n * `minimal` draws the plain logo and is registered explicitly even though it matches the fallback:\n * micro and notification resolve it on every render, and an unregistered variant warns. The\n * fallback is for variants we genuinely do not know.\n */\nconst InsightVisual = createVariantBlock<InsightVisualProps>({\n variants: {\n category_color: BarChartVisual,\n linked_logos: LinkedLogosVisual,\n minimal: PlainVisual,\n with_illustration: IllustrationVisual,\n with_warning_badge: WarningBadgeVisual,\n },\n fallback: PlainVisual,\n name: 'InsightVisual',\n})\n\n/**\n * Beats whose embedded CTA the card reads from its own envelope key and opens in this card's\n * `ActionBlockLayer`, as a bar click does on the full card. The trigger names that key, so the layer\n * resolves the same CTA. Without a trigger the link posts its host message instead (Switch Direct\n * Deposit's op_1: Atomic runs only in pulse). Every other beat keeps `primary_cta` and hands it to\n * the host's `onCtaClick` (e.g. `contact_support_block`). A new beat adds its template here.\n */\nconst BEAT_CTA_CONFIG: Record<\n string,\n { key: 'primary_cta' | 'in_description_cta'; trigger?: ActionDrawerTrigger }\n> = {\n BillAmountNotStandard: { key: 'in_description_cta', trigger: 'inDescriptionCta' },\n ConnectDiscoveredAccountsV2: { key: 'in_description_cta', trigger: 'inDescriptionCta' },\n SwitchDirectDeposit: { key: 'in_description_cta' },\n}\n\nexport interface CompactInsightCardProps {\n /** A `micro` or `embedded` envelope. */\n payload: InsightsPayload\n /** The envelope's beat; when given, the card mounts its `ActionBlockLayer` for CTA drawers. */\n beat?: Beat\n /**\n * Makes the whole card the tap target. What a tap does is the host's decision (post to the\n * host app, open a drawer, …); the card never opens anything itself. Omit for a static card.\n */\n onTap?: () => void\n /** Receives the primary CTA when tapped. The card does not resolve the CTA's block itself. */\n onCtaClick?: (cta: PrimaryCTA) => void\n /**\n * Renders the CTA disabled — label shown, `aria-disabled`, not tappable — for a host that cannot\n * honour it (e.g. `contact_support_block` when the client's `enable_support_requests` is off).\n */\n isCtaDisabled?: boolean\n}\n\nconst stopPropagation = (event: MouseEvent) => event.stopPropagation()\n\n/**\n * The one compact renderer the micro and embedded envelopes share (`insights_v2.2.md` §8.3).\n *\n * Figma 1941:111897 (Embedded | Large Transaction): a title row with the overflow slot, the HTML\n * description with the primary CTA under it, and on the right the slot's `logo` in a\n * `<BadgedTile>`. Under ditto's `with_warning_badge` variant the tile takes a status badge; under\n * `minimal` it draws the logo alone. The card lays out from the envelope alone and never reads\n * `widget_type`.\n *\n * The icon falls back to the neutral insight glyph **here**, not in `LogoFromGuid`, when the slot\n * carries no logo. The `pill` on the same envelope is the transaction row's, not the card's.\n */\nconst CompactInsightCard = ({\n beat,\n isCtaDisabled = false,\n onCtaClick,\n onTap,\n payload,\n}: CompactInsightCardProps) => {\n const stores = useGlobalStore()\n const { openActionDrawer } = useInsightsV2Store()\n const { description, instance_slot, primary_cta, title } = payload\n const beatCta = BEAT_CTA_CONFIG[payload.template ?? '']\n const cta = beatCta ? payload[beatCta.key] : primary_cta\n const message = payload.in_description_cta?.post_message_metadata\n // A link that posts needs its beat and message; without them it draws nothing.\n const canAct = !beatCta || !!beatCta.trigger || (!!beat && !!message)\n // Reduced variants (`minimal`, `with_warning_badge`) declare a bare `logo` slot.\n const rowLogo = slot<LogoRef>(instance_slot.data, 'logo')\n\n const handleCtaClick = (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation()\n if (isCtaDisabled || !cta) return\n\n if (beatCta) {\n if (beat && beatCta.trigger) openActionDrawer({ guid: beat.guid, trigger: beatCta.trigger })\n else if (beat && message) {\n const { action, ...extras } = message\n postCtaMessage({ beat, stores }, { action, payload: extras })\n }\n return\n }\n if (primary_cta) onCtaClick?.(primary_cta)\n }\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n // Only the card itself: Enter on the CTA button is the button's own click.\n if (event.target !== event.currentTarget) return\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onTap?.()\n }\n }\n\n const interactiveProps = onTap\n ? { onClick: onTap, onKeyDown: handleKeyDown, role: 'button', tabIndex: 0 }\n : {}\n\n return (\n <>\n <Card\n data-testid=\"compact-insight-card\"\n {...interactiveProps}\n sx={{\n minWidth: 288,\n pb: 12,\n pl: 8,\n pr: 16,\n pt: 8,\n ...(onTap && { cursor: 'pointer' }),\n }}\n >\n <Stack\n sx={{\n alignItems: 'center',\n flexDirection: 'row',\n gap: 8,\n justifyContent: 'space-between',\n pl: 8,\n pt: 4,\n }}\n >\n <Text bold={true} variant=\"body1\">\n {title ?? ''}\n </Text>\n {/* The menu renders only when the host wired `onMenuAction` (BeatActionsProvider). */}\n <Box onClick={stopPropagation} sx={{ display: 'flex' }}>\n <InsightOptionsMenu />\n </Box>\n </Stack>\n\n <Stack sx={{ alignItems: 'center', flexDirection: 'row', gap: 16, pl: 8 }}>\n <Stack sx={{ alignSelf: 'stretch', flex: 1, gap: 8, minWidth: 0, pt: 2 }}>\n {/* `html_text` is rendered server-side by mrs_content from the ditto copy template (bold\n amount / merchant), not user-authored input; painted the same way `BaseLayout` paints\n the full card's description. */}\n <P\n dangerouslySetInnerHTML={{ __html: description.html_text }}\n data-testid=\"compact-insight-card-description\"\n sx={{\n display: '-webkit-box',\n fontWeight: 'fontWeightRegular',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: DESCRIPTION_MAX_LINES,\n }}\n variant=\"subtitle2\"\n />\n {cta?.label && canAct && (\n <Button\n aria-disabled={isCtaDisabled}\n onClick={handleCtaClick}\n size=\"small\"\n sx={{\n alignSelf: 'flex-start',\n // The label lines up with the description (the column pads 8; the tap target keeps\n // its padding). `my: 0` drops the theme's -12px text-button margin.\n ml: -8,\n my: 0,\n px: 8,\n ...(isCtaDisabled && {\n color: 'text.disabled',\n cursor: 'default',\n }),\n }}\n variant=\"text\"\n >\n <Text bold={true} variant=\"body2\">\n {cta.label}\n </Text>\n </Button>\n )}\n </Stack>\n\n <InsightVisual\n data={instance_slot.data}\n logo={rowLogo}\n template={payload.template}\n variant={instance_slot.variant}\n />\n </Stack>\n </Card>\n {/* Outside the Card: the drawer is a portal, and its clicks would otherwise bubble to `onTap`. */}\n {beat && <ActionBlockLayer beat={beat} />}\n </>\n )\n}\n\nexport default CompactInsightCard\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuCA,IAAM,IAAwB,GAGxB,IAAY,IAYZ,IAAmB,IACnB,KAAmB,IACnB,KAAoB,IAEpB,IAAU;AAAA,EACd,MAAM;AAAA,EACN,UAAU;AAAA,EACV,KAAK;AAAA,EACL,WAAW;AACb,GAMM,IAAA,CAAkB,EAAE,MAAA,EAAA,MACxB,IACE,gBAAA,EAAC,GAAD;AAAA,EAAoB,MAAA;AAAA,EAAM,MAAM;AAAY,CAAA,IAE5C,gBAAA,EAAC,GAAD;AAAA,EACE,eAAY;AAAA,EACZ,IAAI;AAAA,IACF,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AAAA,EAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,IAAM,OAAM;AAAA,IAAU,MAAM;AAAA,IAAM,MAAK;AAAA,IAAY,MAAM;AAAA,EAAK,CAAA;AAC3D,CAAA,GAIH,IAAA,CAAe,EAAE,MAAA,EAAA,MACrB,gBAAA,EAAC,GAAD;AAAA,EAAY,QAAQ,gBAAA,EAAC,GAAD,EAAsB,MAAA,EAAO,CAAA;AAAA,EAAG,MAAM;AAAA,EAAW,IAAI,EAAE,YAAY,EAAE;AAAI,CAAA,GAIzF,KAAA,CAAsB,EAAE,MAAA,EAAA,MAC5B,gBAAA,EAAC,GAAD;AAAA,EACE,QAAQ,gBAAA,EAAC,GAAD,EAAsB,MAAA,EAAO,CAAA;AAAA,EACrC,MAAM;AAAA,EACN,IAAI,EAAE,YAAY,EAAE;AAAA,EACpB,UAAU,gBAAA,EAAC,GAAD,EAAa,MAAK,UAAW,CAAA;AACxC,CAAA,GASG,KAAA,MAEF,gBAAA,EAAC,GAAD;AAAA,EACE,UAAU,EAAE,OAAO;AAAA,IAAE,YAAY;AAAA,IAAG,YAAY;AAAA,IAAG,OAAO;AAAA,EAAc,EAAE;AAAA,EAC1E,OAAO;AACR,CAAA,GAIC,IAAkB,IAElB,KAAA,MACJ,gBAAA,EAAC,GAAD;AAAA,EACE,eAAa;AAAA,EACb,eAAY;AAAA,EACZ,IAAI;AAAA,IACF,GAAG;AAAA,IACH,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,cAAc;AAAA,IACd,SAAS;AAAA,IACT,gBAAgB;AAAA,IAChB,GAAG;AAAA,IACH,QAAQ;AAAA,EACV;AAAA,EAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,IAAM,MAAK;AAAA,IAAO,MAAM;AAAA,IAAI,IAAI,EAAE,OAAO,uBAAuB;AAAA,EAAI,CAAA;AACjE,CAAA,GAOD,KAAA,MACJ,gBAAA,EAAC,GAAD;AAAA,EACE,eAAa;AAAA,EACb,eAAY;AAAA,EACZ,IAAI;AAAA,IACF,GAAG;AAAA,IACH,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AAAA,EAEA,UAAA,gBAAA,EAAC,GAAD;AAAA,IACE,MAAK;AAAA,IACL,MAAM,IAAkB;AAAA,IACxB,IAAI;AAAA,MAAE,OAAO;AAAA,MAAgB,YAAY;AAAA,MAAG,WAAW;AAAA,IAAiB;AAAA,EACzE,CAAA;AACE,CAAA,GAUD,KAAA,CAAqB,EAAE,MAAA,GAAM,UAAA,EAAA,MAAmC;AACpE,QAAM,EAAE,WAAA,GAAW,SAAA,EAAA,IAAa,KAAQ,CAAC,GACnC,IAAS,MAAa;AAE5B,SACE,gBAAA,EAAC,GAAD;AAAA,IACE,IAAI;AAAA,MACF,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,OAAO;AAAA,IACT;AAAA,IANF,UAAA;AAAA,MAQE,gBAAA,EAAC,GAAD;AAAA,QACE,eAAa;AAAA,QACb,eAAY;AAAA,QACZ,IAAI;AAAA,UACF,GAAG;AAAA,UACH,cAAc;AAAA,UACd,QAAQ;AAAA,UACR,OAAO;AAAA,UACP,GAAI,IACA;AAAA,YAAE,QAAQ;AAAA,YAAa,aAAa;AAAA,UAAgB,IACpD,EAAE,SAAS,gBAAgB;AAAA,QACjC;AAAA,MACD,CAAA;AAAA,MACD,gBAAA,EAAC,GAAD;AAAA,QACE,eAAa;AAAA,QACb,eAAY;AAAA,QACZ,IAAI;AAAA,UACF,GAAG;AAAA,UACH,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,cAAc;AAAA,UACd,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,MACD,CAAA;AAAA,MACD,gBAAA,EAAC,GAAD;AAAA,QAAK,IAAI;AAAA,UAAE,cAAc;AAAA,UAAO,MAAM;AAAA,UAAG,UAAU;AAAA,UAAU,UAAU;AAAA,UAAY,KAAK;AAAA,QAAE;AAAA,QACxF,UAAA,gBAAA,EAAC,GAAD;AAAA,UAAc,MAAM;AAAA,UAAW,MAAM;AAAA,QAAmB,CAAA;AAAA,MACrD,CAAA;AAAA,MACL,gBAAA,EAAC,GAAD;AAAA,QACE,IAAI;AAAA,UAAE,cAAc;AAAA,UAAO,QAAQ;AAAA,UAAG,UAAU;AAAA,UAAU,UAAU;AAAA,UAAY,OAAO;AAAA,QAAE;AAAA,QAEzF,UAAA,gBAAA,EAAC,GAAD;AAAA,UAAc,MAAM;AAAA,UAAS,MAAM;AAAA,QAAmB,CAAA;AAAA,MACnD,CAAA;AAAA,MACJ,IAAS,gBAAA,EAAC,IAAD,CAAY,CAAA,IAAI,gBAAA,EAAC,IAAD,CAAY,CAAA;AAAA,IACnC;AAAA;AAET,GAMM,KAAA,CAAkB,EAAE,MAAA,EAAA,MAA+B;AACvD,QAAM,IAAS,EAAgB,EAAiB,GAAM,QAAQ,CAAC;AAC/D,MAAI,CAAC,EAAO,OAAQ,QAAO;AAE3B,QAAM,IAAe,EAAa,GAAM,eAAe,GACjD,IAAO,EAAe,GAAQ,CAAc,EAAE,MAAM,EAAoB;AAE9E,SACE,gBAAA,EAAC,GAAD;AAAA,IAAK,eAAY;AAAA,IAAiC,IAAI,EAAE,YAAY,EAAE;AAAA,IACpE,UAAA,gBAAA,EAAC,GAAD;AAAA,MACE,OAAA,CAAQ,MACN,IAAe,EAAiB,GAAc,CAAK,IAAI,EAAM,QAAQ,QAAQ;AAAA,MAE/E,MAAM;AAAA,IACP,CAAA;AAAA,EACE,CAAA;AAET,GAcM,KAAgB,EAAuC;AAAA,EAC3D,UAAU;AAAA,IACR,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,EACtB;AAAA,EACA,UAAU;AAAA,EACV,MAAM;AACR,CAAC,GASK,KAGF;AAAA,EACF,uBAAuB;AAAA,IAAE,KAAK;AAAA,IAAsB,SAAS;AAAA,EAAmB;AAAA,EAChF,6BAA6B;AAAA,IAAE,KAAK;AAAA,IAAsB,SAAS;AAAA,EAAmB;AAAA,EACtF,qBAAqB,EAAE,KAAK,qBAAqB;AACnD,GAqBM,KAAA,CAAmB,MAAsB,EAAM,gBAAgB,GAc/D,KAAA,CAAsB,EAC1B,MAAA,GACA,eAAA,IAAgB,IAChB,YAAA,GACA,OAAA,GACA,SAAA,EAAA,MAC6B;AAC7B,QAAM,IAAS,EAAe,GACxB,EAAE,kBAAA,EAAA,IAAqB,EAAmB,GAC1C,EAAE,aAAA,GAAa,eAAA,GAAe,aAAA,GAAa,OAAA,EAAA,IAAU,GACrD,IAAU,GAAgB,EAAQ,YAAY,EAAA,GAC9C,IAAM,IAAU,EAAQ,EAAQ,GAAA,IAAO,GACvC,IAAU,EAAQ,oBAAoB,uBAEtC,IAAS,CAAC,KAAW,CAAC,CAAC,EAAQ,WAAY,CAAC,CAAC,KAAQ,CAAC,CAAC,GAEvD,IAAU,EAAc,EAAc,MAAM,MAAM,GAElD,IAAA,CAAkB,MAAyC;AAE/D,QADA,EAAM,gBAAgB,GAClB,EAAA,KAAiB,CAAC,IAEtB;AAAA,UAAI,GAAS;AACX,YAAI,KAAQ,EAAQ,QAAS,CAAA,EAAiB;AAAA,UAAE,MAAM,EAAK;AAAA,UAAM,SAAS,EAAQ;AAAA,QAAQ,CAAC;AAAA,iBAClF,KAAQ,GAAS;AACxB,gBAAM,EAAE,QAAA,GAAQ,GAAG,EAAA,IAAW;AAC9B,UAAA,EAAe;AAAA,YAAE,MAAA;AAAA,YAAM,QAAA;AAAA,UAAO,GAAG;AAAA,YAAE,QAAA;AAAA,YAAQ,SAAS;AAAA,UAAO,CAAC;AAAA,QAC9D;AACA;AAAA,MACF;AACA,MAAI,KAAa,IAAa,CAAW;AAAA;AAAA,EAC3C;AAeA,SACE,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,eAAY;AAAA,IACZ,GARmB,IACrB;AAAA,MAAE,SAAS;AAAA,MAAO,WAVhB,CAAiB,MAAyC;AAE9D,QAAI,EAAM,WAAW,EAAM,kBACvB,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,eAAe,GACrB,IAAQ;AAAA,MAEZ;AAAA,MAGgD,MAAM;AAAA,MAAU,UAAU;AAAA,IAAE,IACxE,CAAC;AAAA,IAOC,IAAI;AAAA,MACF,UAAU;AAAA,MACV,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,GAAI,KAAS,EAAE,QAAQ,UAAU;AAAA,IACnC;AAAA,IAVF,UAAA,CAYE,gBAAA,EAAC,GAAD;AAAA,MACE,IAAI;AAAA,QACF,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,KAAK;AAAA,QACL,gBAAgB;AAAA,QAChB,IAAI;AAAA,QACJ,IAAI;AAAA,MACN;AAAA,MARF,UAAA,CAUE,gBAAA,EAAC,GAAD;AAAA,QAAM,MAAM;AAAA,QAAM,SAAQ;AAAA,QACvB,UAAA,KAAS;AAAA,MACN,CAAA,GAEN,gBAAA,EAAC,GAAD;AAAA,QAAK,SAAS;AAAA,QAAiB,IAAI,EAAE,SAAS,OAAO;AAAA,QACnD,UAAA,gBAAA,EAAC,GAAD,CAAqB,CAAA;AAAA,MAClB,CAAA,CACA;AAAA,IAEP,CAAA,GAAA,gBAAA,EAAC,GAAD;AAAA,MAAO,IAAI;AAAA,QAAE,YAAY;AAAA,QAAU,eAAe;AAAA,QAAO,KAAK;AAAA,QAAI,IAAI;AAAA,MAAE;AAAA,MAAxE,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAO,IAAI;AAAA,UAAE,WAAW;AAAA,UAAW,MAAM;AAAA,UAAG,KAAK;AAAA,UAAG,UAAU;AAAA,UAAG,IAAI;AAAA,QAAE;AAAA,QAAvE,UAAA,CAIE,gBAAA,EAAC,GAAD;AAAA,UACE,yBAAyB,EAAE,QAAQ,EAAY,UAAU;AAAA,UACzD,eAAY;AAAA,UACZ,IAAI;AAAA,YACF,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,UAAU;AAAA,YACV,cAAc;AAAA,YACd,iBAAiB;AAAA,YACjB,iBAAiB;AAAA,UACnB;AAAA,UACA,SAAQ;AAAA,QACT,CAAA,GACA,GAAK,SAAS,KACb,gBAAA,EAAC,GAAD;AAAA,UACE,iBAAe;AAAA,UACf,SAAS;AAAA,UACT,MAAK;AAAA,UACL,IAAI;AAAA,YACF,WAAW;AAAA,YAGX,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,GAAI,KAAiB;AAAA,cACnB,OAAO;AAAA,cACP,QAAQ;AAAA,YACV;AAAA,UACF;AAAA,UACA,SAAQ;AAAA,UAER,UAAA,gBAAA,EAAC,GAAD;AAAA,YAAM,MAAM;AAAA,YAAM,SAAQ;AAAA,YACvB,UAAA,EAAI;AAAA,UACD,CAAA;AAAA,QACA,CAAA,CAEL;AAAA,MAEP,CAAA,GAAA,gBAAA,EAAC,IAAD;AAAA,QACE,MAAM,EAAc;AAAA,QACpB,MAAM;AAAA,QACN,UAAU,EAAQ;AAAA,QAClB,SAAS,EAAc;AAAA,MACxB,CAAA,CACI;AAAA,IACH,CAAA,CAAA;AAAA,EAEL,CAAA,GAAA,KAAQ,gBAAA,EAAC,GAAD,EAAwB,MAAA,EAAO,CAAA,CACxC,EAAA,CAAA;AAEN"}
@@ -34,7 +34,7 @@ interface TransactionListCardProps {
34
34
  background?: string;
35
35
  /** Status disc over the card's corner (needs `background`). */
36
36
  badge?: ReactNode;
37
- /** Card shadow on the wash. */
37
+ /** Card at elevation/1 on the wash; not with `raised` (its shadow wins). */
38
38
  elevated?: boolean;
39
39
  /** Border and shadow on the inner card; only with `background` (Figma Transaction Row). */
40
40
  raised?: boolean;
@@ -1,11 +1,12 @@
1
1
  import k from "./InsightTransactionRow.es.js";
2
+ import { ELEVATION_SHADOW as I } from "./shared/elevation.es.js";
2
3
  import { Fragment as T } from "react";
3
4
  import i from "@mui/material/Stack";
4
- import { Text as h } from "@mxenabled/mxui";
5
- import { Fragment as b, jsx as r, jsxs as d } from "react/jsx-runtime";
6
- import f from "@mui/material/Box";
7
- import m from "@mui/material/Divider";
8
- var I = (n) => n === "primary" ? {
5
+ import { Text as m } from "@mxenabled/mxui";
6
+ import { Fragment as f, jsx as r, jsxs as a } from "react/jsx-runtime";
7
+ import g from "@mui/material/Box";
8
+ import u from "@mui/material/Divider";
9
+ var S = (n) => n === "primary" ? {
9
10
  radius: "8px",
10
11
  borderColor: "primary.main",
11
12
  headerBg: "primary.main",
@@ -29,21 +30,21 @@ var I = (n) => n === "primary" ? {
29
30
  px: 16,
30
31
  py: 2
31
32
  }
32
- }, V = ({ background: n, badge: c, elevated: g = !1, footer: l, header: a, raised: B = !1, rows: u, variant: y = "default", sx: C }) => {
33
- if (u.length === 0) return null;
34
- const e = I(y), o = !!n, t = o ? "8px" : e.radius, s = !!a && !o && e.headerInsideBorder, p = a ? /* @__PURE__ */ r(i, {
33
+ }, V = ({ background: n, badge: c, elevated: B = !1, footer: l, header: d, raised: y = !1, rows: x, variant: v = "default", sx: C }) => {
34
+ if (x.length === 0) return null;
35
+ const e = S(v), o = !!n, t = o ? "8px" : e.radius, s = !!d && !o && e.headerInsideBorder, p = d ? /* @__PURE__ */ r(i, {
35
36
  sx: {
36
37
  bgcolor: e.headerBg,
37
38
  justifyContent: "center",
38
39
  ...e.headerSx
39
40
  },
40
- children: /* @__PURE__ */ r(h, {
41
+ children: /* @__PURE__ */ r(m, {
41
42
  bold: e.headerBold,
42
43
  color: e.headerColor,
43
44
  variant: "caption",
44
- children: a
45
+ children: d
45
46
  })
46
- }) : null, v = l ? /* @__PURE__ */ d(b, { children: [/* @__PURE__ */ r(m, {}), /* @__PURE__ */ d(i, {
47
+ }) : null, w = l ? /* @__PURE__ */ a(f, { children: [/* @__PURE__ */ r(u, {}), /* @__PURE__ */ a(i, {
47
48
  sx: {
48
49
  alignItems: "center",
49
50
  bgcolor: o ? "background.paper" : "background.default",
@@ -53,25 +54,25 @@ var I = (n) => n === "primary" ? {
53
54
  px: 16,
54
55
  py: 2
55
56
  },
56
- children: [/* @__PURE__ */ r(h, {
57
+ children: [/* @__PURE__ */ r(m, {
57
58
  color: "text.secondary",
58
59
  variant: "caption",
59
60
  children: l.label
60
- }), /* @__PURE__ */ r(h, {
61
+ }), /* @__PURE__ */ r(m, {
61
62
  bold: !0,
62
63
  color: l.amountColor ?? "text.primary",
63
64
  variant: "body2",
64
65
  children: l.amount
65
66
  })]
66
- })] }) : null, w = /* @__PURE__ */ r(i, {
67
+ })] }) : null, R = /* @__PURE__ */ r(i, {
67
68
  role: "list",
68
69
  sx: { width: "100%" },
69
- children: u.map((R, x) => /* @__PURE__ */ d(T, { children: [x > 0 && /* @__PURE__ */ r(m, { role: "presentation" }), /* @__PURE__ */ r(f, {
70
+ children: x.map((h, b) => /* @__PURE__ */ a(T, { children: [b > 0 && /* @__PURE__ */ r(u, { role: "presentation" }), /* @__PURE__ */ r(g, {
70
71
  role: "listitem",
71
- children: /* @__PURE__ */ r(k, { ...R })
72
- })] }, x))
72
+ children: /* @__PURE__ */ r(k, { ...h })
73
+ })] }, b))
73
74
  });
74
- return /* @__PURE__ */ d(i, {
75
+ return /* @__PURE__ */ a(i, {
75
76
  "data-testid": "transaction-list-card",
76
77
  sx: {
77
78
  ...o ? {
@@ -86,7 +87,7 @@ var I = (n) => n === "primary" ? {
86
87
  ...C
87
88
  },
88
89
  children: [
89
- o && c && /* @__PURE__ */ r(f, {
90
+ o && c && /* @__PURE__ */ r(g, {
90
91
  sx: {
91
92
  left: 16,
92
93
  position: "absolute",
@@ -103,12 +104,15 @@ var I = (n) => n === "primary" ? {
103
104
  },
104
105
  children: p
105
106
  }),
106
- /* @__PURE__ */ d(i, {
107
+ /* @__PURE__ */ a(i, {
107
108
  sx: {
108
109
  ...o ? {
109
110
  bgcolor: "background.paper",
110
- ...g && { boxShadow: "0px 2px 8px rgba(0, 0, 0, 0.12)" },
111
111
  ...B && {
112
+ backgroundImage: (h) => h.vars?.overlays?.[1] ?? "none",
113
+ boxShadow: I[1]
114
+ },
115
+ ...y && {
112
116
  border: "1px solid",
113
117
  borderColor: "divider",
114
118
  boxShadow: 1
@@ -119,15 +123,15 @@ var I = (n) => n === "primary" ? {
119
123
  },
120
124
  borderBottomLeftRadius: t,
121
125
  borderBottomRightRadius: t,
122
- borderTopLeftRadius: s || !a ? t : 0,
123
- borderTopRightRadius: s || !a ? t : 0,
126
+ borderTopLeftRadius: s || !d ? t : 0,
127
+ borderTopRightRadius: s || !d ? t : 0,
124
128
  overflow: "hidden",
125
129
  width: "100%"
126
130
  },
127
131
  children: [
128
- s && /* @__PURE__ */ d(b, { children: [p, /* @__PURE__ */ r(m, {})] }),
129
- w,
130
- v
132
+ s && /* @__PURE__ */ a(f, { children: [p, /* @__PURE__ */ r(u, {})] }),
133
+ R,
134
+ w
131
135
  ]
132
136
  })
133
137
  ]
@@ -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), unless `raised`.\n */\n background?: string\n /** Status disc over the card's corner (needs `background`). */\n badge?: ReactNode\n /** Card shadow on the wash. */\n elevated?: boolean\n /** Border and shadow on the inner card; only with `background` (Figma Transaction Row). */\n raised?: boolean\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 badge,\n elevated = false,\n footer,\n header,\n raised = false,\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 ...(hasBackground && badge ? { position: 'relative' } : {}),\n width: '100%',\n ...sx,\n }}\n >\n {hasBackground &&\n badge && (\n // Centred on the card's top-left corner.\n <Box sx={{ left: 16, position: 'absolute', top: 12, zIndex: 1 }}>{badge}</Box>\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 ? {\n bgcolor: 'background.paper',\n ...(elevated && { boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.12)' }),\n ...(raised && { border: '1px solid', borderColor: 'divider', boxShadow: 1 }),\n }\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, Theme } from '@mui/material/styles'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport InsightTransactionRow, { type InsightTransactionRowProps } from './InsightTransactionRow'\nimport { ELEVATION_SHADOW } from './shared/elevation'\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), unless `raised`.\n */\n background?: string\n /** Status disc over the card's corner (needs `background`). */\n badge?: ReactNode\n /** Card at elevation/1 on the wash; not with `raised` (its shadow wins). */\n elevated?: boolean\n /** Border and shadow on the inner card; only with `background` (Figma Transaction Row). */\n raised?: boolean\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 badge,\n elevated = false,\n footer,\n header,\n raised = false,\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 ...(hasBackground && badge ? { position: 'relative' } : {}),\n width: '100%',\n ...sx,\n }}\n >\n {hasBackground &&\n badge && (\n // Centred on the card's top-left corner.\n <Box sx={{ left: 16, position: 'absolute', top: 12, zIndex: 1 }}>{badge}</Box>\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 ? {\n bgcolor: 'background.paper',\n // elevation/1 shadow plus the dark-mode tint.\n ...(elevated && {\n backgroundImage: (theme: Theme) => theme.vars?.overlays?.[1] ?? 'none',\n boxShadow: ELEVATION_SHADOW[1],\n }),\n ...(raised && { border: '1px solid', borderColor: 'divider', boxShadow: 1 }),\n }\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,7 +1,11 @@
1
+ /** `standard`: the mxui Toast; `strong`: Figma's `<Snackbar>` (600 tone, white text, elevation/16). */
2
+ export type StatusSnackbarVariant = 'standard' | 'strong';
1
3
  export interface StatusSnackbarProps {
2
4
  open: boolean;
3
5
  /** Snackbar tone — success (green, Figma 1941:167636) or error (red, Figma 1941:167637). */
4
6
  severity?: 'success' | 'error';
7
+ /** Snackbar design; defaults to `standard`. */
8
+ variant?: StatusSnackbarVariant;
5
9
  /** Status description, e.g. "Your feedback has been submitted.". */
6
10
  message: string;
7
11
  /** ARIA label for the close button. */
@@ -24,5 +28,5 @@ export interface StatusSnackbarProps {
24
28
  * so every surface renders the same Figma variants instead of re-wiring
25
29
  * Toast props.
26
30
  */
27
- declare const StatusSnackbar: ({ actionText, autoHideDuration, closeAriaLabel, message, onActionClick, onClose, open, severity, }: StatusSnackbarProps) => import("react/jsx-runtime").JSX.Element;
31
+ declare const StatusSnackbar: ({ actionText, autoHideDuration, closeAriaLabel, message, onActionClick, onClose, open, severity, variant, }: StatusSnackbarProps) => import("react/jsx-runtime").JSX.Element;
28
32
  export default StatusSnackbar;
@@ -1,19 +1,39 @@
1
+ import { ELEVATION_SHADOW as c } from "./elevation.es.js";
1
2
  import { Toast as u } from "@mxenabled/mxui";
2
- import { jsx as c } from "react/jsx-runtime";
3
- var p = ({ actionText: s, autoHideDuration: o, closeAriaLabel: r, message: a, onActionClick: t, onClose: e, open: l, severity: m = "success" }) => /* @__PURE__ */ c(u, {
4
- actionText: s,
5
- autoHideDuration: o,
6
- closeAriaLabel: r,
7
- handleClose: e,
3
+ import { jsx as m } from "react/jsx-runtime";
4
+ var p = (o) => ({
5
+ "& .MuiAlert-root": {
6
+ backgroundColor: (t) => t.palette[o][600] ?? t.palette[o].dark,
7
+ boxShadow: c[16],
8
+ color: "common.white"
9
+ },
10
+ "& .MuiAlert-icon, & .MuiAlert-action .MuiIconButton-root": { color: "common.white" },
11
+ "& .MuiAlert-action": {
12
+ mr: 0,
13
+ pl: 20
14
+ },
15
+ "& .MuiAlert-message p": { lineHeight: "24px" },
16
+ "& .MuiAlert-message .MuiButton-root": {
17
+ color: "common.white",
18
+ fontSize: 15,
19
+ fontWeight: 600,
20
+ lineHeight: "20px"
21
+ }
22
+ }), M = ({ actionText: o, autoHideDuration: t, closeAriaLabel: e, message: a, onActionClick: i, onClose: n, open: l, severity: r = "success", variant: s = "standard" }) => /* @__PURE__ */ m(u, {
23
+ actionText: o,
24
+ autoHideDuration: t,
25
+ closeAriaLabel: e,
26
+ handleClose: n,
8
27
  message: a,
9
- onActionClick: t,
28
+ onActionClick: i,
10
29
  open: l,
11
- severity: m,
12
- showAction: !!s,
13
- showClose: !0
30
+ severity: r,
31
+ showAction: !!o,
32
+ showClose: !0,
33
+ ...s === "strong" && { snackbarSx: p(r) }
14
34
  });
15
35
  export {
16
- p as default
36
+ M as default
17
37
  };
18
38
 
19
39
  //# sourceMappingURL=StatusSnackbar.es.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusSnackbar.es.js","names":[],"sources":["../../../../src/insights-v2/components/shared/StatusSnackbar.tsx"],"sourcesContent":["import { Toast } from '@mxenabled/mxui'\n\nexport interface StatusSnackbarProps {\n open: boolean\n /** Snackbar tone — success (green, Figma 1941:167636) or error (red, Figma 1941:167637). */\n severity?: 'success' | 'error'\n /** Status description, e.g. \"Your feedback has been submitted.\". */\n message: string\n /** ARIA label for the close button. */\n closeAriaLabel: string\n /** Fired on close / auto-hide. */\n onClose: () => void\n /**\n * Optional action button label (e.g. \"Try Again\"). The button renders only\n * when this is provided.\n */\n actionText?: string\n onActionClick?: () => void\n /** Auto-hide in ms; defaults to the mxui Toast default (3s). */\n autoHideDuration?: number\n}\n\n/**\n * Shared status snackbar for insights-v2 (Figma `<Snackbar>`): a filled\n * success/error toast with a message, a close button, and an optional action\n * (e.g. the feedback modal's Try Again). Thin wrapper over the mxui `Toast`\n * so every surface renders the same Figma variants instead of re-wiring\n * Toast props.\n */\nconst StatusSnackbar = ({\n actionText,\n autoHideDuration,\n closeAriaLabel,\n message,\n onActionClick,\n onClose,\n open,\n severity = 'success',\n}: StatusSnackbarProps) => (\n <Toast\n actionText={actionText}\n autoHideDuration={autoHideDuration}\n closeAriaLabel={closeAriaLabel}\n handleClose={onClose}\n message={message}\n onActionClick={onActionClick}\n open={open}\n severity={severity}\n showAction={!!actionText}\n showClose={true}\n />\n)\n\nexport default StatusSnackbar\n"],"mappings":";;AA6BA,IAAM,IAAA,CAAkB,EACtB,YAAA,GACA,kBAAA,GACA,gBAAA,GACA,SAAA,GACA,eAAA,GACA,SAAA,GACA,MAAA,GACA,UAAA,IAAW,UAAA,MAEX,gBAAA,EAAC,GAAD;AAAA,EACc,YAAA;AAAA,EACM,kBAAA;AAAA,EACF,gBAAA;AAAA,EAChB,aAAa;AAAA,EACJ,SAAA;AAAA,EACM,eAAA;AAAA,EACT,MAAA;AAAA,EACI,UAAA;AAAA,EACV,YAAY,CAAC,CAAC;AAAA,EACd,WAAW;AACZ,CAAA"}
1
+ {"version":3,"file":"StatusSnackbar.es.js","names":[],"sources":["../../../../src/insights-v2/components/shared/StatusSnackbar.tsx"],"sourcesContent":["import type { SxProps, Theme } from '@mui/material/styles'\n\nimport { Toast } from '@mxenabled/mxui'\n\nimport { ELEVATION_SHADOW } from './elevation'\n\n/** `standard`: the mxui Toast; `strong`: Figma's `<Snackbar>` (600 tone, white text, elevation/16). */\nexport type StatusSnackbarVariant = 'standard' | 'strong'\n\nexport interface StatusSnackbarProps {\n open: boolean\n /** Snackbar tone — success (green, Figma 1941:167636) or error (red, Figma 1941:167637). */\n severity?: 'success' | 'error'\n /** Snackbar design; defaults to `standard`. */\n variant?: StatusSnackbarVariant\n /** Status description, e.g. \"Your feedback has been submitted.\". */\n message: string\n /** ARIA label for the close button. */\n closeAriaLabel: string\n /** Fired on close / auto-hide. */\n onClose: () => void\n /**\n * Optional action button label (e.g. \"Try Again\"). The button renders only\n * when this is provided.\n */\n actionText?: string\n onActionClick?: () => void\n /** Auto-hide in ms; defaults to the mxui Toast default (3s). */\n autoHideDuration?: number\n}\n\nconst strongSx = (severity: 'success' | 'error'): SxProps<Theme> => ({\n '& .MuiAlert-root': {\n backgroundColor: (theme: Theme) => theme.palette[severity][600] ?? theme.palette[severity].dark,\n boxShadow: ELEVATION_SHADOW[16],\n color: 'common.white',\n },\n '& .MuiAlert-icon, & .MuiAlert-action .MuiIconButton-root': { color: 'common.white' },\n // Figma close frame: 20px gap, 16px edge (the button keeps mxui's 44px target).\n '& .MuiAlert-action': { mr: 0, pl: 20 },\n '& .MuiAlert-message p': { lineHeight: '24px' },\n '& .MuiAlert-message .MuiButton-root': {\n color: 'common.white',\n fontSize: 15,\n fontWeight: 600,\n lineHeight: '20px',\n },\n})\n\n/**\n * Shared status snackbar for insights-v2 (Figma `<Snackbar>`): a filled\n * success/error toast with a message, a close button, and an optional action\n * (e.g. the feedback modal's Try Again). Thin wrapper over the mxui `Toast`\n * so every surface renders the same Figma variants instead of re-wiring\n * Toast props.\n */\nconst StatusSnackbar = ({\n actionText,\n autoHideDuration,\n closeAriaLabel,\n message,\n onActionClick,\n onClose,\n open,\n severity = 'success',\n variant = 'standard',\n}: StatusSnackbarProps) => (\n <Toast\n actionText={actionText}\n autoHideDuration={autoHideDuration}\n closeAriaLabel={closeAriaLabel}\n handleClose={onClose}\n message={message}\n onActionClick={onActionClick}\n open={open}\n severity={severity}\n showAction={!!actionText}\n showClose={true}\n {...(variant === 'strong' && { snackbarSx: strongSx(severity) })}\n />\n)\n\nexport default StatusSnackbar\n"],"mappings":";;;AA+BA,IAAM,IAAA,CAAY,OAAmD;AAAA,EACnE,oBAAoB;AAAA,IAClB,iBAAA,CAAkB,MAAiB,EAAM,QAAQ,CAAA,EAAU,GAAA,KAAQ,EAAM,QAAQ,CAAA,EAAU;AAAA,IAC3F,WAAW,EAAiB,EAAA;AAAA,IAC5B,OAAO;AAAA,EACT;AAAA,EACA,4DAA4D,EAAE,OAAO,eAAe;AAAA,EAEpF,sBAAsB;AAAA,IAAE,IAAI;AAAA,IAAG,IAAI;AAAA,EAAG;AAAA,EACtC,yBAAyB,EAAE,YAAY,OAAO;AAAA,EAC9C,uCAAuC;AAAA,IACrC,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACF,IASM,IAAA,CAAkB,EACtB,YAAA,GACA,kBAAA,GACA,gBAAA,GACA,SAAA,GACA,eAAA,GACA,SAAA,GACA,MAAA,GACA,UAAA,IAAW,WACX,SAAA,IAAU,WAAA,MAEV,gBAAA,EAAC,GAAD;AAAA,EACc,YAAA;AAAA,EACM,kBAAA;AAAA,EACF,gBAAA;AAAA,EAChB,aAAa;AAAA,EACJ,SAAA;AAAA,EACM,eAAA;AAAA,EACT,MAAA;AAAA,EACI,UAAA;AAAA,EACV,YAAY,CAAC,CAAC;AAAA,EACd,WAAW;AAAA,EACX,GAAK,MAAY,YAAY,EAAE,YAAY,EAAS,CAAQ,EAAE;AAC/D,CAAA"}
@@ -0,0 +1,7 @@
1
+ /** Figma elevation shadows (single drop shadows, not MUI's `shadows[n]`). */
2
+ export declare const ELEVATION_SHADOW: {
3
+ /** `elevation/1`: rows on a wash. */
4
+ readonly 1: "0px 2px 8px rgba(0, 0, 0, 0.12)";
5
+ /** `elevation/16`: dialogs, snackbars. */
6
+ readonly 16: "0px 12px 20px rgba(0, 0, 0, 0.22)";
7
+ };
@@ -0,0 +1,9 @@
1
+ var p = {
2
+ 1: "0px 2px 8px rgba(0, 0, 0, 0.12)",
3
+ 16: "0px 12px 20px rgba(0, 0, 0, 0.22)"
4
+ };
5
+ export {
6
+ p as ELEVATION_SHADOW
7
+ };
8
+
9
+ //# sourceMappingURL=elevation.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevation.es.js","names":[],"sources":["../../../../src/insights-v2/components/shared/elevation.ts"],"sourcesContent":["/** Figma elevation shadows (single drop shadows, not MUI's `shadows[n]`). */\nexport const ELEVATION_SHADOW = {\n /** `elevation/1`: rows on a wash. */\n 1: '0px 2px 8px rgba(0, 0, 0, 0.12)',\n /** `elevation/16`: dialogs, snackbars. */\n 16: '0px 12px 20px rgba(0, 0, 0, 0.22)',\n} as const\n"],"mappings":"AACA,IAAa,IAAmB;AAAA,EAE9B,GAAG;AAAA,EAEH,IAAI;AACN"}
@@ -1,12 +1,12 @@
1
1
  import { ANALYTICS_EVENTS_CONFIG as o } from "../analytics/analyticsEventsConfig.es.js";
2
2
  import { CTA_STATUS_CONTENT_CLASS as r } from "../components/CtaStatus.es.js";
3
3
  import { HOST_ACTIONS as a } from "./hostActions.es.js";
4
- import { subscriptionEntryStep as n, subscriptionSurvey as _ } from "./subscriptionAnswer.es.js";
4
+ import { subscriptionEntryStep as n, subscriptionSurvey as p } from "./subscriptionAnswer.es.js";
5
5
  import { alpha as c } from "@mui/material/styles";
6
- var u = ({ beat: t, stores: i }) => {
7
- const e = i.insightsV2Store.beatContext[t.guid]?.selected_account_guid;
6
+ var u = ({ beat: t, stores: s }) => {
7
+ const e = s.insightsV2Store.beatContext[t.guid]?.selected_account_guid;
8
8
  if (typeof e == "string")
9
- return i.accountStore.visibleSavingsAccounts.some((s) => s.guid === e && !s.is_closed && !s.is_deleted) ? e : void 0;
9
+ return s.accountStore.visibleSavingsAccounts.some((i) => i.guid === e && !i.is_closed && !i.is_deleted) ? e : void 0;
10
10
  }, S = {
11
11
  dismiss_beat: {
12
12
  run: "delegateToHost",
@@ -29,7 +29,7 @@ var u = ({ beat: t, stores: i }) => {
29
29
  positive: "confirmed",
30
30
  negative: "incorrect"
31
31
  } }),
32
- surveyAnswer: _
32
+ surveyAnswer: p
33
33
  },
34
34
  confirm_subscription_status: {
35
35
  ...n({
@@ -39,12 +39,20 @@ var u = ({ beat: t, stores: i }) => {
39
39
  },
40
40
  sx: {
41
41
  minHeight: 56,
42
- [`& .${r}`]: { gap: 10 }
42
+ [`& .${r}`]: { gap: 10 },
43
+ "& > .MuiButton-root": {
44
+ fontSize: 13,
45
+ fontWeight: 600,
46
+ lineHeight: "16px",
47
+ minWidth: 0,
48
+ px: 8,
49
+ py: 4
50
+ }
43
51
  },
44
52
  negativeSx: {
45
53
  bgcolor: "background.paper",
46
- borderColor: (t) => c(t.palette.common.black, 0.5),
47
- [`& .${r} .MuiSvgIcon-root`]: { color: (t) => c(t.palette.common.black, 0.7) }
54
+ borderColor: (t) => c(t.palette.text.primary, 0.5),
55
+ [`& .${r} .MuiSvgIcon-root`]: { color: (t) => c(t.palette.text.primary, 0.7) }
48
56
  },
49
57
  answeredTitle: (t) => t.insights_feed?.subscription_status_modal?.reviewed_title
50
58
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"ctaConfig.es.js","names":[],"sources":["../../../src/insights-v2/ctaActions/ctaConfig.ts"],"sourcesContent":["import { alpha, type Theme } from '@mui/material/styles'\n\nimport { ANALYTICS_EVENTS_CONFIG } from '../analytics/analyticsEventsConfig'\nimport { CTA_STATUS_CONTENT_CLASS } from '../components/CtaStatus'\nimport { HOST_ACTIONS } from './hostActions'\nimport { subscriptionEntryStep, subscriptionSurvey } from './subscriptionAnswer'\nimport type { CtaStateContext, CtaStep } from './types'\n\n/**\n * The account the svg_image_block picker wrote into this beat's context, and only while it is\n * still one the user can save into (visible, open, not deleted) — a pick that went stale between\n * pick and Save never reaches the API.\n */\nconst pickedSavingsAccountGuid = ({ beat, stores }: Pick<CtaStateContext, 'beat' | 'stores'>) => {\n const picked = stores.insightsV2Store.beatContext[beat.guid]?.selected_account_guid\n\n if (typeof picked !== 'string') return undefined\n\n const usable = stores.accountStore.visibleSavingsAccounts.some(\n (account) => account.guid === picked && !account.is_closed && !account.is_deleted,\n )\n\n return usable ? picked : undefined\n}\n\n/**\n * Steps keyed by the backend-named `cta.action_key` (ditto `*_cta_action`, via tupac). No key or\n * an unknown key = default: open the CTA's block drawer, if any. Its post message, when one\n * resolves (`cta.metadata` / `ctaPostMessages`), is sent either way. A new key is registered in\n * ditto and here in the same change; most CTAs need none. See README.md.\n */\nexport const ctaActions: Record<string, CtaStep> = {\n /** ConnectDiscoveredAccounts \"I don't have any\": dismiss through the host, then stop. */\n dismiss_beat: {\n run: 'delegateToHost',\n params: { hostAction: HOST_ACTIONS.dismissBeat },\n },\n\n /**\n * Designate Emergency Savings Account \"Save\": designates the account picked in the\n * svg_image_block picker (kept in the per-beat context), then refreshes the beat. The beat is\n * sampled, so the refresh re-reads its sample, which the backend rebuilds as the saved card\n * (change_account: \"Account Saved!\", no CTA). Disabled until a pick is made.\n */\n select_savings_account: {\n run: 'updateUserInsightProfile',\n params: (ctx) => ({\n fields: { emergency_savings_account_guid: pickedSavingsAccountGuid(ctx) },\n }),\n disabledWhen: (ctx) => !pickedSavingsAccountGuid(ctx),\n onSuccess: ['refreshBeat'],\n analytics: ANALYTICS_EVENTS_CONFIG.EMERGENCY_SAVINGS_ACCT_SAVED,\n },\n\n /**\n * Designate Emergency Savings Account \"Open a Savings Account\": no handler. The op_1 post\n * message comes from `ctaPostMessages`; this step adds the Created event.\n */\n open_savings_account: {\n analytics: ANALYTICS_EVENTS_CONFIG.EMERGENCY_SAVINGS_ACCT_CREATED,\n },\n\n /**\n * SetUpDirectDeposit `not_set_up`: hand the press to the host, which owns the Atomic SDK and its\n * lifecycle. No drawer, no `refreshBeat`, and no interim post message is registered for the\n * template (a backend-supplied `cta.metadata` would still post).\n */\n atomic_flow: {\n run: 'delegateToHost',\n params: { hostAction: HOST_ACTIONS.atomicTransact },\n },\n\n /**\n * SubscriptionDetected \"Does this look right?\": the shared subscription status CTA (every answer\n * counts, as pulse), answered through the survey.\n */\n confirm_subscription_detected: {\n ...subscriptionEntryStep({ statusLabels: { positive: 'confirmed', negative: 'incorrect' } }),\n surveyAnswer: subscriptionSurvey,\n },\n\n /**\n * Unexpected Subscription Payment: the shared subscription status CTA, answered through its\n * Subscription Status modal. Its Figma: a 56px bar, and a white \"Not subscribed\" bar with a 50%\n * black border and 70% black icon. Mini and micro mirror the status (`compactStatus`).\n */\n confirm_subscription_status: {\n ...subscriptionEntryStep({\n statusLabels: { positive: 'subscribed', negative: 'not_subscribed' },\n sx: { minHeight: 56, [`& .${CTA_STATUS_CONTENT_CLASS}`]: { gap: 10 } },\n negativeSx: {\n bgcolor: 'background.paper',\n borderColor: (theme: Theme) => alpha(theme.palette.common.black, 0.5),\n [`& .${CTA_STATUS_CONTENT_CLASS} .MuiSvgIcon-root`]: {\n color: (theme: Theme) => alpha(theme.palette.common.black, 0.7),\n },\n },\n answeredTitle: (copy) => copy.insights_feed?.subscription_status_modal?.reviewed_title,\n }),\n compactStatus: true,\n },\n}\n"],"mappings":";;;;;AAaA,IAAM,IAAA,CAA4B,EAAE,MAAA,GAAM,QAAA,EAAA,MAAuD;AAC/F,QAAM,IAAS,EAAO,gBAAgB,YAAY,EAAK,IAAA,GAAO;AAE9D,MAAI,OAAO,KAAW;AAMtB,WAJe,EAAO,aAAa,uBAAuB,KAAA,CACvD,MAAY,EAAQ,SAAS,KAAU,CAAC,EAAQ,aAAa,CAAC,EAAQ,UAGlE,IAAS,IAAS;AAC3B,GAQa,IAAsC;AAAA,EAEjD,cAAc;AAAA,IACZ,KAAK;AAAA,IACL,QAAQ,EAAE,YAAY,EAAa,YAAY;AAAA,EACjD;AAAA,EAQA,wBAAwB;AAAA,IACtB,KAAK;AAAA,IACL,QAAA,CAAS,OAAS,EAChB,QAAQ,EAAE,gCAAgC,EAAyB,CAAG,EAAE,EAC1E;AAAA,IACA,cAAA,CAAe,MAAQ,CAAC,EAAyB,CAAG;AAAA,IACpD,WAAW,CAAC,aAAa;AAAA,IACzB,WAAW,EAAwB;AAAA,EACrC;AAAA,EAMA,sBAAsB,EACpB,WAAW,EAAwB,+BACrC;AAAA,EAOA,aAAa;AAAA,IACX,KAAK;AAAA,IACL,QAAQ,EAAE,YAAY,EAAa,eAAe;AAAA,EACpD;AAAA,EAMA,+BAA+B;AAAA,IAC7B,GAAG,EAAsB,EAAE,cAAc;AAAA,MAAE,UAAU;AAAA,MAAa,UAAU;AAAA,IAAY,EAAE,CAAC;AAAA,IAC3F,cAAc;AAAA,EAChB;AAAA,EAOA,6BAA6B;AAAA,IAC3B,GAAG,EAAsB;AAAA,MACvB,cAAc;AAAA,QAAE,UAAU;AAAA,QAAc,UAAU;AAAA,MAAiB;AAAA,MACnE,IAAI;AAAA,QAAE,WAAW;AAAA,QAAK,CAAA,MAAM,CAAA,EAAA,GAA6B,EAAE,KAAK,GAAG;AAAA,MAAE;AAAA,MACrE,YAAY;AAAA,QACV,SAAS;AAAA,QACT,aAAA,CAAc,MAAiB,EAAM,EAAM,QAAQ,OAAO,OAAO,GAAG;AAAA,QACnE,CAAA,MAAM,CAAA,mBAAyB,GAAqB,EACnD,OAAA,CAAQ,MAAiB,EAAM,EAAM,QAAQ,OAAO,OAAO,GAAG,EAChE;AAAA,MACF;AAAA,MACA,eAAA,CAAgB,MAAS,EAAK,eAAe,2BAA2B;AAAA,IAC1E,CAAC;AAAA,IACD,eAAe;AAAA,EACjB;AACF"}
1
+ {"version":3,"file":"ctaConfig.es.js","names":[],"sources":["../../../src/insights-v2/ctaActions/ctaConfig.ts"],"sourcesContent":["import { alpha, type Theme } from '@mui/material/styles'\n\nimport { ANALYTICS_EVENTS_CONFIG } from '../analytics/analyticsEventsConfig'\nimport { CTA_STATUS_CONTENT_CLASS } from '../components/CtaStatus'\nimport { HOST_ACTIONS } from './hostActions'\nimport { subscriptionEntryStep, subscriptionSurvey } from './subscriptionAnswer'\nimport type { CtaStateContext, CtaStep } from './types'\n\n/**\n * The account the svg_image_block picker wrote into this beat's context, and only while it is\n * still one the user can save into (visible, open, not deleted) — a pick that went stale between\n * pick and Save never reaches the API.\n */\nconst pickedSavingsAccountGuid = ({ beat, stores }: Pick<CtaStateContext, 'beat' | 'stores'>) => {\n const picked = stores.insightsV2Store.beatContext[beat.guid]?.selected_account_guid\n\n if (typeof picked !== 'string') return undefined\n\n const usable = stores.accountStore.visibleSavingsAccounts.some(\n (account) => account.guid === picked && !account.is_closed && !account.is_deleted,\n )\n\n return usable ? picked : undefined\n}\n\n/**\n * Steps keyed by the backend-named `cta.action_key` (ditto `*_cta_action`, via tupac). No key or\n * an unknown key = default: open the CTA's block drawer, if any. Its post message, when one\n * resolves (`cta.metadata` / `ctaPostMessages`), is sent either way. A new key is registered in\n * ditto and here in the same change; most CTAs need none. See README.md.\n */\nexport const ctaActions: Record<string, CtaStep> = {\n /** ConnectDiscoveredAccounts \"I don't have any\": dismiss through the host, then stop. */\n dismiss_beat: {\n run: 'delegateToHost',\n params: { hostAction: HOST_ACTIONS.dismissBeat },\n },\n\n /**\n * Designate Emergency Savings Account \"Save\": designates the account picked in the\n * svg_image_block picker (kept in the per-beat context), then refreshes the beat. The beat is\n * sampled, so the refresh re-reads its sample, which the backend rebuilds as the saved card\n * (change_account: \"Account Saved!\", no CTA). Disabled until a pick is made.\n */\n select_savings_account: {\n run: 'updateUserInsightProfile',\n params: (ctx) => ({\n fields: { emergency_savings_account_guid: pickedSavingsAccountGuid(ctx) },\n }),\n disabledWhen: (ctx) => !pickedSavingsAccountGuid(ctx),\n onSuccess: ['refreshBeat'],\n analytics: ANALYTICS_EVENTS_CONFIG.EMERGENCY_SAVINGS_ACCT_SAVED,\n },\n\n /**\n * Designate Emergency Savings Account \"Open a Savings Account\": no handler. The op_1 post\n * message comes from `ctaPostMessages`; this step adds the Created event.\n */\n open_savings_account: {\n analytics: ANALYTICS_EVENTS_CONFIG.EMERGENCY_SAVINGS_ACCT_CREATED,\n },\n\n /**\n * SetUpDirectDeposit `not_set_up`: hand the press to the host, which owns the Atomic SDK and its\n * lifecycle. No drawer, no `refreshBeat`, and no interim post message is registered for the\n * template (a backend-supplied `cta.metadata` would still post).\n */\n atomic_flow: {\n run: 'delegateToHost',\n params: { hostAction: HOST_ACTIONS.atomicTransact },\n },\n\n /**\n * SubscriptionDetected \"Does this look right?\": the shared subscription status CTA (every answer\n * counts, as pulse), answered through the survey.\n */\n confirm_subscription_detected: {\n ...subscriptionEntryStep({ statusLabels: { positive: 'confirmed', negative: 'incorrect' } }),\n surveyAnswer: subscriptionSurvey,\n },\n\n /** Unexpected Subscription Payment: Figma's status bar; mini and micro mirror it (`compactStatus`). */\n confirm_subscription_status: {\n ...subscriptionEntryStep({\n statusLabels: { positive: 'subscribed', negative: 'not_subscribed' },\n sx: {\n minHeight: 56,\n [`& .${CTA_STATUS_CONTENT_CLASS}`]: { gap: 10 },\n '& > .MuiButton-root': {\n fontSize: 13,\n fontWeight: 600,\n lineHeight: '16px',\n minWidth: 0,\n px: 8,\n py: 4,\n },\n },\n negativeSx: {\n bgcolor: 'background.paper',\n borderColor: (theme: Theme) => alpha(theme.palette.text.primary, 0.5),\n [`& .${CTA_STATUS_CONTENT_CLASS} .MuiSvgIcon-root`]: {\n color: (theme: Theme) => alpha(theme.palette.text.primary, 0.7),\n },\n },\n answeredTitle: (copy) => copy.insights_feed?.subscription_status_modal?.reviewed_title,\n }),\n compactStatus: true,\n },\n}\n"],"mappings":";;;;;AAaA,IAAM,IAAA,CAA4B,EAAE,MAAA,GAAM,QAAA,EAAA,MAAuD;AAC/F,QAAM,IAAS,EAAO,gBAAgB,YAAY,EAAK,IAAA,GAAO;AAE9D,MAAI,OAAO,KAAW;AAMtB,WAJe,EAAO,aAAa,uBAAuB,KAAA,CACvD,MAAY,EAAQ,SAAS,KAAU,CAAC,EAAQ,aAAa,CAAC,EAAQ,UAGlE,IAAS,IAAS;AAC3B,GAQa,IAAsC;AAAA,EAEjD,cAAc;AAAA,IACZ,KAAK;AAAA,IACL,QAAQ,EAAE,YAAY,EAAa,YAAY;AAAA,EACjD;AAAA,EAQA,wBAAwB;AAAA,IACtB,KAAK;AAAA,IACL,QAAA,CAAS,OAAS,EAChB,QAAQ,EAAE,gCAAgC,EAAyB,CAAG,EAAE,EAC1E;AAAA,IACA,cAAA,CAAe,MAAQ,CAAC,EAAyB,CAAG;AAAA,IACpD,WAAW,CAAC,aAAa;AAAA,IACzB,WAAW,EAAwB;AAAA,EACrC;AAAA,EAMA,sBAAsB,EACpB,WAAW,EAAwB,+BACrC;AAAA,EAOA,aAAa;AAAA,IACX,KAAK;AAAA,IACL,QAAQ,EAAE,YAAY,EAAa,eAAe;AAAA,EACpD;AAAA,EAMA,+BAA+B;AAAA,IAC7B,GAAG,EAAsB,EAAE,cAAc;AAAA,MAAE,UAAU;AAAA,MAAa,UAAU;AAAA,IAAY,EAAE,CAAC;AAAA,IAC3F,cAAc;AAAA,EAChB;AAAA,EAGA,6BAA6B;AAAA,IAC3B,GAAG,EAAsB;AAAA,MACvB,cAAc;AAAA,QAAE,UAAU;AAAA,QAAc,UAAU;AAAA,MAAiB;AAAA,MACnE,IAAI;AAAA,QACF,WAAW;AAAA,QACV,CAAA,MAAM,CAAA,EAAA,GAA6B,EAAE,KAAK,GAAG;AAAA,QAC9C,uBAAuB;AAAA,UACrB,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,IAAI;AAAA,UACJ,IAAI;AAAA,QACN;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV,SAAS;AAAA,QACT,aAAA,CAAc,MAAiB,EAAM,EAAM,QAAQ,KAAK,SAAS,GAAG;AAAA,QACnE,CAAA,MAAM,CAAA,mBAAyB,GAAqB,EACnD,OAAA,CAAQ,MAAiB,EAAM,EAAM,QAAQ,KAAK,SAAS,GAAG,EAChE;AAAA,MACF;AAAA,MACA,eAAA,CAAgB,MAAS,EAAK,eAAe,2BAA2B;AAAA,IAC1E,CAAC;AAAA,IACD,eAAe;AAAA,EACjB;AACF"}
@@ -2,6 +2,6 @@ export { ctaActions } from './ctaConfig';
2
2
  export { ctaHandlers, type CtaHandlerName } from './ctaHandlers';
3
3
  export { ctaPostMessages, resolveCtaMetadata, type CtaPostMessageResolver } from './ctaPostMessages';
4
4
  export { HOST_ACTIONS, type HostActionName } from './hostActions';
5
- export { beatContextOf, reportCtaClick, resolveCtaState, resolveStep, runCtaAction, runCtaHandler, runInDescriptionCta, sendCtaAnalytics, } from './runCtaAction';
5
+ export { beatContextOf, postCtaMessage, reportCtaClick, resolveCtaState, resolveStep, runCtaAction, runCtaHandler, runInDescriptionCta, sendCtaAnalytics, } from './runCtaAction';
6
6
  export { useBeatCtaActions, useCtaHandler, type BeatCtaActions } from './useCtaAction';
7
7
  export type { CtaContext, CtaEffect, CtaHandler, CtaHandlerContext, CtaParams, CtaPresentation, CtaSurveyAnswer, CtaSlot, CtaState, CtaStateContext, CtaStep, RunHandlerOptions, RunInDescriptionCtaArgs, } from './types';
@@ -1,5 +1,6 @@
1
1
  import { AnalyticsEventConfigEntry } from '../analytics/analyticsEventsConfig';
2
2
  import { CtaHandlerName } from './ctaHandlers';
3
+ import { CtaPostMessageMetadata } from '../../core';
3
4
  import { CtaContext, CtaHandlerContext, CtaState, CtaStateContext, CtaStep, RunHandlerOptions, RunInDescriptionCtaArgs } from './types';
4
5
  /** The beat's own context (input a block collected for it), `{}` until something is written. */
5
6
  export declare const beatContextOf: ({ beat, stores }: Pick<CtaStateContext, "beat" | "stores">) => Record<string, unknown>;
@@ -11,6 +12,11 @@ export declare const resolveStep: ({ cta }: {
11
12
  }) => CtaStep;
12
13
  /** Pending always disables, as may the step's `disabledWhen`; its `presenter` may replace the button. */
13
14
  export declare const resolveCtaState: (ctx: CtaStateContext) => CtaState;
15
+ /**
16
+ * Posts this CTA's resolved message (event, op and beat-specific payload, from the backend's
17
+ * `cta.metadata` or the template's `ctaPostMessages` entry) to the host.
18
+ */
19
+ export declare const postCtaMessage: ({ beat, stores }: Pick<CtaContext, "beat" | "stores">, metadata: CtaPostMessageMetadata) => void;
14
20
  type AnalyticsCtx = Pick<CtaContext, 'beat' | 'stores' | 'hostActions'>;
15
21
  /**
16
22
  * The one way to fire a catalogued analytics event. Takes the catalogue entry itself (e.g.
@@ -137,6 +137,7 @@ var E = {}, l = ({ cta: t }) => t.action_key && S[t.action_key] || E, D = (t) =>
137
137
  }, { handler: a });
138
138
  };
139
139
  export {
140
+ b as postCtaMessage,
140
141
  R as reportCtaClick,
141
142
  D as resolveCtaState,
142
143
  l as resolveStep,