@fairmint/ui 0.3.18 → 0.3.20

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 (29) hide show
  1. package/dist/components/generic/Banner/Banner.cjs +3 -1
  2. package/dist/components/generic/Banner/Banner.cjs.map +1 -1
  3. package/dist/components/generic/Banner/Banner.d.ts.map +1 -1
  4. package/dist/components/generic/Banner/Banner.js +3 -1
  5. package/dist/components/generic/Banner/Banner.js.map +1 -1
  6. package/dist/components/generic/NotificationRow/NotificationRow.cjs +169 -0
  7. package/dist/components/generic/NotificationRow/NotificationRow.cjs.map +1 -0
  8. package/dist/components/generic/NotificationRow/NotificationRow.d.ts +51 -0
  9. package/dist/components/generic/NotificationRow/NotificationRow.d.ts.map +1 -0
  10. package/dist/components/generic/NotificationRow/NotificationRow.js +169 -0
  11. package/dist/components/generic/NotificationRow/NotificationRow.js.map +1 -0
  12. package/dist/components/generic/TaskRow/TaskRow.cjs +151 -0
  13. package/dist/components/generic/TaskRow/TaskRow.cjs.map +1 -0
  14. package/dist/components/generic/TaskRow/TaskRow.d.ts +56 -0
  15. package/dist/components/generic/TaskRow/TaskRow.d.ts.map +1 -0
  16. package/dist/components/generic/TaskRow/TaskRow.js +151 -0
  17. package/dist/components/generic/TaskRow/TaskRow.js.map +1 -0
  18. package/dist/components/primitives/Alert/Alert.cjs +6 -0
  19. package/dist/components/primitives/Alert/Alert.cjs.map +1 -1
  20. package/dist/components/primitives/Alert/Alert.d.ts.map +1 -1
  21. package/dist/components/primitives/Alert/Alert.js +6 -0
  22. package/dist/components/primitives/Alert/Alert.js.map +1 -1
  23. package/dist/fairmint-ui.cjs +4 -0
  24. package/dist/fairmint-ui.cjs.map +1 -1
  25. package/dist/fairmint-ui.js +4 -0
  26. package/dist/fairmint-ui.js.map +1 -1
  27. package/dist/index.d.ts +4 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/package.json +1 -1
@@ -0,0 +1,169 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { fairmintVars } from "../../../theme/index.js";
3
+ import { colors } from "../../../theme/colors.js";
4
+ import { ActionIcon } from "../../primitives/ActionIcon/ActionIcon.js";
5
+ import { Badge } from "../../primitives/Badge/Badge.js";
6
+ import { Box, Stack } from "../../primitives/layout.js";
7
+ import { ColorDot } from "../ColorDot/ColorDot.js";
8
+ import { Group } from "../../../node_modules/@mantine/core/esm/components/Group/Group.js";
9
+ import { Text } from "../../../node_modules/@mantine/core/esm/components/Text/Text.js";
10
+ const SEVERITY_BADGE_COLORS = {
11
+ critical: colors.error,
12
+ high: colors.warning,
13
+ medium: colors.info,
14
+ low: colors.neutral,
15
+ info: colors.info,
16
+ success: colors.success,
17
+ resolved: colors.success
18
+ };
19
+ const DEFAULT_SEVERITY_LABELS = {
20
+ critical: "Critical",
21
+ high: "High",
22
+ medium: "Medium",
23
+ low: "Low",
24
+ info: "Info",
25
+ success: "Success",
26
+ resolved: "Completed"
27
+ };
28
+ function DefaultCheckIcon() {
29
+ return /* @__PURE__ */ jsx(
30
+ "svg",
31
+ {
32
+ "aria-hidden": "true",
33
+ width: "16",
34
+ height: "16",
35
+ viewBox: "0 0 24 24",
36
+ fill: "none",
37
+ stroke: "currentColor",
38
+ strokeWidth: "2",
39
+ strokeLinecap: "round",
40
+ strokeLinejoin: "round",
41
+ children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" })
42
+ }
43
+ );
44
+ }
45
+ function DefaultMailIcon() {
46
+ return /* @__PURE__ */ jsxs(
47
+ "svg",
48
+ {
49
+ "aria-hidden": "true",
50
+ width: "16",
51
+ height: "16",
52
+ viewBox: "0 0 24 24",
53
+ fill: "none",
54
+ stroke: "currentColor",
55
+ strokeWidth: "2",
56
+ strokeLinecap: "round",
57
+ strokeLinejoin: "round",
58
+ children: [
59
+ /* @__PURE__ */ jsx("path", { d: "M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" }),
60
+ /* @__PURE__ */ jsx("path", { d: "m22 6-10 7L2 6" })
61
+ ]
62
+ }
63
+ );
64
+ }
65
+ function NotificationRow({
66
+ ariaLabel,
67
+ body,
68
+ className,
69
+ isUnread = false,
70
+ onToggleRead,
71
+ severity = "medium",
72
+ severityLabel,
73
+ timestamp,
74
+ title,
75
+ toggleReadLabel,
76
+ variant = "standalone",
77
+ withDivider = true
78
+ }) {
79
+ const resolvedSeverityLabel = severityLabel ?? DEFAULT_SEVERITY_LABELS[severity];
80
+ const resolvedToggleReadLabel = toggleReadLabel ?? (isUnread ? `Mark read: ${title}` : `Mark unread: ${title}`);
81
+ const readStateLabel = isUnread ? "Unread notification" : "Read notification";
82
+ const resolvedAriaLabel = ariaLabel ?? (timestamp ? `${title}. ${resolvedSeverityLabel}. ${readStateLabel}. ${timestamp}` : `${title}. ${resolvedSeverityLabel}. ${readStateLabel}`);
83
+ const isList = variant === "list";
84
+ const badgeColor = SEVERITY_BADGE_COLORS[severity];
85
+ return /* @__PURE__ */ jsx(
86
+ Box,
87
+ {
88
+ "aria-label": resolvedAriaLabel,
89
+ role: "group",
90
+ className,
91
+ "data-severity": severity,
92
+ "data-testid": "notification-row",
93
+ "data-unread": isUnread || void 0,
94
+ "data-variant": variant,
95
+ px: "md",
96
+ py: "sm",
97
+ w: "100%",
98
+ style: {
99
+ backgroundColor: isUnread ? fairmintVars.colorBgSurface : fairmintVars.colorBgSurfaceSecondary,
100
+ border: isList ? "none" : `1px solid ${fairmintVars.colorBorderDefault}`,
101
+ borderBottom: isList && withDivider ? `1px solid ${fairmintVars.colorBorderDefault}` : void 0,
102
+ borderRadius: isList ? 0 : 10
103
+ },
104
+ children: /* @__PURE__ */ jsxs(Group, { align: "flex-start", gap: "sm", justify: "space-between", wrap: "nowrap", children: [
105
+ /* @__PURE__ */ jsxs(Group, { align: "flex-start", gap: "sm", miw: 0, wrap: "nowrap", style: { flex: 1 }, children: [
106
+ /* @__PURE__ */ jsx(
107
+ Box,
108
+ {
109
+ "aria-hidden": true,
110
+ mt: 6,
111
+ style: {
112
+ flexShrink: 0,
113
+ width: 8,
114
+ display: "flex",
115
+ justifyContent: "center"
116
+ },
117
+ children: /* @__PURE__ */ jsx(
118
+ ColorDot,
119
+ {
120
+ color: isUnread ? fairmintVars.colorBrandPrimary : fairmintVars.colorBorderDisabled,
121
+ size: 8
122
+ }
123
+ )
124
+ }
125
+ ),
126
+ /* @__PURE__ */ jsxs(Stack, { gap: 4, miw: 0, style: { flex: 1 }, children: [
127
+ /* @__PURE__ */ jsx(Badge, { color: badgeColor, size: "xs", variant: "light", children: resolvedSeverityLabel }),
128
+ /* @__PURE__ */ jsx(
129
+ Text,
130
+ {
131
+ fw: isUnread ? 600 : 500,
132
+ lineClamp: 2,
133
+ size: "sm",
134
+ c: fairmintVars.colorTextPrimary,
135
+ style: { minWidth: 0 },
136
+ children: title
137
+ }
138
+ ),
139
+ /* @__PURE__ */ jsx(
140
+ Text,
141
+ {
142
+ c: fairmintVars.colorTextSecondary,
143
+ lineClamp: 3,
144
+ size: "sm",
145
+ style: { minWidth: 0 },
146
+ children: body
147
+ }
148
+ )
149
+ ] })
150
+ ] }),
151
+ onToggleRead ? /* @__PURE__ */ jsx(
152
+ ActionIcon,
153
+ {
154
+ "aria-label": resolvedToggleReadLabel,
155
+ color: colors.neutral,
156
+ onClick: onToggleRead,
157
+ size: "md",
158
+ variant: "subtle",
159
+ children: isUnread ? /* @__PURE__ */ jsx(DefaultCheckIcon, {}) : /* @__PURE__ */ jsx(DefaultMailIcon, {})
160
+ }
161
+ ) : null
162
+ ] })
163
+ }
164
+ );
165
+ }
166
+ export {
167
+ NotificationRow
168
+ };
169
+ //# sourceMappingURL=NotificationRow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationRow.js","sources":["../../../../src/components/generic/NotificationRow/NotificationRow.tsx"],"sourcesContent":["import { fairmintVars } from \"../../../theme\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Badge } from \"../../primitives/Badge/Badge\";\nimport { Box, Group, Stack, Text } from \"../../primitives/layout\";\nimport { ColorDot } from \"../ColorDot/ColorDot\";\n\nexport type NotificationRowSeverity =\n | \"critical\"\n | \"high\"\n | \"medium\"\n | \"low\"\n | \"info\"\n | \"success\"\n | \"resolved\";\n\nexport type NotificationRowVariant = \"standalone\" | \"list\";\n\nexport interface NotificationRowProps {\n /** Whether the notification is unread. @default false */\n isUnread?: boolean;\n /** Severity shown as a pill above the title. @default \"medium\" */\n severity?: NotificationRowSeverity;\n /**\n * Severity pill label. Defaults to the capitalized severity name\n * (for example, \"Critical\", \"High\", \"Completed\" for resolved).\n */\n severityLabel?: string;\n /** Primary notification title. */\n title: string;\n /** Supporting body copy. */\n body: string;\n /**\n * Caller-formatted timestamp (for example, \"2 hours ago\").\n * Included in the accessible name when provided; not shown in the row body.\n */\n timestamp?: string;\n /**\n * Toggle read/unread handler. Renders a mark-read icon action on the right.\n * Unread rows show a check icon; read rows show an envelope icon.\n */\n onToggleRead?: () => void;\n /** Accessible label for the toggle-read control. */\n toggleReadLabel?: string;\n /**\n * Layout presentation. Use `list` inside a shared bordered stack so rows\n * sit flush with no card gaps. @default \"standalone\"\n */\n variant?: NotificationRowVariant;\n /**\n * When `variant=\"list\"`, draw a bottom divider. Set false on the last row.\n * @default true\n */\n withDivider?: boolean;\n /** Accessible label for the row. Defaults to title plus read state. */\n ariaLabel?: string;\n className?: string;\n}\n\nconst SEVERITY_BADGE_COLORS: Record<NotificationRowSeverity, string> = {\n critical: colors.error,\n high: colors.warning,\n medium: colors.info,\n low: colors.neutral,\n info: colors.info,\n success: colors.success,\n resolved: colors.success,\n};\n\nconst DEFAULT_SEVERITY_LABELS: Record<NotificationRowSeverity, string> = {\n critical: \"Critical\",\n high: \"High\",\n medium: \"Medium\",\n low: \"Low\",\n info: \"Info\",\n success: \"Success\",\n resolved: \"Completed\",\n};\n\nfunction DefaultCheckIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\nfunction DefaultMailIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z\" />\n <path d=\"m22 6-10 7L2 6\" />\n </svg>\n );\n}\n\n/**\n * Presentational notification row for bell/inbox surfaces.\n *\n * Owns read/unread dot, severity pill, title, body, and a mark-read icon\n * action. The caller owns routing, dedupe, and domain resolution — toggling\n * read state silences awareness only; it never completes related work.\n */\nexport function NotificationRow({\n ariaLabel,\n body,\n className,\n isUnread = false,\n onToggleRead,\n severity = \"medium\",\n severityLabel,\n timestamp,\n title,\n toggleReadLabel,\n variant = \"standalone\",\n withDivider = true,\n}: NotificationRowProps) {\n const resolvedSeverityLabel = severityLabel ?? DEFAULT_SEVERITY_LABELS[severity];\n const resolvedToggleReadLabel =\n toggleReadLabel ?? (isUnread ? `Mark read: ${title}` : `Mark unread: ${title}`);\n const readStateLabel = isUnread ? \"Unread notification\" : \"Read notification\";\n const resolvedAriaLabel =\n ariaLabel ??\n (timestamp\n ? `${title}. ${resolvedSeverityLabel}. ${readStateLabel}. ${timestamp}`\n : `${title}. ${resolvedSeverityLabel}. ${readStateLabel}`);\n const isList = variant === \"list\";\n const badgeColor = SEVERITY_BADGE_COLORS[severity];\n\n return (\n <Box\n aria-label={resolvedAriaLabel}\n role=\"group\"\n className={className}\n data-severity={severity}\n data-testid=\"notification-row\"\n data-unread={isUnread || undefined}\n data-variant={variant}\n px=\"md\"\n py=\"sm\"\n w=\"100%\"\n style={{\n backgroundColor: isUnread\n ? fairmintVars.colorBgSurface\n : fairmintVars.colorBgSurfaceSecondary,\n border: isList ? \"none\" : `1px solid ${fairmintVars.colorBorderDefault}`,\n borderBottom:\n isList && withDivider ? `1px solid ${fairmintVars.colorBorderDefault}` : undefined,\n borderRadius: isList ? 0 : 10,\n }}\n >\n <Group align=\"flex-start\" gap=\"sm\" justify=\"space-between\" wrap=\"nowrap\">\n <Group align=\"flex-start\" gap=\"sm\" miw={0} wrap=\"nowrap\" style={{ flex: 1 }}>\n <Box\n aria-hidden\n mt={6}\n style={{\n flexShrink: 0,\n width: 8,\n display: \"flex\",\n justifyContent: \"center\",\n }}\n >\n <ColorDot\n color={isUnread ? fairmintVars.colorBrandPrimary : fairmintVars.colorBorderDisabled}\n size={8}\n />\n </Box>\n\n <Stack gap={4} miw={0} style={{ flex: 1 }}>\n <Badge color={badgeColor} size=\"xs\" variant=\"light\">\n {resolvedSeverityLabel}\n </Badge>\n\n <Text\n fw={isUnread ? 600 : 500}\n lineClamp={2}\n size=\"sm\"\n c={fairmintVars.colorTextPrimary}\n style={{ minWidth: 0 }}\n >\n {title}\n </Text>\n\n <Text\n c={fairmintVars.colorTextSecondary}\n lineClamp={3}\n size=\"sm\"\n style={{ minWidth: 0 }}\n >\n {body}\n </Text>\n </Stack>\n </Group>\n\n {onToggleRead ? (\n <ActionIcon\n aria-label={resolvedToggleReadLabel}\n color={colors.neutral}\n onClick={onToggleRead}\n size=\"md\"\n variant=\"subtle\"\n >\n {isUnread ? <DefaultCheckIcon /> : <DefaultMailIcon />}\n </ActionIcon>\n ) : null}\n </Group>\n </Box>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const index = require("../../../theme/index.cjs");
5
+ const colors = require("../../../theme/colors.cjs");
6
+ const ActionIcon = require("../../primitives/ActionIcon/ActionIcon.cjs");
7
+ const Button = require("../../primitives/Button/Button.cjs");
8
+ const layout = require("../../primitives/layout.cjs");
9
+ const Group = require("../../../node_modules/@mantine/core/esm/components/Group/Group.cjs");
10
+ const Text = require("../../../node_modules/@mantine/core/esm/components/Text/Text.cjs");
11
+ const PRIORITY_SEVERITY_COLORS = {
12
+ critical: index.fairmintVars.colorErrorText,
13
+ // Mid warning ramp (amber) — clearer than warning-text/solid brown vs error red.
14
+ high: "warning.5",
15
+ medium: "warning.5",
16
+ low: index.fairmintVars.colorTextTertiary
17
+ };
18
+ const DEFAULT_PRIORITY_LABELS = {
19
+ critical: "Critical",
20
+ high: "High",
21
+ medium: "Medium",
22
+ low: "Low"
23
+ };
24
+ const CRITICAL_ROW_BACKGROUND = `color-mix(in srgb, ${index.fairmintVars.colorErrorSolid} 18%, ${index.fairmintVars.colorBgSurface})`;
25
+ function DefaultDismissIcon() {
26
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27
+ "svg",
28
+ {
29
+ "aria-hidden": "true",
30
+ width: "14",
31
+ height: "14",
32
+ viewBox: "0 0 24 24",
33
+ fill: "none",
34
+ stroke: "currentColor",
35
+ strokeWidth: "2",
36
+ strokeLinecap: "round",
37
+ strokeLinejoin: "round",
38
+ children: [
39
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18" }),
40
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 6 12 12" })
41
+ ]
42
+ }
43
+ );
44
+ }
45
+ function TaskRow({
46
+ action,
47
+ ariaLabel,
48
+ className,
49
+ description,
50
+ dismissLabel = "Dismiss task",
51
+ onDismiss,
52
+ priority = "medium",
53
+ priorityLabel,
54
+ timingLabel,
55
+ title,
56
+ variant = "standalone",
57
+ withDivider = true
58
+ }) {
59
+ const resolvedSeverityLabel = priorityLabel ?? DEFAULT_PRIORITY_LABELS[priority];
60
+ const resolvedAriaLabel = ariaLabel ?? (timingLabel ? `${title}. ${resolvedSeverityLabel} priority. ${timingLabel}` : `${title}. ${resolvedSeverityLabel} priority`);
61
+ const isCritical = priority === "critical";
62
+ const isList = variant === "list";
63
+ const hasDescription = description.trim().length > 0;
64
+ const { label: actionLabel, ...actionProps } = action;
65
+ return /* @__PURE__ */ jsxRuntime.jsx(
66
+ layout.Box,
67
+ {
68
+ "aria-label": resolvedAriaLabel,
69
+ role: "group",
70
+ className,
71
+ "data-priority": priority,
72
+ "data-testid": "task-row",
73
+ "data-variant": variant,
74
+ px: "sm",
75
+ py: 10,
76
+ w: "100%",
77
+ miw: 0,
78
+ style: {
79
+ background: isCritical ? CRITICAL_ROW_BACKGROUND : index.fairmintVars.colorBgSurface,
80
+ border: isList ? "none" : `1px solid ${index.fairmintVars.colorBorderDefault}`,
81
+ borderBottom: isList && withDivider ? `1px solid ${index.fairmintVars.colorBorderDefault}` : void 0,
82
+ borderRadius: isList ? 0 : 10
83
+ },
84
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Group.Group, { align: "center", gap: "sm", justify: "space-between", wrap: "nowrap", children: [
85
+ /* @__PURE__ */ jsxRuntime.jsxs(layout.Stack, { gap: 4, miw: 0, style: { flex: 1 }, children: [
86
+ /* @__PURE__ */ jsxRuntime.jsx(
87
+ Text.Text,
88
+ {
89
+ "aria-hidden": true,
90
+ c: PRIORITY_SEVERITY_COLORS[priority],
91
+ fw: 650,
92
+ size: "xs",
93
+ style: {
94
+ letterSpacing: "0.03em",
95
+ lineHeight: 1.2,
96
+ textTransform: "uppercase"
97
+ },
98
+ children: resolvedSeverityLabel
99
+ }
100
+ ),
101
+ /* @__PURE__ */ jsxRuntime.jsx(
102
+ Text.Text,
103
+ {
104
+ fw: 600,
105
+ lineClamp: 2,
106
+ size: "sm",
107
+ c: index.fairmintVars.colorTextPrimary,
108
+ style: { minWidth: 0 },
109
+ children: title
110
+ }
111
+ ),
112
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(
113
+ Text.Text,
114
+ {
115
+ c: index.fairmintVars.colorTextSecondary,
116
+ lineClamp: 2,
117
+ size: "sm",
118
+ style: { minWidth: 0 },
119
+ children: description
120
+ }
121
+ ) : null
122
+ ] }),
123
+ /* @__PURE__ */ jsxRuntime.jsxs(Group.Group, { align: "center", gap: "xs", wrap: "nowrap", style: { flexShrink: 0 }, children: [
124
+ /* @__PURE__ */ jsxRuntime.jsx(
125
+ Button.Button,
126
+ {
127
+ ...actionProps,
128
+ color: colors.colors.primary,
129
+ size: "sm",
130
+ variant: isCritical ? "filled" : "light",
131
+ children: actionLabel
132
+ }
133
+ ),
134
+ onDismiss ? /* @__PURE__ */ jsxRuntime.jsx(
135
+ ActionIcon.ActionIcon,
136
+ {
137
+ "aria-label": dismissLabel,
138
+ color: colors.colors.neutral,
139
+ onClick: onDismiss,
140
+ size: "md",
141
+ variant: "subtle",
142
+ children: /* @__PURE__ */ jsxRuntime.jsx(DefaultDismissIcon, {})
143
+ }
144
+ ) : null
145
+ ] })
146
+ ] })
147
+ }
148
+ );
149
+ }
150
+ exports.TaskRow = TaskRow;
151
+ //# sourceMappingURL=TaskRow.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskRow.cjs","sources":["../../../../src/components/generic/TaskRow/TaskRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { fairmintVars } from \"../../../theme\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Button, type ButtonProps } from \"../../primitives/Button/Button\";\nimport { Box, Group, Stack, Text } from \"../../primitives/layout\";\n\nexport type TaskRowPriority = \"critical\" | \"high\" | \"medium\" | \"low\";\n\nexport type TaskRowVariant = \"standalone\" | \"list\";\n\nexport interface TaskRowActionProps\n extends Omit<ButtonProps, \"children\" | \"color\" | \"variant\" | \"size\"> {\n /** Visible primary CTA label. */\n label: ReactNode;\n}\n\nexport interface TaskRowProps {\n /** Priority / urgency affordance. @default \"medium\" */\n priority?: TaskRowPriority;\n /**\n * Severity label shown above the title in uppercase plain text.\n * Defaults to the capitalized priority name (for example, \"Critical\", \"High\").\n */\n priorityLabel?: string;\n /** Task title. */\n title: string;\n /** Supporting description. */\n description: string;\n /**\n * Caller-formatted due date or age (for example, \"Due today\", \"3 days ago\").\n * Included in the accessible name when provided; not shown beside the CTA.\n */\n timingLabel?: string;\n /** Primary workflow CTA. */\n action: TaskRowActionProps;\n /**\n * Layout presentation. Use `list` inside a shared bordered stack so rows\n * sit flush with no card gaps. @default \"standalone\"\n */\n variant?: TaskRowVariant;\n /**\n * When `variant=\"list\"`, draw a bottom divider. Set false on the last row.\n * @default true\n */\n withDivider?: boolean;\n /** Optional dismiss or snooze handler. */\n onDismiss?: () => void;\n /** Accessible label for the dismiss control. @default \"Dismiss task\" */\n dismissLabel?: string;\n /** Accessible label for the row. Defaults to title plus timing when provided. */\n ariaLabel?: string;\n className?: string;\n}\n\nconst PRIORITY_SEVERITY_COLORS = {\n critical: fairmintVars.colorErrorText,\n // Mid warning ramp (amber) — clearer than warning-text/solid brown vs error red.\n high: \"warning.5\",\n medium: \"warning.5\",\n low: fairmintVars.colorTextTertiary,\n} as const;\n\nconst DEFAULT_PRIORITY_LABELS: Record<TaskRowPriority, string> = {\n critical: \"Critical\",\n high: \"High\",\n medium: \"Medium\",\n low: \"Low\",\n};\n\n/** Soft critical tint that stays readable in Light and Dark (avoids solid error-bg in dark). */\nconst CRITICAL_ROW_BACKGROUND = `color-mix(in srgb, ${fairmintVars.colorErrorSolid} 18%, ${fairmintVars.colorBgSurface})`;\n\nfunction DefaultDismissIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n/**\n * Presentational durable-task row for Studio Tasks and future Investor inbox work.\n *\n * Owns uppercase severity text above the title, description, a right-pinned\n * vertically centered `sm` primary CTA, and optional dismiss. Only `critical`\n * priority receives a semantic fill; non-critical rows stay on the neutral\n * list surface. The owning workflow resolves completion; this row does not\n * infer resolution from dismiss.\n */\nexport function TaskRow({\n action,\n ariaLabel,\n className,\n description,\n dismissLabel = \"Dismiss task\",\n onDismiss,\n priority = \"medium\",\n priorityLabel,\n timingLabel,\n title,\n variant = \"standalone\",\n withDivider = true,\n}: TaskRowProps) {\n const resolvedSeverityLabel = priorityLabel ?? DEFAULT_PRIORITY_LABELS[priority];\n const resolvedAriaLabel =\n ariaLabel ??\n (timingLabel\n ? `${title}. ${resolvedSeverityLabel} priority. ${timingLabel}`\n : `${title}. ${resolvedSeverityLabel} priority`);\n const isCritical = priority === \"critical\";\n const isList = variant === \"list\";\n const hasDescription = description.trim().length > 0;\n const { label: actionLabel, ...actionProps } = action;\n\n return (\n <Box\n aria-label={resolvedAriaLabel}\n role=\"group\"\n className={className}\n data-priority={priority}\n data-testid=\"task-row\"\n data-variant={variant}\n px=\"sm\"\n py={10}\n w=\"100%\"\n miw={0}\n style={{\n background: isCritical ? CRITICAL_ROW_BACKGROUND : fairmintVars.colorBgSurface,\n border: isList ? \"none\" : `1px solid ${fairmintVars.colorBorderDefault}`,\n borderBottom:\n isList && withDivider ? `1px solid ${fairmintVars.colorBorderDefault}` : undefined,\n borderRadius: isList ? 0 : 10,\n }}\n >\n <Group align=\"center\" gap=\"sm\" justify=\"space-between\" wrap=\"nowrap\">\n <Stack gap={4} miw={0} style={{ flex: 1 }}>\n <Text\n aria-hidden\n c={PRIORITY_SEVERITY_COLORS[priority]}\n fw={650}\n size=\"xs\"\n style={{\n letterSpacing: \"0.03em\",\n lineHeight: 1.2,\n textTransform: \"uppercase\",\n }}\n >\n {resolvedSeverityLabel}\n </Text>\n\n <Text\n fw={600}\n lineClamp={2}\n size=\"sm\"\n c={fairmintVars.colorTextPrimary}\n style={{ minWidth: 0 }}\n >\n {title}\n </Text>\n\n {hasDescription ? (\n <Text\n c={fairmintVars.colorTextSecondary}\n lineClamp={2}\n size=\"sm\"\n style={{ minWidth: 0 }}\n >\n {description}\n </Text>\n ) : null}\n </Stack>\n\n <Group align=\"center\" gap=\"xs\" wrap=\"nowrap\" style={{ flexShrink: 0 }}>\n <Button\n {...actionProps}\n color={colors.primary}\n size=\"sm\"\n variant={isCritical ? \"filled\" : \"light\"}\n >\n {actionLabel}\n </Button>\n {onDismiss ? (\n <ActionIcon\n aria-label={dismissLabel}\n color={colors.neutral}\n onClick={onDismiss}\n size=\"md\"\n variant=\"subtle\"\n >\n <DefaultDismissIcon />\n </ActionIcon>\n ) : null}\n </Group>\n </Group>\n </Box>\n );\n}\n"],"names":["fairmintVars","jsxs","jsx","Box","Group","Stack","Text","Button","colors","ActionIcon"],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { ReactNode } from 'react';
2
+ import { ButtonProps } from '../../primitives/Button/Button';
3
+ export type TaskRowPriority = "critical" | "high" | "medium" | "low";
4
+ export type TaskRowVariant = "standalone" | "list";
5
+ export interface TaskRowActionProps extends Omit<ButtonProps, "children" | "color" | "variant" | "size"> {
6
+ /** Visible primary CTA label. */
7
+ label: ReactNode;
8
+ }
9
+ export interface TaskRowProps {
10
+ /** Priority / urgency affordance. @default "medium" */
11
+ priority?: TaskRowPriority;
12
+ /**
13
+ * Severity label shown above the title in uppercase plain text.
14
+ * Defaults to the capitalized priority name (for example, "Critical", "High").
15
+ */
16
+ priorityLabel?: string;
17
+ /** Task title. */
18
+ title: string;
19
+ /** Supporting description. */
20
+ description: string;
21
+ /**
22
+ * Caller-formatted due date or age (for example, "Due today", "3 days ago").
23
+ * Included in the accessible name when provided; not shown beside the CTA.
24
+ */
25
+ timingLabel?: string;
26
+ /** Primary workflow CTA. */
27
+ action: TaskRowActionProps;
28
+ /**
29
+ * Layout presentation. Use `list` inside a shared bordered stack so rows
30
+ * sit flush with no card gaps. @default "standalone"
31
+ */
32
+ variant?: TaskRowVariant;
33
+ /**
34
+ * When `variant="list"`, draw a bottom divider. Set false on the last row.
35
+ * @default true
36
+ */
37
+ withDivider?: boolean;
38
+ /** Optional dismiss or snooze handler. */
39
+ onDismiss?: () => void;
40
+ /** Accessible label for the dismiss control. @default "Dismiss task" */
41
+ dismissLabel?: string;
42
+ /** Accessible label for the row. Defaults to title plus timing when provided. */
43
+ ariaLabel?: string;
44
+ className?: string;
45
+ }
46
+ /**
47
+ * Presentational durable-task row for Studio Tasks and future Investor inbox work.
48
+ *
49
+ * Owns uppercase severity text above the title, description, a right-pinned
50
+ * vertically centered `sm` primary CTA, and optional dismiss. Only `critical`
51
+ * priority receives a semantic fill; non-critical rows stay on the neutral
52
+ * list surface. The owning workflow resolves completion; this row does not
53
+ * infer resolution from dismiss.
54
+ */
55
+ export declare function TaskRow({ action, ariaLabel, className, description, dismissLabel, onDismiss, priority, priorityLabel, timingLabel, title, variant, withDivider, }: TaskRowProps): import("react/jsx-runtime").JSX.Element;
56
+ //# sourceMappingURL=TaskRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskRow.d.ts","sourceRoot":"","sources":["../../../../src/components/generic/TaskRow/TaskRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAG1E,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAErE,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;AAEnD,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpE,iCAAiC;IACjC,KAAK,EAAE,SAAS,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,MAAM,EAAE,kBAAkB,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,EACtB,MAAM,EACN,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAA6B,EAC7B,SAAS,EACT,QAAmB,EACnB,aAAa,EACb,WAAW,EACX,KAAK,EACL,OAAsB,EACtB,WAAkB,GACnB,EAAE,YAAY,2CA8Fd"}
@@ -0,0 +1,151 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { fairmintVars } from "../../../theme/index.js";
3
+ import { colors } from "../../../theme/colors.js";
4
+ import { ActionIcon } from "../../primitives/ActionIcon/ActionIcon.js";
5
+ import { Button } from "../../primitives/Button/Button.js";
6
+ import { Box, Stack } from "../../primitives/layout.js";
7
+ import { Group } from "../../../node_modules/@mantine/core/esm/components/Group/Group.js";
8
+ import { Text } from "../../../node_modules/@mantine/core/esm/components/Text/Text.js";
9
+ const PRIORITY_SEVERITY_COLORS = {
10
+ critical: fairmintVars.colorErrorText,
11
+ // Mid warning ramp (amber) — clearer than warning-text/solid brown vs error red.
12
+ high: "warning.5",
13
+ medium: "warning.5",
14
+ low: fairmintVars.colorTextTertiary
15
+ };
16
+ const DEFAULT_PRIORITY_LABELS = {
17
+ critical: "Critical",
18
+ high: "High",
19
+ medium: "Medium",
20
+ low: "Low"
21
+ };
22
+ const CRITICAL_ROW_BACKGROUND = `color-mix(in srgb, ${fairmintVars.colorErrorSolid} 18%, ${fairmintVars.colorBgSurface})`;
23
+ function DefaultDismissIcon() {
24
+ return /* @__PURE__ */ jsxs(
25
+ "svg",
26
+ {
27
+ "aria-hidden": "true",
28
+ width: "14",
29
+ height: "14",
30
+ viewBox: "0 0 24 24",
31
+ fill: "none",
32
+ stroke: "currentColor",
33
+ strokeWidth: "2",
34
+ strokeLinecap: "round",
35
+ strokeLinejoin: "round",
36
+ children: [
37
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
38
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
39
+ ]
40
+ }
41
+ );
42
+ }
43
+ function TaskRow({
44
+ action,
45
+ ariaLabel,
46
+ className,
47
+ description,
48
+ dismissLabel = "Dismiss task",
49
+ onDismiss,
50
+ priority = "medium",
51
+ priorityLabel,
52
+ timingLabel,
53
+ title,
54
+ variant = "standalone",
55
+ withDivider = true
56
+ }) {
57
+ const resolvedSeverityLabel = priorityLabel ?? DEFAULT_PRIORITY_LABELS[priority];
58
+ const resolvedAriaLabel = ariaLabel ?? (timingLabel ? `${title}. ${resolvedSeverityLabel} priority. ${timingLabel}` : `${title}. ${resolvedSeverityLabel} priority`);
59
+ const isCritical = priority === "critical";
60
+ const isList = variant === "list";
61
+ const hasDescription = description.trim().length > 0;
62
+ const { label: actionLabel, ...actionProps } = action;
63
+ return /* @__PURE__ */ jsx(
64
+ Box,
65
+ {
66
+ "aria-label": resolvedAriaLabel,
67
+ role: "group",
68
+ className,
69
+ "data-priority": priority,
70
+ "data-testid": "task-row",
71
+ "data-variant": variant,
72
+ px: "sm",
73
+ py: 10,
74
+ w: "100%",
75
+ miw: 0,
76
+ style: {
77
+ background: isCritical ? CRITICAL_ROW_BACKGROUND : fairmintVars.colorBgSurface,
78
+ border: isList ? "none" : `1px solid ${fairmintVars.colorBorderDefault}`,
79
+ borderBottom: isList && withDivider ? `1px solid ${fairmintVars.colorBorderDefault}` : void 0,
80
+ borderRadius: isList ? 0 : 10
81
+ },
82
+ children: /* @__PURE__ */ jsxs(Group, { align: "center", gap: "sm", justify: "space-between", wrap: "nowrap", children: [
83
+ /* @__PURE__ */ jsxs(Stack, { gap: 4, miw: 0, style: { flex: 1 }, children: [
84
+ /* @__PURE__ */ jsx(
85
+ Text,
86
+ {
87
+ "aria-hidden": true,
88
+ c: PRIORITY_SEVERITY_COLORS[priority],
89
+ fw: 650,
90
+ size: "xs",
91
+ style: {
92
+ letterSpacing: "0.03em",
93
+ lineHeight: 1.2,
94
+ textTransform: "uppercase"
95
+ },
96
+ children: resolvedSeverityLabel
97
+ }
98
+ ),
99
+ /* @__PURE__ */ jsx(
100
+ Text,
101
+ {
102
+ fw: 600,
103
+ lineClamp: 2,
104
+ size: "sm",
105
+ c: fairmintVars.colorTextPrimary,
106
+ style: { minWidth: 0 },
107
+ children: title
108
+ }
109
+ ),
110
+ hasDescription ? /* @__PURE__ */ jsx(
111
+ Text,
112
+ {
113
+ c: fairmintVars.colorTextSecondary,
114
+ lineClamp: 2,
115
+ size: "sm",
116
+ style: { minWidth: 0 },
117
+ children: description
118
+ }
119
+ ) : null
120
+ ] }),
121
+ /* @__PURE__ */ jsxs(Group, { align: "center", gap: "xs", wrap: "nowrap", style: { flexShrink: 0 }, children: [
122
+ /* @__PURE__ */ jsx(
123
+ Button,
124
+ {
125
+ ...actionProps,
126
+ color: colors.primary,
127
+ size: "sm",
128
+ variant: isCritical ? "filled" : "light",
129
+ children: actionLabel
130
+ }
131
+ ),
132
+ onDismiss ? /* @__PURE__ */ jsx(
133
+ ActionIcon,
134
+ {
135
+ "aria-label": dismissLabel,
136
+ color: colors.neutral,
137
+ onClick: onDismiss,
138
+ size: "md",
139
+ variant: "subtle",
140
+ children: /* @__PURE__ */ jsx(DefaultDismissIcon, {})
141
+ }
142
+ ) : null
143
+ ] })
144
+ ] })
145
+ }
146
+ );
147
+ }
148
+ export {
149
+ TaskRow
150
+ };
151
+ //# sourceMappingURL=TaskRow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskRow.js","sources":["../../../../src/components/generic/TaskRow/TaskRow.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { fairmintVars } from \"../../../theme\";\nimport { colors } from \"../../../theme/colors\";\nimport { ActionIcon } from \"../../primitives/ActionIcon/ActionIcon\";\nimport { Button, type ButtonProps } from \"../../primitives/Button/Button\";\nimport { Box, Group, Stack, Text } from \"../../primitives/layout\";\n\nexport type TaskRowPriority = \"critical\" | \"high\" | \"medium\" | \"low\";\n\nexport type TaskRowVariant = \"standalone\" | \"list\";\n\nexport interface TaskRowActionProps\n extends Omit<ButtonProps, \"children\" | \"color\" | \"variant\" | \"size\"> {\n /** Visible primary CTA label. */\n label: ReactNode;\n}\n\nexport interface TaskRowProps {\n /** Priority / urgency affordance. @default \"medium\" */\n priority?: TaskRowPriority;\n /**\n * Severity label shown above the title in uppercase plain text.\n * Defaults to the capitalized priority name (for example, \"Critical\", \"High\").\n */\n priorityLabel?: string;\n /** Task title. */\n title: string;\n /** Supporting description. */\n description: string;\n /**\n * Caller-formatted due date or age (for example, \"Due today\", \"3 days ago\").\n * Included in the accessible name when provided; not shown beside the CTA.\n */\n timingLabel?: string;\n /** Primary workflow CTA. */\n action: TaskRowActionProps;\n /**\n * Layout presentation. Use `list` inside a shared bordered stack so rows\n * sit flush with no card gaps. @default \"standalone\"\n */\n variant?: TaskRowVariant;\n /**\n * When `variant=\"list\"`, draw a bottom divider. Set false on the last row.\n * @default true\n */\n withDivider?: boolean;\n /** Optional dismiss or snooze handler. */\n onDismiss?: () => void;\n /** Accessible label for the dismiss control. @default \"Dismiss task\" */\n dismissLabel?: string;\n /** Accessible label for the row. Defaults to title plus timing when provided. */\n ariaLabel?: string;\n className?: string;\n}\n\nconst PRIORITY_SEVERITY_COLORS = {\n critical: fairmintVars.colorErrorText,\n // Mid warning ramp (amber) — clearer than warning-text/solid brown vs error red.\n high: \"warning.5\",\n medium: \"warning.5\",\n low: fairmintVars.colorTextTertiary,\n} as const;\n\nconst DEFAULT_PRIORITY_LABELS: Record<TaskRowPriority, string> = {\n critical: \"Critical\",\n high: \"High\",\n medium: \"Medium\",\n low: \"Low\",\n};\n\n/** Soft critical tint that stays readable in Light and Dark (avoids solid error-bg in dark). */\nconst CRITICAL_ROW_BACKGROUND = `color-mix(in srgb, ${fairmintVars.colorErrorSolid} 18%, ${fairmintVars.colorBgSurface})`;\n\nfunction DefaultDismissIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n/**\n * Presentational durable-task row for Studio Tasks and future Investor inbox work.\n *\n * Owns uppercase severity text above the title, description, a right-pinned\n * vertically centered `sm` primary CTA, and optional dismiss. Only `critical`\n * priority receives a semantic fill; non-critical rows stay on the neutral\n * list surface. The owning workflow resolves completion; this row does not\n * infer resolution from dismiss.\n */\nexport function TaskRow({\n action,\n ariaLabel,\n className,\n description,\n dismissLabel = \"Dismiss task\",\n onDismiss,\n priority = \"medium\",\n priorityLabel,\n timingLabel,\n title,\n variant = \"standalone\",\n withDivider = true,\n}: TaskRowProps) {\n const resolvedSeverityLabel = priorityLabel ?? DEFAULT_PRIORITY_LABELS[priority];\n const resolvedAriaLabel =\n ariaLabel ??\n (timingLabel\n ? `${title}. ${resolvedSeverityLabel} priority. ${timingLabel}`\n : `${title}. ${resolvedSeverityLabel} priority`);\n const isCritical = priority === \"critical\";\n const isList = variant === \"list\";\n const hasDescription = description.trim().length > 0;\n const { label: actionLabel, ...actionProps } = action;\n\n return (\n <Box\n aria-label={resolvedAriaLabel}\n role=\"group\"\n className={className}\n data-priority={priority}\n data-testid=\"task-row\"\n data-variant={variant}\n px=\"sm\"\n py={10}\n w=\"100%\"\n miw={0}\n style={{\n background: isCritical ? CRITICAL_ROW_BACKGROUND : fairmintVars.colorBgSurface,\n border: isList ? \"none\" : `1px solid ${fairmintVars.colorBorderDefault}`,\n borderBottom:\n isList && withDivider ? `1px solid ${fairmintVars.colorBorderDefault}` : undefined,\n borderRadius: isList ? 0 : 10,\n }}\n >\n <Group align=\"center\" gap=\"sm\" justify=\"space-between\" wrap=\"nowrap\">\n <Stack gap={4} miw={0} style={{ flex: 1 }}>\n <Text\n aria-hidden\n c={PRIORITY_SEVERITY_COLORS[priority]}\n fw={650}\n size=\"xs\"\n style={{\n letterSpacing: \"0.03em\",\n lineHeight: 1.2,\n textTransform: \"uppercase\",\n }}\n >\n {resolvedSeverityLabel}\n </Text>\n\n <Text\n fw={600}\n lineClamp={2}\n size=\"sm\"\n c={fairmintVars.colorTextPrimary}\n style={{ minWidth: 0 }}\n >\n {title}\n </Text>\n\n {hasDescription ? (\n <Text\n c={fairmintVars.colorTextSecondary}\n lineClamp={2}\n size=\"sm\"\n style={{ minWidth: 0 }}\n >\n {description}\n </Text>\n ) : null}\n </Stack>\n\n <Group align=\"center\" gap=\"xs\" wrap=\"nowrap\" style={{ flexShrink: 0 }}>\n <Button\n {...actionProps}\n color={colors.primary}\n size=\"sm\"\n variant={isCritical ? \"filled\" : \"light\"}\n >\n {actionLabel}\n </Button>\n {onDismiss ? (\n <ActionIcon\n aria-label={dismissLabel}\n color={colors.neutral}\n onClick={onDismiss}\n size=\"md\"\n variant=\"subtle\"\n >\n <DefaultDismissIcon />\n </ActionIcon>\n ) : null}\n </Group>\n </Group>\n </Box>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -132,6 +132,10 @@ function Alert({
132
132
  // Slightly more room on the trailing edge than Mantine's symmetric md.
133
133
  paddingInlineEnd: spacing.spacing.lg
134
134
  },
135
+ // Top-align the icon with the title rather than centering against multi-line body.
136
+ wrapper: {
137
+ alignItems: "flex-start"
138
+ },
135
139
  body: {
136
140
  // Tighter than Mantine's default spacing.xs between title and body.
137
141
  gap: "0.25rem"
@@ -163,6 +167,7 @@ function Alert({
163
167
  ...surfaceStyles,
164
168
  ...resolved,
165
169
  root: mergePart("root", resolved.root),
170
+ wrapper: mergePart("wrapper", resolved.wrapper),
166
171
  body: mergePart("body", resolved.body),
167
172
  title: mergePart("title", resolved.title),
168
173
  label: mergePart("label", resolved.label),
@@ -173,6 +178,7 @@ function Alert({
173
178
  ...surfaceStyles,
174
179
  ...styles,
175
180
  root: mergePart("root", styles?.root),
181
+ wrapper: mergePart("wrapper", styles?.wrapper),
176
182
  body: mergePart("body", styles?.body),
177
183
  title: mergePart("title", styles?.title),
178
184
  label: mergePart("label", styles?.label),