@mx-cartographer/experiences 9.5.4 → 9.6.0-alpha-ram1-connect-widget-testing

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 (78) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/common/components/ConnectDrawer.es.js +17 -44
  3. package/dist/common/components/ConnectDrawer.es.js.map +1 -1
  4. package/dist/common/components/ConnectWidgetPanel.d.ts +8 -0
  5. package/dist/common/components/ConnectWidgetPanel.es.js +44 -0
  6. package/dist/common/components/ConnectWidgetPanel.es.js.map +1 -0
  7. package/dist/common/components/dialog/Dialog.d.ts +2 -0
  8. package/dist/common/components/dialog/Dialog.es.js +30 -30
  9. package/dist/common/components/dialog/Dialog.es.js.map +1 -1
  10. package/dist/common/components/index.d.ts +1 -0
  11. package/dist/common/index.es.js +67 -65
  12. package/dist/core/index.es.js +111 -109
  13. package/dist/core/types/Insights.d.ts +33 -16
  14. package/dist/core/types/Insights.es.js +6 -0
  15. package/dist/core/types/Insights.es.js.map +1 -0
  16. package/dist/core/types/index.d.ts +2 -1
  17. package/dist/core/types/localization/InsightsFeedCopy.d.ts +87 -0
  18. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js +19 -19
  19. package/dist/insights-v2/actionBlocks/ActionBlockLayer.es.js.map +1 -1
  20. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.d.ts +21 -0
  21. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js +16 -0
  22. package/dist/insights-v2/actionBlocks/ConnectWidgetActionBlock.es.js.map +1 -0
  23. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.d.ts +12 -0
  24. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.es.js +25 -0
  25. package/dist/insights-v2/actionBlocks/ConnectionDetailActionBlock.es.js.map +1 -0
  26. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.d.ts +17 -0
  27. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.es.js +39 -0
  28. package/dist/insights-v2/actionBlocks/FeedbackModalActionBlock.es.js.map +1 -0
  29. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.d.ts +16 -0
  30. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.es.js +47 -0
  31. package/dist/insights-v2/actionBlocks/SurveyModalActionBlock.es.js.map +1 -0
  32. package/dist/insights-v2/beatActions.d.ts +2 -2
  33. package/dist/insights-v2/beatActions.es.js.map +1 -1
  34. package/dist/insights-v2/blocks/ChartBlocks/DonutChartBlock/utils.d.ts +1 -1
  35. package/dist/insights-v2/blocks/ChartBlocks/DonutChartBlock/utils.es.js.map +1 -1
  36. package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.d.ts +1 -1
  37. package/dist/insights-v2/blocks/ChartBlocks/DoubleBarChartBlock/layout.es.js.map +1 -1
  38. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/IconComponent.d.ts +1 -1
  39. package/dist/insights-v2/blocks/ComponentBlocks/AccountBlock/IconComponent.es.js.map +1 -1
  40. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.d.ts +5 -2
  41. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js +36 -35
  42. package/dist/insights-v2/blocks/ComponentBlocks/TransactionBlock/TransactionBlock.es.js.map +1 -1
  43. package/dist/insights-v2/blocks/ComponentBlocks/WithdrawalBlock/WithdrawalBlock.d.ts +2 -2
  44. package/dist/insights-v2/blocks/ComponentBlocks/WithdrawalBlock/WithdrawalBlock.es.js +6 -5
  45. package/dist/insights-v2/blocks/ComponentBlocks/WithdrawalBlock/WithdrawalBlock.es.js.map +1 -1
  46. package/dist/insights-v2/blocks/ImageBlocks/SVGImageBlock/layout.d.ts +1 -1
  47. package/dist/insights-v2/blocks/ImageBlocks/SVGImageBlock/layout.es.js.map +1 -1
  48. package/dist/insights-v2/components/BaseLayout.es.js +14 -14
  49. package/dist/insights-v2/components/CompactInsightCard.d.ts +4 -4
  50. package/dist/insights-v2/components/CompactInsightCard.es.js +50 -46
  51. package/dist/insights-v2/components/CompactInsightCard.es.js.map +1 -1
  52. package/dist/insights-v2/components/ConnectionDetailDrillDown.d.ts +32 -0
  53. package/dist/insights-v2/components/ConnectionDetailDrillDown.es.js +148 -0
  54. package/dist/insights-v2/components/ConnectionDetailDrillDown.es.js.map +1 -0
  55. package/dist/insights-v2/components/FeedbackDialog.d.ts +3 -1
  56. package/dist/insights-v2/components/FeedbackDialog.es.js +80 -72
  57. package/dist/insights-v2/components/FeedbackDialog.es.js.map +1 -1
  58. package/dist/insights-v2/components/FeedbackModal.d.ts +60 -0
  59. package/dist/insights-v2/components/FeedbackModal.es.js +61 -0
  60. package/dist/insights-v2/components/FeedbackModal.es.js.map +1 -0
  61. package/dist/insights-v2/components/SurveyModal.d.ts +65 -0
  62. package/dist/insights-v2/components/SurveyModal.es.js +138 -0
  63. package/dist/insights-v2/components/SurveyModal.es.js.map +1 -0
  64. package/dist/insights-v2/components/shared/StatusSnackbar.d.ts +28 -0
  65. package/dist/insights-v2/components/shared/StatusSnackbar.es.js +19 -0
  66. package/dist/insights-v2/components/shared/StatusSnackbar.es.js.map +1 -0
  67. package/dist/insights-v2/index.d.ts +4 -0
  68. package/dist/insights-v2/index.es.js +72 -64
  69. package/dist/insights-v2/mappings/actionBlocksKey.d.ts +4 -0
  70. package/dist/insights-v2/mappings/actionBlocksKey.es.js +4 -0
  71. package/dist/insights-v2/mappings/actionBlocksKey.es.js.map +1 -1
  72. package/dist/insights-v2/mappings/blocks.es.js +79 -56
  73. package/dist/insights-v2/mappings/blocks.es.js.map +1 -1
  74. package/dist/insights-v2/resolveInsightRender.d.ts +8 -5
  75. package/dist/insights-v2/resolveInsightRender.es.js.map +1 -1
  76. package/dist/microinsights/cards/InsightCard.es.js +32 -31
  77. package/dist/microinsights/cards/InsightCard.es.js.map +1 -1
  78. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackDialog.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackDialog.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport FormControl from '@mui/material/FormControl'\nimport FormControlLabel from '@mui/material/FormControlLabel'\nimport Radio from '@mui/material/Radio'\nimport RadioGroup from '@mui/material/RadioGroup'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nconst CHARACTER_LIMIT = 250\n\nexport type FeedbackDialogCloseReason = 'closeButton' | 'backdropClick' | 'escapeKeyDown'\n\nexport interface FeedbackDialogProps {\n title: string\n options: string[]\n characterLimit?: number\n characterLimitLabel?: string\n isOpen: boolean\n onSubmit: (option: string, detail?: string) => void\n /** Called on every close; `reason` is set for user-initiated closes (X/backdrop/escape), undefined on submit/back. */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n onBackClick?: () => void\n onTextInputFocus?: () => void\n secondaryText: string\n primaryText: string\n closeAriaLabel: string\n}\n\n/** Generic feedback survey dialog. Last option shows detail text field. */\nconst FeedbackDialog = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n options,\n characterLimit = CHARACTER_LIMIT,\n characterLimitLabel,\n secondaryText,\n primaryText,\n closeAriaLabel,\n onBackClick,\n onTextInputFocus,\n}: FeedbackDialogProps) => {\n const [selected, setSelected] = useState('')\n const [detail, setDetail] = useState('')\n const hasTrackedFocus = useRef(false)\n const skipCloseAnalytics = useRef(false)\n\n useEffect(() => {\n if (isOpen) {\n hasTrackedFocus.current = false\n skipCloseAnalytics.current = false\n }\n }, [isOpen])\n\n if (options.length === 0) return null\n\n const isOther = selected === options[options.length - 1]\n const isSubmitDisabled = !selected || (isOther && !detail.trim())\n\n const reset = () => {\n setSelected('')\n setDetail('')\n }\n\n const resolveCloseReason = (reason?: string): FeedbackDialogCloseReason | undefined => {\n if (reason === 'backdropClick' || reason === 'escapeKeyDown') return reason\n if (!skipCloseAnalytics.current) return 'closeButton'\n return undefined\n }\n\n const handleClose = (_event?: unknown, reason?: string) => {\n const closeReason = resolveCloseReason(reason)\n reset()\n onClose(closeReason)\n }\n\n const handleBack = () => {\n skipCloseAnalytics.current = true\n onBackClick?.()\n }\n\n const handleTextFocus = () => {\n if (!hasTrackedFocus.current) {\n hasTrackedFocus.current = true\n onTextInputFocus?.()\n }\n }\n\n const handleSubmit = () => {\n skipCloseAnalytics.current = true\n onSubmit(selected, isOther ? detail.trim() : undefined)\n reset()\n }\n\n return (\n <Dialog\n copy={{ title, close_aria: closeAriaLabel }}\n disablePrimaryButton={isSubmitDisabled}\n isOpen={isOpen}\n onClose={handleClose}\n onPrimaryAction={handleSubmit}\n onSecondaryAction={handleBack}\n primaryText={primaryText}\n secondaryText={secondaryText}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiDialog-paperScrollPaper': { bgcolor: 'background.paper' },\n '& .MuiDialog-paper': {\n outline: 'none',\n '&:focus-visible': {\n outline: '2px solid',\n outlineColor: 'primary.main',\n },\n },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n <FormControl>\n <RadioGroup\n aria-label={title}\n name=\"feedback-radio-group\"\n onChange={(e) => setSelected(e.target.value)}\n value={selected}\n >\n {options.map((option) => (\n <FormControlLabel\n control={\n <Radio\n sx={{\n '& .MuiSvgIcon-root': {\n fontSize: 22,\n color: 'action.active',\n },\n }}\n />\n }\n key={option}\n label={option}\n sx={{\n '& .MuiFormControlLabel-label': {\n color: 'text.primary',\n fontSize: 15,\n },\n }}\n value={option}\n />\n ))}\n </RadioGroup>\n </FormControl>\n\n {isOther && (\n <Stack sx={{ gap: 3, mt: 4 }}>\n <TextField\n autoFocus\n maxRows={4}\n minRows={4}\n multiline={true}\n onChange={(e) => setDetail(e.target.value)}\n onFocus={handleTextFocus}\n slotProps={{ htmlInput: { maxLength: characterLimit } }}\n value={detail}\n />\n {characterLimitLabel && (\n <Text sx={{ color: 'text.secondary', fontWeight: 400 }} variant=\"subtitle2\">\n {characterLimitLabel}\n </Text>\n )}\n </Stack>\n )}\n </Dialog>\n )\n}\n\nexport default FeedbackDialog\n"],"mappings":"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"}
1
+ {"version":3,"file":"FeedbackDialog.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackDialog.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport FormControl from '@mui/material/FormControl'\nimport FormControlLabel from '@mui/material/FormControlLabel'\nimport Radio from '@mui/material/Radio'\nimport RadioGroup from '@mui/material/RadioGroup'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nconst CHARACTER_LIMIT = 250\n\nexport type FeedbackDialogCloseReason = 'closeButton' | 'backdropClick' | 'escapeKeyDown'\n\nexport interface FeedbackDialogProps {\n title: string\n options: string[]\n characterLimit?: number\n /** Optional paragraph rendered between the title and the options (Figma feedback survey). */\n description?: string\n characterLimitLabel?: string\n isOpen: boolean\n onSubmit: (option: string, detail?: string) => void\n /** Called on every close; `reason` is set for user-initiated closes (X/backdrop/escape), undefined on submit/back. */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n onBackClick?: () => void\n onTextInputFocus?: () => void\n secondaryText: string\n primaryText: string\n closeAriaLabel: string\n}\n\n/** Generic feedback survey dialog. Last option shows detail text field. */\nconst FeedbackDialog = ({\n isOpen,\n onClose,\n onSubmit,\n title,\n options,\n characterLimit = CHARACTER_LIMIT,\n description,\n characterLimitLabel,\n secondaryText,\n primaryText,\n closeAriaLabel,\n onBackClick,\n onTextInputFocus,\n}: FeedbackDialogProps) => {\n const [selected, setSelected] = useState('')\n const [detail, setDetail] = useState('')\n const hasTrackedFocus = useRef(false)\n const skipCloseAnalytics = useRef(false)\n\n useEffect(() => {\n if (isOpen) {\n hasTrackedFocus.current = false\n skipCloseAnalytics.current = false\n }\n }, [isOpen])\n\n if (options.length === 0) return null\n\n const isOther = selected === options[options.length - 1]\n const isSubmitDisabled = !selected || (isOther && !detail.trim())\n\n const reset = () => {\n setSelected('')\n setDetail('')\n }\n\n const resolveCloseReason = (reason?: string): FeedbackDialogCloseReason | undefined => {\n if (reason === 'backdropClick' || reason === 'escapeKeyDown') return reason\n if (!skipCloseAnalytics.current) return 'closeButton'\n return undefined\n }\n\n const handleClose = (_event?: unknown, reason?: string) => {\n const closeReason = resolveCloseReason(reason)\n reset()\n onClose(closeReason)\n }\n\n const handleBack = () => {\n skipCloseAnalytics.current = true\n onBackClick?.()\n }\n\n const handleTextFocus = () => {\n if (!hasTrackedFocus.current) {\n hasTrackedFocus.current = true\n onTextInputFocus?.()\n }\n }\n\n const handleSubmit = () => {\n skipCloseAnalytics.current = true\n onSubmit(selected, isOther ? detail.trim() : undefined)\n reset()\n }\n\n return (\n <Dialog\n copy={{ title, close_aria: closeAriaLabel }}\n disablePrimaryButton={isSubmitDisabled}\n isOpen={isOpen}\n onClose={handleClose}\n onPrimaryAction={handleSubmit}\n onSecondaryAction={handleBack}\n primaryText={primaryText}\n secondaryText={secondaryText}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiDialog-paperScrollPaper': { bgcolor: 'background.paper' },\n '& .MuiDialog-paper': {\n outline: 'none',\n '&:focus-visible': {\n outline: '2px solid',\n outlineColor: 'primary.main',\n },\n },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n {description && (\n <Text sx={{ mb: 8 }} variant=\"body1\">\n {description}\n </Text>\n )}\n <FormControl>\n <RadioGroup\n aria-label={title}\n name=\"feedback-radio-group\"\n onChange={(e) => setSelected(e.target.value)}\n value={selected}\n >\n {options.map((option) => (\n <FormControlLabel\n control={\n <Radio\n sx={{\n '& .MuiSvgIcon-root': {\n fontSize: 22,\n color: 'action.active',\n },\n }}\n />\n }\n key={option}\n label={option}\n sx={{\n '& .MuiFormControlLabel-label': {\n color: 'text.primary',\n fontSize: 15,\n },\n }}\n value={option}\n />\n ))}\n </RadioGroup>\n </FormControl>\n\n {isOther && (\n <Stack sx={{ gap: 3, mt: 4 }}>\n <TextField\n autoFocus\n maxRows={4}\n minRows={4}\n multiline={true}\n onChange={(e) => setDetail(e.target.value)}\n onFocus={handleTextFocus}\n slotProps={{ htmlInput: { maxLength: characterLimit } }}\n value={detail}\n />\n {characterLimitLabel && (\n <Text sx={{ color: 'text.secondary', fontWeight: 400 }} variant=\"subtitle2\">\n {characterLimitLabel}\n </Text>\n )}\n </Stack>\n )}\n </Dialog>\n )\n}\n\nexport default FeedbackDialog\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { FeedbackDialogCloseReason } from './FeedbackDialog';
2
+ /** Localized strings the modal renders — resolved by the caller (see FeedbackModalActionBlock). */
3
+ export interface FeedbackModalContent {
4
+ /** Dialog title, e.g. "Can you tell us why?". */
5
+ title: string;
6
+ /** Optional paragraph under the title, e.g. "We'd love to hear why…". */
7
+ description?: string;
8
+ /** Survey reasons; the last option reveals the free-text detail field. */
9
+ options: string[];
10
+ /** Primary (Submit) button label. */
11
+ submitText: string;
12
+ /** Secondary (No thanks) button label. */
13
+ cancelText: string;
14
+ /** ARIA label for the dialog close button. */
15
+ closeAriaLabel: string;
16
+ /** Helper text under the detail field, e.g. "250 character limit". */
17
+ characterLimitLabel?: string;
18
+ /** Success snackbar message, e.g. "Your feedback has been submitted.". */
19
+ successMessage: string;
20
+ /** Error snackbar message, e.g. "Your feedback could not be submitted.". */
21
+ errorMessage: string;
22
+ /** Error snackbar action label, e.g. "Try Again". */
23
+ tryAgainText: string;
24
+ /** ARIA label for the snackbar close button. */
25
+ toastCloseAriaLabel: string;
26
+ }
27
+ interface FeedbackModalProps {
28
+ isOpen: boolean;
29
+ copy: FeedbackModalContent;
30
+ /**
31
+ * Fired when the survey is submitted. May return a promise: a rejection
32
+ * switches to the error snackbar (Figma `1941:167637`), whose Try Again
33
+ * action re-submits the same selection. Sync/resolved submissions show the
34
+ * success snackbar.
35
+ */
36
+ onSubmit: (option: string, detail?: string) => void | Promise<void>;
37
+ /**
38
+ * Fired when the whole flow ends: the dialog is dismissed without submitting
39
+ * (reason set), or either snackbar is closed / auto-hides (no reason).
40
+ */
41
+ onClose: (reason?: FeedbackDialogCloseReason) => void;
42
+ /**
43
+ * When provided, the secondary button acts as "Back" — it fires this instead
44
+ * of ending the flow via `onClose` (e.g. SurveyModal returning to its survey
45
+ * step). When absent, the secondary ("No thanks") ends the flow as before.
46
+ */
47
+ onBack?: () => void;
48
+ }
49
+ /**
50
+ * The CTA feedback drilldown (Figma `1941:192803`): a "Can you tell us why?"
51
+ * survey dialog followed by a success snackbar (Figma `1941:167636`) — or an
52
+ * error snackbar with a Try Again action (Figma `1941:167637`) when the
53
+ * submission fails.
54
+ *
55
+ * Purely presentational — copy arrives resolved via `FeedbackModalContent`;
56
+ * the `feedback_modal_block` action block wires it to the copy store, the beat
57
+ * actions, and the action-drawer session.
58
+ */
59
+ declare const FeedbackModal: ({ copy, isOpen, onBack, onClose, onSubmit }: FeedbackModalProps) => import("react/jsx-runtime").JSX.Element;
60
+ export default FeedbackModal;
@@ -0,0 +1,61 @@
1
+ import g from "./shared/StatusSnackbar.es.js";
2
+ import k from "./FeedbackDialog.es.js";
3
+ import { useEffect as L, useRef as u, useState as T } from "react";
4
+ import { Fragment as A, jsx as b, jsxs as S } from "react/jsx-runtime";
5
+ var D = ({ copy: e, isOpen: a, onBack: l, onClose: m, onSubmit: d }) => {
6
+ const [t, i] = T("survey"), n = u(!1), s = u(null);
7
+ L(() => {
8
+ a && (i("survey"), n.current = !1, s.current = null);
9
+ }, [a]);
10
+ const f = async (r, c) => {
11
+ n.current = !0, s.current = {
12
+ option: r,
13
+ detail: c
14
+ };
15
+ try {
16
+ await d(r, c), i("success");
17
+ } catch {
18
+ i("error");
19
+ }
20
+ }, h = () => {
21
+ s.current && f(s.current.option, s.current.detail);
22
+ }, o = u(!1), v = l ? () => {
23
+ o.current = !0, l();
24
+ } : void 0, x = (r) => {
25
+ if (!n.current) {
26
+ if (o.current) {
27
+ o.current = !1;
28
+ return;
29
+ }
30
+ m(r);
31
+ }
32
+ };
33
+ return /* @__PURE__ */ S(A, { children: [/* @__PURE__ */ b(k, {
34
+ characterLimitLabel: e.characterLimitLabel,
35
+ closeAriaLabel: e.closeAriaLabel,
36
+ description: e.description,
37
+ isOpen: a && t === "survey" && !n.current,
38
+ onBackClick: v,
39
+ onClose: x,
40
+ onSubmit: (r, c) => {
41
+ f(r, c);
42
+ },
43
+ options: e.options,
44
+ primaryText: e.submitText,
45
+ secondaryText: e.cancelText,
46
+ title: e.title
47
+ }), /* @__PURE__ */ b(g, {
48
+ actionText: t === "error" ? e.tryAgainText : void 0,
49
+ closeAriaLabel: e.toastCloseAriaLabel,
50
+ message: t === "error" ? e.errorMessage : e.successMessage,
51
+ onActionClick: h,
52
+ onClose: () => m(),
53
+ open: a && t !== "survey",
54
+ severity: t === "error" ? "error" : "success"
55
+ })] });
56
+ };
57
+ export {
58
+ D as default
59
+ };
60
+
61
+ //# sourceMappingURL=FeedbackModal.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedbackModal.es.js","names":[],"sources":["../../../src/insights-v2/components/FeedbackModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport StatusSnackbar from './shared/StatusSnackbar'\n\nimport FeedbackDialog, { type FeedbackDialogCloseReason } from './FeedbackDialog'\n\n/** Localized strings the modal renders — resolved by the caller (see FeedbackModalActionBlock). */\nexport interface FeedbackModalContent {\n /** Dialog title, e.g. \"Can you tell us why?\". */\n title: string\n /** Optional paragraph under the title, e.g. \"We'd love to hear why…\". */\n description?: string\n /** Survey reasons; the last option reveals the free-text detail field. */\n options: string[]\n /** Primary (Submit) button label. */\n submitText: string\n /** Secondary (No thanks) button label. */\n cancelText: string\n /** ARIA label for the dialog close button. */\n closeAriaLabel: string\n /** Helper text under the detail field, e.g. \"250 character limit\". */\n characterLimitLabel?: string\n /** Success snackbar message, e.g. \"Your feedback has been submitted.\". */\n successMessage: string\n /** Error snackbar message, e.g. \"Your feedback could not be submitted.\". */\n errorMessage: string\n /** Error snackbar action label, e.g. \"Try Again\". */\n tryAgainText: string\n /** ARIA label for the snackbar close button. */\n toastCloseAriaLabel: string\n}\n\ninterface FeedbackModalProps {\n isOpen: boolean\n copy: FeedbackModalContent\n /**\n * Fired when the survey is submitted. May return a promise: a rejection\n * switches to the error snackbar (Figma `1941:167637`), whose Try Again\n * action re-submits the same selection. Sync/resolved submissions show the\n * success snackbar.\n */\n onSubmit: (option: string, detail?: string) => void | Promise<void>\n /**\n * Fired when the whole flow ends: the dialog is dismissed without submitting\n * (reason set), or either snackbar is closed / auto-hides (no reason).\n */\n onClose: (reason?: FeedbackDialogCloseReason) => void\n /**\n * When provided, the secondary button acts as \"Back\" — it fires this instead\n * of ending the flow via `onClose` (e.g. SurveyModal returning to its survey\n * step). When absent, the secondary (\"No thanks\") ends the flow as before.\n */\n onBack?: () => void\n}\n\ntype Phase = 'survey' | 'success' | 'error'\n\n/**\n * The CTA feedback drilldown (Figma `1941:192803`): a \"Can you tell us why?\"\n * survey dialog followed by a success snackbar (Figma `1941:167636`) — or an\n * error snackbar with a Try Again action (Figma `1941:167637`) when the\n * submission fails.\n *\n * Purely presentational — copy arrives resolved via `FeedbackModalContent`;\n * the `feedback_modal_block` action block wires it to the copy store, the beat\n * actions, and the action-drawer session.\n */\nconst FeedbackModal = ({ copy, isOpen, onBack, onClose, onSubmit }: FeedbackModalProps) => {\n const [phase, setPhase] = useState<Phase>('survey')\n // Ref, not state: the shared Dialog fires `onClose()` synchronously right\n // after `onPrimaryAction()`, before the state update lands. Without the ref\n // that close would end the whole flow and the snackbar could never show.\n const hasSubmitted = useRef(false)\n // Kept for the error snackbar's Try Again, which re-submits the selection.\n const lastSubmission = useRef<{ option: string; detail?: string } | null>(null)\n\n // A new flow session starts from the survey, not a stale snackbar.\n useEffect(() => {\n if (isOpen) {\n setPhase('survey')\n hasSubmitted.current = false\n lastSubmission.current = null\n }\n }, [isOpen])\n\n const submit = async (option: string, detail?: string) => {\n hasSubmitted.current = true\n lastSubmission.current = { option, detail }\n try {\n await onSubmit(option, detail)\n setPhase('success')\n } catch {\n setPhase('error')\n }\n }\n\n const retry = () => {\n if (lastSubmission.current) {\n void submit(lastSubmission.current.option, lastSubmission.current.detail)\n }\n }\n\n // Ref for the same reason as hasSubmitted: the back-click's trailing Dialog\n // close fires synchronously, before any state lands.\n const backTaken = useRef(false)\n\n const handleBack = onBack\n ? () => {\n backTaken.current = true\n onBack()\n }\n : undefined\n\n // Only user-initiated closes (X / backdrop / escape / No thanks) end the\n // flow — the post-submit close hands over to the snackbar, and a back-click's\n // trailing close belongs to the caller's back navigation.\n const handleDialogClose = (reason?: FeedbackDialogCloseReason) => {\n if (hasSubmitted.current) return\n if (backTaken.current) {\n backTaken.current = false\n return\n }\n onClose(reason)\n }\n\n return (\n <>\n <FeedbackDialog\n characterLimitLabel={copy.characterLimitLabel}\n closeAriaLabel={copy.closeAriaLabel}\n description={copy.description}\n isOpen={isOpen && phase === 'survey' && !hasSubmitted.current}\n onBackClick={handleBack}\n onClose={handleDialogClose}\n onSubmit={(option, detail) => void submit(option, detail)}\n options={copy.options}\n primaryText={copy.submitText}\n secondaryText={copy.cancelText}\n title={copy.title}\n />\n <StatusSnackbar\n actionText={phase === 'error' ? copy.tryAgainText : undefined}\n closeAriaLabel={copy.toastCloseAriaLabel}\n message={phase === 'error' ? copy.errorMessage : copy.successMessage}\n onActionClick={retry}\n onClose={() => onClose()}\n open={isOpen && phase !== 'survey'}\n severity={phase === 'error' ? 'error' : 'success'}\n />\n </>\n )\n}\n\nexport default FeedbackModal\n"],"mappings":";;;;AAmEA,IAAM,IAAA,CAAiB,EAAE,MAAA,GAAM,QAAA,GAAQ,QAAA,GAAQ,SAAA,GAAS,UAAA,EAAA,MAAmC;AACzF,QAAM,CAAC,GAAO,CAAA,IAAY,EAAgB,QAAQ,GAI5C,IAAe,EAAO,EAAK,GAE3B,IAAiB,EAAmD,IAAI;AAG9E,EAAA,EAAA,MAAgB;AACd,IAAI,MACF,EAAS,QAAQ,GACjB,EAAa,UAAU,IACvB,EAAe,UAAU;AAAA,EAE7B,GAAG,CAAC,CAAM,CAAC;AAEX,QAAM,IAAS,OAAO,GAAgB,MAAoB;AACxD,IAAA,EAAa,UAAU,IACvB,EAAe,UAAU;AAAA,MAAE,QAAA;AAAA,MAAQ,QAAA;AAAA,IAAO;AAC1C,QAAI;AACF,YAAM,EAAS,GAAQ,CAAM,GAC7B,EAAS,SAAS;AAAA,IACpB,QAAQ;AACN,MAAA,EAAS,OAAO;AAAA,IAClB;AAAA,EACF,GAEM,IAAA,MAAc;AAClB,IAAI,EAAe,WACjB,EAAY,EAAe,QAAQ,QAAQ,EAAe,QAAQ,MAAM;AAAA,EAE5E,GAIM,IAAY,EAAO,EAAK,GAExB,IAAa,IAAA,MACT;AACJ,IAAA,EAAU,UAAU,IACpB,EAAO;AAAA,EACT,IACA,QAKE,IAAA,CAAqB,MAAuC;AAChE,QAAI,CAAA,EAAa,SACjB;AAAA,UAAI,EAAU,SAAS;AACrB,QAAA,EAAU,UAAU;AACpB;AAAA,MACF;AACA,MAAA,EAAQ,CAAM;AAAA;AAAA,EAChB;AAEA,SACE,gBAAA,EAAA,GAAA,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IACE,qBAAqB,EAAK;AAAA,IAC1B,gBAAgB,EAAK;AAAA,IACrB,aAAa,EAAK;AAAA,IAClB,QAAQ,KAAU,MAAU,YAAY,CAAC,EAAa;AAAA,IACtD,aAAa;AAAA,IACb,SAAS;AAAA,IACT,UAAA,CAAW,GAAQ,MAAA;AAAW,MAAK,EAAO,GAAQ,CAAM;AAAA;AAAA,IACxD,SAAS,EAAK;AAAA,IACd,aAAa,EAAK;AAAA,IAClB,eAAe,EAAK;AAAA,IACpB,OAAO,EAAK;AAAA,EACb,CAAA,GACD,gBAAA,EAAC,GAAD;AAAA,IACE,YAAY,MAAU,UAAU,EAAK,eAAe;AAAA,IACpD,gBAAgB,EAAK;AAAA,IACrB,SAAS,MAAU,UAAU,EAAK,eAAe,EAAK;AAAA,IACtD,eAAe;AAAA,IACf,SAAA,MAAe,EAAQ;AAAA,IACvB,MAAM,KAAU,MAAU;AAAA,IAC1B,UAAU,MAAU,UAAU,UAAU;AAAA,EACzC,CAAA,CACD,EAAA,CAAA;AAEN"}
@@ -0,0 +1,65 @@
1
+ /** One survey row (Figma `<UtilityRow>`). Rows act immediately on click. */
2
+ export interface SurveyModalOption {
3
+ /** Overline above the row label, e.g. "Yes," / "No,". */
4
+ overline: string;
5
+ /** Row label, e.g. "This looks correct." */
6
+ label: string;
7
+ /**
8
+ * Row behavior + glyph: `positive` (green check_circle) submits the label
9
+ * right away; `negative` (red cancel) opens the reasons dialog.
10
+ */
11
+ tone: 'positive' | 'negative';
12
+ }
13
+ /** Localized strings the modal renders — resolved by the caller (see SurveyModalActionBlock). */
14
+ export interface SurveyModalContent {
15
+ /** Survey dialog title, e.g. "Does this look right?". */
16
+ title: string;
17
+ options: SurveyModalOption[];
18
+ /** Reasons dialog primary (Submit) button label. */
19
+ submitText: string;
20
+ /** ARIA label for the dialog close buttons. */
21
+ closeAriaLabel: string;
22
+ /** Reasons dialog title (negative path), e.g. "This looks wrong". */
23
+ reasonsTitle: string;
24
+ /** Reasons dialog options; the last one reveals the detail text field. */
25
+ reasonOptions: string[];
26
+ /** Reasons dialog secondary (Back) label. */
27
+ backText: string;
28
+ /** Helper text under the reasons detail field. */
29
+ characterLimitLabel?: string;
30
+ /** Success snackbar message (Figma 1941:212643). */
31
+ successMessage: string;
32
+ /** Error snackbar message (Figma 1941:212644). */
33
+ errorMessage: string;
34
+ /** Error snackbar retry label, e.g. "Try Again". */
35
+ tryAgainText: string;
36
+ /** ARIA label for the snackbar close button. */
37
+ toastCloseAriaLabel: string;
38
+ }
39
+ interface SurveyModalProps {
40
+ isOpen: boolean;
41
+ copy: SurveyModalContent;
42
+ /**
43
+ * Fired when an answer is submitted — the positive row's label, or a
44
+ * reasons-dialog selection (with optional detail). May return a promise: a
45
+ * rejection switches to the error snackbar, whose Try Again re-submits.
46
+ */
47
+ onSubmit: (option: string, detail?: string) => void | Promise<void>;
48
+ /** Fired when the whole flow ends (dialogs dismissed or a snackbar closed). */
49
+ onClose: () => void;
50
+ }
51
+ /**
52
+ * The confirmation survey drilldown (Figma `1941:212640`, Upcoming
53
+ * Subscriptions "Does this look right?"):
54
+ *
55
+ * - the POSITIVE row submits immediately and shows the success snackbar
56
+ * (`1941:212643`) — or the error snackbar with Try Again (`1941:212644`);
57
+ * - the NEGATIVE row opens the reasons dialog (`1941:212642`, a FeedbackDialog:
58
+ * radios + Back/Submit), whose submission feeds the same snackbars.
59
+ *
60
+ * Purely presentational — copy arrives resolved via `SurveyModalContent`; the
61
+ * `survey_modal_block` action block wires it to the copy store, the beat
62
+ * actions, and the action-drawer session.
63
+ */
64
+ declare const SurveyModal: ({ copy, isOpen, onClose, onSubmit }: SurveyModalProps) => import("react/jsx-runtime").JSX.Element;
65
+ export default SurveyModal;
@@ -0,0 +1,138 @@
1
+ import T from "../../common/components/dialog/Dialog.es.js";
2
+ import C from "./shared/StatusSnackbar.es.js";
3
+ import L from "./FeedbackModal.es.js";
4
+ import { useEffect as k, useRef as d, useState as M } from "react";
5
+ import m from "@mui/material/Stack";
6
+ import { Text as h } from "@mxenabled/mxui";
7
+ import { Icon as b } from "@mxenabled/mx-icons";
8
+ import { Fragment as p, jsx as t, jsxs as l } from "react/jsx-runtime";
9
+ import y from "@mui/material/Divider";
10
+ import S from "@mui/material/ButtonBase";
11
+ var w = {
12
+ positive: {
13
+ color: "success.main",
14
+ name: "check_circle"
15
+ },
16
+ negative: {
17
+ color: "error.main",
18
+ name: "cancel"
19
+ }
20
+ }, W = ({ copy: e, isOpen: a, onClose: c, onSubmit: f }) => {
21
+ const [s, o] = M("survey"), u = d(!1), n = d(null);
22
+ k(() => {
23
+ a && (o("survey"), u.current = !1, n.current = null);
24
+ }, [a]);
25
+ const x = async (r, i) => {
26
+ u.current = !0, n.current = {
27
+ option: r,
28
+ detail: i
29
+ };
30
+ try {
31
+ await f(r, i), o("success");
32
+ } catch {
33
+ o("error");
34
+ }
35
+ }, g = () => {
36
+ n.current && x(n.current.option, n.current.detail);
37
+ }, v = (r) => {
38
+ r.tone === "positive" ? x(r.label) : o("reasons");
39
+ }, A = () => {
40
+ u.current || c();
41
+ };
42
+ return /* @__PURE__ */ l(p, { children: [
43
+ /* @__PURE__ */ t(T, {
44
+ copy: {
45
+ title: e.title,
46
+ close_aria: e.closeAriaLabel
47
+ },
48
+ isOpen: a && s === "survey",
49
+ onClose: A,
50
+ showActions: !1,
51
+ sx: {
52
+ "& .MuiDialogContent-root": { py: 0 },
53
+ "& .MuiButton-outlined": {
54
+ border: "none",
55
+ "&:hover": {
56
+ bgcolor: "transparent",
57
+ border: "none"
58
+ }
59
+ }
60
+ },
61
+ children: /* @__PURE__ */ t(m, { children: e.options.map((r) => {
62
+ const i = w[r.tone];
63
+ return /* @__PURE__ */ l(m, { children: [/* @__PURE__ */ t(y, {}), /* @__PURE__ */ l(S, {
64
+ onClick: () => v(r),
65
+ sx: {
66
+ alignItems: "center",
67
+ display: "flex",
68
+ gap: 12,
69
+ justifyContent: "flex-start",
70
+ px: 4,
71
+ py: 14,
72
+ textAlign: "left",
73
+ width: "100%"
74
+ },
75
+ children: [
76
+ /* @__PURE__ */ t(b, {
77
+ name: i.name,
78
+ size: 24,
79
+ sx: { color: i.color }
80
+ }),
81
+ /* @__PURE__ */ l(m, {
82
+ sx: {
83
+ flex: 1,
84
+ minWidth: 0
85
+ },
86
+ children: [/* @__PURE__ */ t(h, {
87
+ color: "text.primary",
88
+ variant: "caption",
89
+ children: r.overline
90
+ }), /* @__PURE__ */ t(h, {
91
+ sx: { fontWeight: 600 },
92
+ variant: "body1",
93
+ children: r.label
94
+ })]
95
+ }),
96
+ /* @__PURE__ */ t(b, {
97
+ name: "chevron_right",
98
+ size: 20,
99
+ sx: { color: "text.primary" }
100
+ })
101
+ ]
102
+ })] }, r.label);
103
+ }) })
104
+ }),
105
+ /* @__PURE__ */ t(L, {
106
+ copy: {
107
+ title: e.reasonsTitle,
108
+ options: e.reasonOptions,
109
+ submitText: e.submitText,
110
+ cancelText: e.backText,
111
+ closeAriaLabel: e.closeAriaLabel,
112
+ characterLimitLabel: e.characterLimitLabel,
113
+ successMessage: e.successMessage,
114
+ errorMessage: e.errorMessage,
115
+ tryAgainText: e.tryAgainText,
116
+ toastCloseAriaLabel: e.toastCloseAriaLabel
117
+ },
118
+ isOpen: a && s === "reasons",
119
+ onBack: () => o("survey"),
120
+ onClose: () => c(),
121
+ onSubmit: f
122
+ }),
123
+ /* @__PURE__ */ t(C, {
124
+ actionText: s === "error" ? e.tryAgainText : void 0,
125
+ closeAriaLabel: e.toastCloseAriaLabel,
126
+ message: s === "error" ? e.errorMessage : e.successMessage,
127
+ onActionClick: g,
128
+ onClose: () => c(),
129
+ open: a && (s === "success" || s === "error"),
130
+ severity: s === "error" ? "error" : "success"
131
+ })
132
+ ] });
133
+ };
134
+ export {
135
+ W as default
136
+ };
137
+
138
+ //# sourceMappingURL=SurveyModal.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SurveyModal.es.js","names":[],"sources":["../../../src/insights-v2/components/SurveyModal.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport ButtonBase from '@mui/material/ButtonBase'\nimport Divider from '@mui/material/Divider'\nimport Stack from '@mui/material/Stack'\n\nimport { Icon } from '@mxenabled/mx-icons'\nimport { Text } from '@mxenabled/mxui'\n\nimport { Dialog } from '../../common'\n\nimport FeedbackModal from './FeedbackModal'\nimport StatusSnackbar from './shared/StatusSnackbar'\n\n/** One survey row (Figma `<UtilityRow>`). Rows act immediately on click. */\nexport interface SurveyModalOption {\n /** Overline above the row label, e.g. \"Yes,\" / \"No,\". */\n overline: string\n /** Row label, e.g. \"This looks correct.\" */\n label: string\n /**\n * Row behavior + glyph: `positive` (green check_circle) submits the label\n * right away; `negative` (red cancel) opens the reasons dialog.\n */\n tone: 'positive' | 'negative'\n}\n\n/** Localized strings the modal renders — resolved by the caller (see SurveyModalActionBlock). */\nexport interface SurveyModalContent {\n /** Survey dialog title, e.g. \"Does this look right?\". */\n title: string\n options: SurveyModalOption[]\n /** Reasons dialog primary (Submit) button label. */\n submitText: string\n /** ARIA label for the dialog close buttons. */\n closeAriaLabel: string\n /** Reasons dialog title (negative path), e.g. \"This looks wrong\". */\n reasonsTitle: string\n /** Reasons dialog options; the last one reveals the detail text field. */\n reasonOptions: string[]\n /** Reasons dialog secondary (Back) label. */\n backText: string\n /** Helper text under the reasons detail field. */\n characterLimitLabel?: string\n /** Success snackbar message (Figma 1941:212643). */\n successMessage: string\n /** Error snackbar message (Figma 1941:212644). */\n errorMessage: string\n /** Error snackbar retry label, e.g. \"Try Again\". */\n tryAgainText: string\n /** ARIA label for the snackbar close button. */\n toastCloseAriaLabel: string\n}\n\ninterface SurveyModalProps {\n isOpen: boolean\n copy: SurveyModalContent\n /**\n * Fired when an answer is submitted — the positive row's label, or a\n * reasons-dialog selection (with optional detail). May return a promise: a\n * rejection switches to the error snackbar, whose Try Again re-submits.\n */\n onSubmit: (option: string, detail?: string) => void | Promise<void>\n /** Fired when the whole flow ends (dialogs dismissed or a snackbar closed). */\n onClose: () => void\n}\n\ntype Phase = 'survey' | 'reasons' | 'success' | 'error'\n\nconst TONE_ICON: Record<SurveyModalOption['tone'], { color: string; name: string }> = {\n positive: { color: 'success.main', name: 'check_circle' },\n negative: { color: 'error.main', name: 'cancel' },\n}\n\n/**\n * The confirmation survey drilldown (Figma `1941:212640`, Upcoming\n * Subscriptions \"Does this look right?\"):\n *\n * - the POSITIVE row submits immediately and shows the success snackbar\n * (`1941:212643`) — or the error snackbar with Try Again (`1941:212644`);\n * - the NEGATIVE row opens the reasons dialog (`1941:212642`, a FeedbackDialog:\n * radios + Back/Submit), whose submission feeds the same snackbars.\n *\n * Purely presentational — copy arrives resolved via `SurveyModalContent`; the\n * `survey_modal_block` action block wires it to the copy store, the beat\n * actions, and the action-drawer session.\n */\nconst SurveyModal = ({ copy, isOpen, onClose, onSubmit }: SurveyModalProps) => {\n const [phase, setPhase] = useState<Phase>('survey')\n // Guards the survey Dialog's trailing `onClose` after a row acted — the row\n // click hands over to the snackbar / reasons dialog, not a flow end.\n const actionTaken = useRef(false)\n // Kept for the error snackbar's Try Again, which re-submits the selection.\n const lastSubmission = useRef<{ option: string; detail?: string } | null>(null)\n\n // A fresh session starts from the survey.\n useEffect(() => {\n if (isOpen) {\n setPhase('survey')\n actionTaken.current = false\n lastSubmission.current = null\n }\n }, [isOpen])\n\n const submit = async (option: string, detail?: string) => {\n actionTaken.current = true\n lastSubmission.current = { option, detail }\n try {\n await onSubmit(option, detail)\n setPhase('success')\n } catch {\n setPhase('error')\n }\n }\n\n const retry = () => {\n if (lastSubmission.current) {\n void submit(lastSubmission.current.option, lastSubmission.current.detail)\n }\n }\n\n const handleRowClick = (option: SurveyModalOption) => {\n if (option.tone === 'positive') {\n void submit(option.label)\n } else {\n setPhase('reasons')\n }\n }\n\n const handleSurveyClose = () => {\n if (actionTaken.current) return\n onClose()\n }\n\n return (\n <>\n <Dialog\n copy={{ title: copy.title, close_aria: copy.closeAriaLabel }}\n isOpen={isOpen && phase === 'survey'}\n onClose={handleSurveyClose}\n // Figma 1941:212640: the DialogActions row is hidden — the utility\n // rows are the only actions; the flow closes via X or a row.\n showActions={false}\n sx={{\n '& .MuiDialogContent-root': { py: 0 },\n '& .MuiButton-outlined': {\n border: 'none',\n '&:hover': { bgcolor: 'transparent', border: 'none' },\n },\n }}\n >\n <Stack>\n {copy.options.map((option) => {\n const icon = TONE_ICON[option.tone]\n\n return (\n <Stack key={option.label}>\n <Divider />\n <ButtonBase\n onClick={() => handleRowClick(option)}\n sx={{\n alignItems: 'center',\n display: 'flex',\n gap: 12,\n justifyContent: 'flex-start',\n px: 4,\n py: 14,\n textAlign: 'left',\n width: '100%',\n }}\n >\n <Icon name={icon.name} size={24} sx={{ color: icon.color }} />\n <Stack sx={{ flex: 1, minWidth: 0 }}>\n <Text color=\"text.primary\" variant=\"caption\">\n {option.overline}\n </Text>\n <Text sx={{ fontWeight: 600 }} variant=\"body1\">\n {option.label}\n </Text>\n </Stack>\n <Icon name=\"chevron_right\" size={20} sx={{ color: 'text.primary' }} />\n </ButtonBase>\n </Stack>\n )\n })}\n </Stack>\n </Dialog>\n\n {/* Negative path: the whole FeedbackModal — reasons dialog + its own\n success/error snackbars with Try Again. Back returns to the survey;\n its onClose fires only when the sub-flow truly ends. */}\n <FeedbackModal\n copy={{\n title: copy.reasonsTitle,\n options: copy.reasonOptions,\n submitText: copy.submitText,\n cancelText: copy.backText,\n closeAriaLabel: copy.closeAriaLabel,\n characterLimitLabel: copy.characterLimitLabel,\n successMessage: copy.successMessage,\n errorMessage: copy.errorMessage,\n tryAgainText: copy.tryAgainText,\n toastCloseAriaLabel: copy.toastCloseAriaLabel,\n }}\n isOpen={isOpen && phase === 'reasons'}\n onBack={() => setPhase('survey')}\n onClose={() => onClose()}\n onSubmit={onSubmit}\n />\n\n <StatusSnackbar\n actionText={phase === 'error' ? copy.tryAgainText : undefined}\n closeAriaLabel={copy.toastCloseAriaLabel}\n message={phase === 'error' ? copy.errorMessage : copy.successMessage}\n onActionClick={retry}\n onClose={() => onClose()}\n open={isOpen && (phase === 'success' || phase === 'error')}\n severity={phase === 'error' ? 'error' : 'success'}\n />\n </>\n )\n}\n\nexport default SurveyModal\n"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ export interface StatusSnackbarProps {
2
+ open: boolean;
3
+ /** Snackbar tone — success (green, Figma 1941:167636) or error (red, Figma 1941:167637). */
4
+ severity?: 'success' | 'error';
5
+ /** Status description, e.g. "Your feedback has been submitted.". */
6
+ message: string;
7
+ /** ARIA label for the close button. */
8
+ closeAriaLabel: string;
9
+ /** Fired on close / auto-hide. */
10
+ onClose: () => void;
11
+ /**
12
+ * Optional action button label (e.g. "Try Again"). The button renders only
13
+ * when this is provided.
14
+ */
15
+ actionText?: string;
16
+ onActionClick?: () => void;
17
+ /** Auto-hide in ms; defaults to the mxui Toast default (3s). */
18
+ autoHideDuration?: number;
19
+ }
20
+ /**
21
+ * Shared status snackbar for insights-v2 (Figma `<Snackbar>`): a filled
22
+ * success/error toast with a message, a close button, and an optional action
23
+ * (e.g. the feedback modal's Try Again). Thin wrapper over the mxui `Toast`
24
+ * so every surface renders the same Figma variants instead of re-wiring
25
+ * Toast props.
26
+ */
27
+ declare const StatusSnackbar: ({ actionText, autoHideDuration, closeAriaLabel, message, onActionClick, onClose, open, severity, }: StatusSnackbarProps) => import("react/jsx-runtime").JSX.Element;
28
+ export default StatusSnackbar;
@@ -0,0 +1,19 @@
1
+ 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,
8
+ message: a,
9
+ onActionClick: t,
10
+ open: l,
11
+ severity: m,
12
+ showAction: !!s,
13
+ showClose: !0
14
+ });
15
+ export {
16
+ p as default
17
+ };
18
+
19
+ //# sourceMappingURL=StatusSnackbar.es.js.map
@@ -0,0 +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,5 +1,6 @@
1
1
  export * from './blocks';
2
2
  export { default as AccountHeroCard } from './components/AccountHeroCard';
3
+ export { default as ConnectionDetailDrillDown, type ConnectionDetailContent, } from './components/ConnectionDetailDrillDown';
3
4
  export { default as DirectDepositCard, type DirectDepositCardStyleProps, type DirectDepositPillConfig, } from './components/DirectDepositCard';
4
5
  export { default as AmountPill } from './components/AmountPill';
5
6
  export { default as BadgedTile } from './components/BadgedTile';
@@ -22,6 +23,9 @@ export { default as DismissInsightDialog, type DismissInsightDialogProps, type D
22
23
  export { default as HiddenConfirmationCard, type HiddenConfirmationCardProps, } from './components/HiddenConfirmationCard';
23
24
  export { default as FeedbackDialog, type FeedbackDialogCloseReason, type FeedbackDialogProps, } from './components/FeedbackDialog';
24
25
  export { default as FeedbackBar, type FeedbackBarProps } from './components/FeedbackBar';
26
+ export { default as FeedbackModal, type FeedbackModalContent } from './components/FeedbackModal';
27
+ export { default as SurveyModal, type SurveyModalContent, type SurveyModalOption, } from './components/SurveyModal';
28
+ export { default as StatusSnackbar, type StatusSnackbarProps, } from './components/shared/StatusSnackbar';
25
29
  export { ObsolesceBanner, type ObsolesceBannerProps, type ObsolesceBannerState, type ObsolesceBannerCopy, } from './components/ObsolesceBanner';
26
30
  export { HOST_ACTIONS, useBeatCtaActions, useCtaHandler } from './ctaActions';
27
31
  export type { BeatCtaActions, CtaContext, CtaEffect, CtaHandlerName, CtaParams, CtaStateContext, CtaStep, HostActionName, RunHandlerOptions, } from './ctaActions';