pixelize-design-library 3.0.0 → 3.1.0

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 (176) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/COMPONENT-GOTCHAS.md +37 -13
  3. package/DESIGN-GUIDE.md +4 -1
  4. package/dist/Components/NotificationBell/NotificationBellProps.d.ts +3 -3
  5. package/dist/Components/NotificationBell/NotificationItem.d.ts +1 -1
  6. package/dist/Components/NotificationBell/NotificationItem.js +1 -1
  7. package/dist/Components/NotificationBell/NotificationList.d.ts +1 -1
  8. package/dist/Components/NotificationBell/NotificationList.js +1 -1
  9. package/dist/Components/NotificationBell/NotificationPanel.d.ts +1 -1
  10. package/dist/Components/NotificationBell/NotificationPanel.js +1 -1
  11. package/dist/Components/NotificationCenter/center/CenterPanel.d.ts +15 -0
  12. package/dist/Components/NotificationCenter/center/CenterPanel.js +87 -0
  13. package/dist/Components/NotificationCenter/center/NotificationCenter.d.ts +4 -0
  14. package/dist/Components/NotificationCenter/center/NotificationCenter.js +130 -0
  15. package/dist/Components/NotificationCenter/center/NotificationCenterProps.d.ts +71 -0
  16. package/dist/Components/NotificationCenter/center/NotificationCenterProps.js +2 -0
  17. package/dist/Components/NotificationCenter/center/PanelRows.d.ts +10 -0
  18. package/dist/Components/NotificationCenter/center/PanelRows.js +35 -0
  19. package/dist/Components/NotificationCenter/center/PanelStates.d.ts +17 -0
  20. package/dist/Components/NotificationCenter/center/PanelStates.js +21 -0
  21. package/dist/Components/NotificationCenter/center/centerLabels.d.ts +4 -0
  22. package/dist/Components/NotificationCenter/center/centerLabels.js +38 -0
  23. package/dist/Components/NotificationCenter/center/useArrivals.d.ts +14 -0
  24. package/dist/Components/NotificationCenter/center/useArrivals.js +71 -0
  25. package/dist/Components/NotificationCenter/center/useIsSheet.d.ts +2 -0
  26. package/dist/Components/NotificationCenter/center/useIsSheet.js +20 -0
  27. package/dist/Components/NotificationCenter/core/NotificationCenterProvider.d.ts +17 -0
  28. package/dist/Components/NotificationCenter/core/NotificationCenterProvider.js +46 -0
  29. package/dist/Components/NotificationCenter/core/NotificationEngineProps.d.ts +182 -0
  30. package/dist/Components/NotificationCenter/core/NotificationEngineProps.js +2 -0
  31. package/dist/Components/NotificationCenter/core/NotificationSourceProps.d.ts +284 -0
  32. package/dist/Components/NotificationCenter/core/NotificationSourceProps.js +2 -0
  33. package/dist/Components/NotificationCenter/core/actionError.d.ts +4 -0
  34. package/dist/Components/NotificationCenter/core/actionError.js +45 -0
  35. package/dist/Components/NotificationCenter/core/format.d.ts +4 -0
  36. package/dist/Components/NotificationCenter/core/format.js +91 -0
  37. package/dist/Components/NotificationCenter/core/grouping.d.ts +14 -0
  38. package/dist/Components/NotificationCenter/core/grouping.js +102 -0
  39. package/dist/Components/NotificationCenter/core/labels.d.ts +6 -0
  40. package/dist/Components/NotificationCenter/core/labels.js +94 -0
  41. package/dist/Components/NotificationCenter/core/overlay.d.ts +109 -0
  42. package/dist/Components/NotificationCenter/core/overlay.js +281 -0
  43. package/dist/Components/NotificationCenter/core/useNotificationEngine.d.ts +13 -0
  44. package/dist/Components/NotificationCenter/core/useNotificationEngine.js +415 -0
  45. package/dist/Components/NotificationCenter/inbox/InboxList.d.ts +17 -0
  46. package/dist/Components/NotificationCenter/inbox/InboxList.js +25 -0
  47. package/dist/Components/NotificationCenter/inbox/InboxStates.d.ts +17 -0
  48. package/dist/Components/NotificationCenter/inbox/InboxStates.js +27 -0
  49. package/dist/Components/NotificationCenter/inbox/NotificationInbox.d.ts +4 -0
  50. package/dist/Components/NotificationCenter/inbox/NotificationInbox.js +434 -0
  51. package/dist/Components/NotificationCenter/inbox/NotificationInboxProps.d.ts +106 -0
  52. package/dist/Components/NotificationCenter/inbox/NotificationInboxProps.js +2 -0
  53. package/dist/Components/NotificationCenter/inbox/ShortcutsDialog.d.ts +8 -0
  54. package/dist/Components/NotificationCenter/inbox/ShortcutsDialog.js +63 -0
  55. package/dist/Components/NotificationCenter/inbox/inboxLabels.d.ts +4 -0
  56. package/dist/Components/NotificationCenter/inbox/inboxLabels.js +56 -0
  57. package/dist/Components/NotificationCenter/inbox/inboxModel.d.ts +17 -0
  58. package/dist/Components/NotificationCenter/inbox/inboxModel.js +47 -0
  59. package/dist/Components/NotificationCenter/inbox/useControllable.d.ts +1 -0
  60. package/dist/Components/NotificationCenter/inbox/useControllable.js +15 -0
  61. package/dist/Components/NotificationCenter/index.d.ts +8 -0
  62. package/dist/Components/NotificationCenter/index.js +26 -0
  63. package/dist/Components/NotificationCenter/preferences/NotificationPreferences.d.ts +4 -0
  64. package/dist/Components/NotificationCenter/preferences/NotificationPreferences.js +72 -0
  65. package/dist/Components/NotificationCenter/preferences/NotificationPreferencesProps.d.ts +111 -0
  66. package/dist/Components/NotificationCenter/preferences/NotificationPreferencesProps.js +2 -0
  67. package/dist/Components/NotificationCenter/preferences/PreferenceCells.d.ts +16 -0
  68. package/dist/Components/NotificationCenter/preferences/PreferenceCells.js +35 -0
  69. package/dist/Components/NotificationCenter/preferences/PreferenceGroups.d.ts +15 -0
  70. package/dist/Components/NotificationCenter/preferences/PreferenceGroups.js +26 -0
  71. package/dist/Components/NotificationCenter/preferences/preferencesLabels.d.ts +2 -0
  72. package/dist/Components/NotificationCenter/preferences/preferencesLabels.js +28 -0
  73. package/dist/Components/NotificationCenter/preferences/useAutosave.d.ts +8 -0
  74. package/dist/Components/NotificationCenter/preferences/useAutosave.js +41 -0
  75. package/dist/Components/NotificationCenter/row/NotificationDetail.d.ts +4 -0
  76. package/dist/Components/NotificationCenter/row/NotificationDetail.js +65 -0
  77. package/dist/Components/NotificationCenter/row/NotificationDetailProps.d.ts +15 -0
  78. package/dist/Components/NotificationCenter/row/NotificationDetailProps.js +2 -0
  79. package/dist/Components/NotificationCenter/row/NotificationRow.d.ts +3 -0
  80. package/dist/Components/NotificationCenter/row/NotificationRow.js +124 -0
  81. package/dist/Components/NotificationCenter/row/NotificationRowProps.d.ts +33 -0
  82. package/dist/Components/NotificationCenter/row/NotificationRowProps.js +2 -0
  83. package/dist/Components/NotificationCenter/row/ReasonForm.d.ts +14 -0
  84. package/dist/Components/NotificationCenter/row/ReasonForm.js +59 -0
  85. package/dist/Components/NotificationCenter/row/RowActions.d.ts +16 -0
  86. package/dist/Components/NotificationCenter/row/RowActions.js +36 -0
  87. package/dist/Components/NotificationCenter/row/RowQuickActions.d.ts +17 -0
  88. package/dist/Components/NotificationCenter/row/RowQuickActions.js +57 -0
  89. package/dist/Components/NotificationCenter/row/RowStatus.d.ts +10 -0
  90. package/dist/Components/NotificationCenter/row/RowStatus.js +42 -0
  91. package/dist/Components/NotificationCenter/row/category.d.ts +8 -0
  92. package/dist/Components/NotificationCenter/row/category.js +13 -0
  93. package/dist/Components/NotificationCenter/row/rowMenu.d.ts +14 -0
  94. package/dist/Components/NotificationCenter/row/rowMenu.js +37 -0
  95. package/dist/Components/NotificationCenter/row/rowParts.d.ts +40 -0
  96. package/dist/Components/NotificationCenter/row/rowParts.js +72 -0
  97. package/dist/Components/NotificationCenter/row/rowStyles.d.ts +11 -0
  98. package/dist/Components/NotificationCenter/row/rowStyles.js +25 -0
  99. package/dist/Components/SegmentedControl/segmentedInk.d.ts +4 -0
  100. package/dist/Components/SegmentedControl/segmentedInk.js +16 -2
  101. package/dist/Components/SideBar/SecondaryBar.js +2 -2
  102. package/dist/Components/SideBar/SideBar.js +18 -8
  103. package/dist/Components/SideBar/SideBarProps.d.ts +4 -2
  104. package/dist/Components/SideBar/components/MenuItemBox.d.ts +0 -2
  105. package/dist/Components/SideBar/components/MenuItemBox.js +2 -3
  106. package/dist/Components/SideBar/components/MenuItems.js +2 -2
  107. package/dist/Components/SideBar/components/PinnedSection.js +3 -4
  108. package/dist/Components/SideBar/sidebarScale.d.ts +0 -2
  109. package/dist/Components/SideBar/sidebarScale.js +0 -2
  110. package/dist/Components/Switch/Switch.d.ts +1 -1
  111. package/dist/Components/Switch/Switch.js +2 -2
  112. package/dist/Components/Switch/SwitchProps.d.ts +3 -0
  113. package/dist/Components/Toggle/TableToggle.js +4 -5
  114. package/dist/Components/Toggle/tableToggleInk.d.ts +7 -0
  115. package/dist/Components/Toggle/tableToggleInk.js +28 -0
  116. package/dist/esm/Components/NotificationBell/NotificationItem.js +1 -1
  117. package/dist/esm/Components/NotificationBell/NotificationList.js +1 -1
  118. package/dist/esm/Components/NotificationBell/NotificationPanel.js +1 -1
  119. package/dist/esm/Components/NotificationCenter/center/CenterPanel.js +81 -0
  120. package/dist/esm/Components/NotificationCenter/center/NotificationCenter.js +92 -0
  121. package/dist/esm/Components/NotificationCenter/center/NotificationCenterProps.js +1 -0
  122. package/dist/esm/Components/NotificationCenter/center/PanelRows.js +28 -0
  123. package/dist/esm/Components/NotificationCenter/center/PanelStates.js +11 -0
  124. package/dist/esm/Components/NotificationCenter/center/centerLabels.js +34 -0
  125. package/dist/esm/Components/NotificationCenter/center/useArrivals.js +67 -0
  126. package/dist/esm/Components/NotificationCenter/center/useIsSheet.js +16 -0
  127. package/dist/esm/Components/NotificationCenter/core/NotificationCenterProvider.js +35 -0
  128. package/dist/esm/Components/NotificationCenter/core/NotificationEngineProps.js +1 -0
  129. package/dist/esm/Components/NotificationCenter/core/NotificationSourceProps.js +1 -0
  130. package/dist/esm/Components/NotificationCenter/core/actionError.js +39 -0
  131. package/dist/esm/Components/NotificationCenter/core/format.js +87 -0
  132. package/dist/esm/Components/NotificationCenter/core/grouping.js +88 -0
  133. package/dist/esm/Components/NotificationCenter/core/labels.js +88 -0
  134. package/dist/esm/Components/NotificationCenter/core/overlay.js +274 -0
  135. package/dist/esm/Components/NotificationCenter/core/useNotificationEngine.js +408 -0
  136. package/dist/esm/Components/NotificationCenter/inbox/InboxList.js +18 -0
  137. package/dist/esm/Components/NotificationCenter/inbox/InboxStates.js +18 -0
  138. package/dist/esm/Components/NotificationCenter/inbox/NotificationInbox.js +396 -0
  139. package/dist/esm/Components/NotificationCenter/inbox/NotificationInboxProps.js +1 -0
  140. package/dist/esm/Components/NotificationCenter/inbox/ShortcutsDialog.js +23 -0
  141. package/dist/esm/Components/NotificationCenter/inbox/inboxLabels.js +52 -0
  142. package/dist/esm/Components/NotificationCenter/inbox/inboxModel.js +37 -0
  143. package/dist/esm/Components/NotificationCenter/inbox/useControllable.js +11 -0
  144. package/dist/esm/Components/NotificationCenter/index.js +8 -0
  145. package/dist/esm/Components/NotificationCenter/preferences/NotificationPreferences.js +67 -0
  146. package/dist/esm/Components/NotificationCenter/preferences/NotificationPreferencesProps.js +1 -0
  147. package/dist/esm/Components/NotificationCenter/preferences/PreferenceCells.js +27 -0
  148. package/dist/esm/Components/NotificationCenter/preferences/PreferenceGroups.js +21 -0
  149. package/dist/esm/Components/NotificationCenter/preferences/preferencesLabels.js +24 -0
  150. package/dist/esm/Components/NotificationCenter/preferences/useAutosave.js +37 -0
  151. package/dist/esm/Components/NotificationCenter/row/NotificationDetail.js +60 -0
  152. package/dist/esm/Components/NotificationCenter/row/NotificationDetailProps.js +1 -0
  153. package/dist/esm/Components/NotificationCenter/row/NotificationRow.js +119 -0
  154. package/dist/esm/Components/NotificationCenter/row/NotificationRowProps.js +1 -0
  155. package/dist/esm/Components/NotificationCenter/row/ReasonForm.js +52 -0
  156. package/dist/esm/Components/NotificationCenter/row/RowActions.js +28 -0
  157. package/dist/esm/Components/NotificationCenter/row/RowQuickActions.js +49 -0
  158. package/dist/esm/Components/NotificationCenter/row/RowStatus.js +35 -0
  159. package/dist/esm/Components/NotificationCenter/row/category.js +9 -0
  160. package/dist/esm/Components/NotificationCenter/row/rowMenu.js +30 -0
  161. package/dist/esm/Components/NotificationCenter/row/rowParts.js +59 -0
  162. package/dist/esm/Components/NotificationCenter/row/rowStyles.js +19 -0
  163. package/dist/esm/Components/SegmentedControl/segmentedInk.js +15 -2
  164. package/dist/esm/Components/SideBar/SecondaryBar.js +3 -3
  165. package/dist/esm/Components/SideBar/SideBar.js +18 -8
  166. package/dist/esm/Components/SideBar/components/MenuItemBox.js +2 -3
  167. package/dist/esm/Components/SideBar/components/MenuItems.js +2 -2
  168. package/dist/esm/Components/SideBar/components/PinnedSection.js +3 -4
  169. package/dist/esm/Components/SideBar/sidebarScale.js +0 -2
  170. package/dist/esm/Components/Switch/Switch.js +2 -2
  171. package/dist/esm/Components/Toggle/TableToggle.js +4 -5
  172. package/dist/esm/Components/Toggle/tableToggleInk.js +24 -0
  173. package/dist/esm/index.js +1 -0
  174. package/dist/index.d.ts +8 -0
  175. package/dist/index.js +16 -3
  176. package/package.json +1 -1
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const react_2 = require("@chakra-ui/react");
9
+ const lucide_react_1 = require("lucide-react");
10
+ const Primitives_1 = require("../../Primitives/Primitives");
11
+ const Avatar_1 = __importDefault(require("../../Avatar/Avatar"));
12
+ const Button_1 = __importDefault(require("../../Button/Button"));
13
+ const DescriptionList_1 = __importDefault(require("../../DescriptionList/DescriptionList"));
14
+ const EmptyState_1 = __importDefault(require("../../EmptyState/EmptyState"));
15
+ const Tag_1 = __importDefault(require("../../Tag/Tag"));
16
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
17
+ const focusRing_styles_1 = require("../../../Theme/chakra/focusRing.styles");
18
+ const planeStep_1 = require("../../../Theme/tokens/builders/planeStep");
19
+ const borderWidths_1 = require("../../../Theme/tokens/primitives/borderWidths");
20
+ const radii_1 = require("../../../Theme/tokens/primitives/radii");
21
+ const NotificationCenterProvider_1 = require("../core/NotificationCenterProvider");
22
+ const category_1 = require("./category");
23
+ const ReasonForm_1 = require("./ReasonForm");
24
+ const RowActions_1 = require("./RowActions");
25
+ const RowStatus_1 = require("./RowStatus");
26
+ const rowParts_1 = require("./rowParts");
27
+ const rowMenu_1 = require("./rowMenu");
28
+ const rowStyles_1 = require("./rowStyles");
29
+ /** One notification in full for a reading pane or a phone screen; text only, never markup. */
30
+ const NotificationDetail = ({ item, variant = "desktop", onBack, titleRef }) => {
31
+ var _a, _b, _c;
32
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
33
+ const shared = (0, NotificationCenterProvider_1.useNotificationShared)();
34
+ const { labels, format, now, categories, features, isOffline, appName, actions } = shared;
35
+ const { entry, state } = item;
36
+ const titleId = (0, react_1.useId)();
37
+ const [asking, setAsking] = (0, react_1.useState)(null);
38
+ const isPhone = variant === "phone";
39
+ const size = isPhone ? "md" : "sm";
40
+ const iconPx = (0, rowStyles_1.iconSizeFor)(size);
41
+ const category = (0, category_1.categoryFor)(categories, entry.category, labels.otherCategory);
42
+ const tile = (0, rowParts_1.useToneTile)(category.tone);
43
+ const isUnread = entry.isRead === false;
44
+ const actionList = (0, rowMenu_1.visibleActionsFor)(entry, features);
45
+ const decides = actionList.some(rowMenu_1.isDecision);
46
+ const days = format.daysSince(entry.createdAt, now);
47
+ const isWaiting = state.zone === "needsYou" && decides && days >= rowStyles_1.WAITING_AFTER_DAYS;
48
+ const request = state.reasonRequest;
49
+ const askingAction = asking && asking.id === entry.id ? asking.action : undefined;
50
+ const requested = request ? actionList.find((action) => action.id === request.actionId) : undefined;
51
+ const formAction = state.status === "open" ? (askingAction !== null && askingAction !== void 0 ? askingAction : requested) : undefined;
52
+ const isQuiet = state.status === "open";
53
+ const plane = colors.surfaceRaised;
54
+ const closeForm = () => {
55
+ setAsking(null);
56
+ if (request)
57
+ actions.clearReasonRequest(entry.id);
58
+ };
59
+ const archiveButton = features.archive && state.zone === "activity" ? ((0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: entry.blocked ? "outline" : "ghost", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Archive, { size: iconPx, "aria-hidden": "true" }), label: labels.archive, isDisabled: isOffline, sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, "archive"), onClick: () => actions.archive([entry.id]) })) : null;
60
+ return ((0, jsx_runtime_1.jsxs)(react_2.chakra.article, { "aria-labelledby": titleId, display: "flex", flexDirection: "column", gap: 4, px: isPhone ? 4 : 8, pt: isPhone ? 2 : 6, pb: 8, maxW: "47.5rem", "data-testid": (0, rowStyles_1.testIdFor)(entry, "detail"), children: [isPhone && onBack && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { mx: -2, children: (0, jsx_runtime_1.jsx)(Button_1.default, { size: "md", variant: "ghost", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.ArrowLeft, { size: (0, rowStyles_1.iconSizeFor)("md"), "aria-hidden": "true" }), label: labels.back, sx: (0, rowStyles_1.touchTargetFor)("md"), onClick: onBack }) })), (0, jsx_runtime_1.jsxs)(Primitives_1.Box, { as: "header", display: "grid", gap: 1.5, children: [(0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { wrap: "wrap", align: "center", gap: 1.5, fontSize: "xs", fontWeight: 500, color: colors.textMuted, children: [(0, jsx_runtime_1.jsx)(Primitives_1.Flex, { boxSize: "1.25rem", align: "center", justify: "center", borderRadius: radii_1.RADIUS_ROLE.option, bg: tile.bg, color: tile.fg, "aria-hidden": "true", children: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: category.icon, boxSize: "0.75rem" }) }), (0, jsx_runtime_1.jsx)("span", { children: category.label }), entry.eyebrow && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: "\u00B7" }), (0, jsx_runtime_1.jsx)(react_2.chakra.span, { fontFamily: "mono", children: entry.eyebrow })] })), isUnread && (0, jsx_runtime_1.jsx)(Tag_1.default, { size: "xs", colorScheme: "primary", label: labels.unread })] }), (0, jsx_runtime_1.jsx)(Primitives_1.Heading, { as: "h2", id: titleId, ref: titleRef, tabIndex: -1, fontSize: "lg", fontWeight: 500, lineHeight: "1.4", color: colors.text[800], borderRadius: "sm", sx: { textWrap: "balance", "&:focus-visible": (0, focusRing_styles_1.focusVisibleRing)(colors) }, children: (0, jsx_runtime_1.jsx)(rowParts_1.TitleText, { parts: entry.title, isUnread: true }) }), (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { wrap: "wrap", align: "center", gap: 2, fontSize: "xs-plus", color: colors.textMuted, children: [entry.actor && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Avatar_1.default, { name: entry.actor.name, src: entry.actor.avatarUrl, size: "xs" }), (0, jsx_runtime_1.jsx)("span", { children: entry.actor.name }), (0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: "\u00B7" })] })), (0, jsx_runtime_1.jsx)(react_2.chakra.time, { dateTime: format.iso(entry.createdAt), children: format.absolute(entry.createdAt, now) }), isWaiting && (0, jsx_runtime_1.jsx)(Tag_1.default, { size: "xs", tone: "warning", leadingIcon: lucide_react_1.Hourglass, label: labels.waiting(days) })] })] }), entry.blocked ? ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { borderRadius: radii_1.RADIUS_ROLE.control, bg: colors.backgroundColor.subtle, children: (0, jsx_runtime_1.jsx)(EmptyState_1.default, { icon: lucide_react_1.Lock, size: "sm", titleAs: "h3", title: labels.blockedTitle, description: entry.blocked, action: archiveButton }) })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [entry.context && ((0, jsx_runtime_1.jsx)(Primitives_1.Text, { mt: -2, fontSize: "xs-plus", color: colors.textMuted, children: entry.context })), ((_a = entry.body) !== null && _a !== void 0 ? _a : entry.preview) && ((0, jsx_runtime_1.jsx)(Primitives_1.Text, { fontSize: "sm", lineHeight: "1.65", color: colors.text[800], maxW: "65ch", whiteSpace: "pre-line", children: (_b = entry.body) !== null && _b !== void 0 ? _b : entry.preview })), entry.change && (0, jsx_runtime_1.jsx)(rowParts_1.ChangeChips, { change: entry.change, labels: labels }), entry.fields && entry.fields.length > 0 && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { p: 4, borderRadius: radii_1.RADIUS_ROLE.control, bg: colors.backgroundColor.subtle, children: (0, jsx_runtime_1.jsx)(DescriptionList_1.default, { items: entry.fields.map(([label, value]) => ({ label, value })), layout: isPhone ? "stacked" : "inline", columns: { base: 1 } }) })), state.status !== "open" ? ((0, jsx_runtime_1.jsx)(RowStatus_1.RowStatus, { item: item, shared: shared, size: size })) : formAction ? ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { maxW: "32.5rem", children: (0, jsx_runtime_1.jsx)(ReasonForm_1.ReasonForm, { entry: entry, action: formAction, labels: labels, size: size, isOffline: isOffline, serverMessage: request ? ((_c = request.message) !== null && _c !== void 0 ? _c : labels.reasonRequiredMessage) : undefined, onCancel: closeForm, onSubmit: (reason) => {
61
+ setAsking(null);
62
+ actions.decide([entry.id], formAction, reason);
63
+ } }) })) : (actionList.length > 0 && ((0, jsx_runtime_1.jsxs)(Primitives_1.Box, { display: "grid", gap: 2, children: [(0, jsx_runtime_1.jsx)(RowActions_1.RowActions, { entry: entry, actionList: actionList, shared: shared, size: size, emphasis: "detail", onAsk: (action) => setAsking({ id: entry.id, action }) }), isOffline && decides && (0, jsx_runtime_1.jsx)(RowActions_1.OfflineNote, { text: labels.offlineMessage })] })))] })), (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { wrap: "wrap", gap: 2, pt: 4, borderTop: `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${(0, planeStep_1.ruleOn)(colors, plane)}`, children: [!entry.blocked && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: decides ? "outline" : "solid", colorScheme: decides ? "gray" : "primary", rightIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.ExternalLink, { size: iconPx, "aria-hidden": "true" }), label: labels.openIn(appName), sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, "open"), onClick: (event) => actions.open(entry, event) })), isQuiet && features.markRead && entry.isRead !== undefined && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: "ghost", colorScheme: "gray", leftIcon: isUnread ? (0, jsx_runtime_1.jsx)(lucide_react_1.MailOpen, { size: iconPx, "aria-hidden": "true" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Mail, { size: iconPx, "aria-hidden": "true" }), label: isUnread ? labels.markRead : labels.markUnread, isDisabled: isOffline, sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, "read"), onClick: () => actions.setRead([entry.id], isUnread) })), isQuiet && !entry.blocked && archiveButton, isQuiet && features.restore && state.zone === "archived" && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: "ghost", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.ArchiveRestore, { size: iconPx, "aria-hidden": "true" }), label: labels.restore, isDisabled: isOffline, sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, "restore"), onClick: () => actions.restore([entry.id]) }))] })] }));
64
+ };
65
+ exports.default = NotificationDetail;
@@ -0,0 +1,15 @@
1
+ import type { Ref } from "react";
2
+ import type { LiveNotificationEntry } from "../core/NotificationEngineProps";
3
+ /** Density: desktop uses 32px buttons, phone 40px with 44px touch targets and a Back button. */
4
+ export type NotificationDetailVariant = "desktop" | "phone";
5
+ /** One entry in full: facts, the decision, and Open in, read and archive actions. Reads the nearest `NotificationCenterProvider`. */
6
+ export interface NotificationDetailProps {
7
+ /** A live entry from `useNotificationCenter()`. */
8
+ item: LiveNotificationEntry;
9
+ /** Defaults to "desktop". */
10
+ variant?: NotificationDetailVariant;
11
+ /** Shows the Back button on phone. */
12
+ onBack?: () => void;
13
+ /** Ref to the focusable title, so opening an entry can move focus to it. */
14
+ titleRef?: Ref<HTMLHeadingElement>;
15
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import type { NotificationRowProps } from "./NotificationRowProps";
2
+ declare const _default: import("react").MemoExoticComponent<({ item, variant, isSelected, isChecked, onCheckedChange, isThreadChild, thread, isThreadOpen, onThreadToggle, initialReasonActionId, onOpen, linkRef, }: NotificationRowProps) => import("react/jsx-runtime").JSX.Element>;
3
+ export default _default;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const react_2 = require("@chakra-ui/react");
9
+ const lucide_react_1 = require("lucide-react");
10
+ const Primitives_1 = require("../../Primitives/Primitives");
11
+ const Button_1 = __importDefault(require("../../Button/Button"));
12
+ const Checkbox_1 = __importDefault(require("../../Checkbox/Checkbox"));
13
+ const VisuallyHidden_1 = __importDefault(require("../../VisuallyHidden/VisuallyHidden"));
14
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
15
+ const rowStates_1 = require("../../../Theme/tokens/builders/rowStates");
16
+ const focusRing_styles_1 = require("../../../Theme/chakra/focusRing.styles");
17
+ const motion_1 = require("../../../Theme/chakra/motion");
18
+ const motion_2 = require("../../../Theme/tokens/primitives/motion");
19
+ const radii_1 = require("../../../Theme/tokens/primitives/radii");
20
+ const NotificationCenterProvider_1 = require("../core/NotificationCenterProvider");
21
+ const grouping_1 = require("../core/grouping");
22
+ const category_1 = require("./category");
23
+ const ReasonForm_1 = require("./ReasonForm");
24
+ const RowActions_1 = require("./RowActions");
25
+ const RowQuickActions_1 = require("./RowQuickActions");
26
+ const RowStatus_1 = require("./RowStatus");
27
+ const rowParts_1 = require("./rowParts");
28
+ const rowMenu_1 = require("./rowMenu");
29
+ const rowStyles_1 = require("./rowStyles");
30
+ const COLLAPSE = (0, motion_2.transitionFor)(["grid-template-rows", "opacity"], "base");
31
+ const HIDE = `${COLLAPSE}, visibility ${motion_2.MOTION_MS.base}ms step-end`;
32
+ const SHOW = `${COLLAPSE}, visibility ${motion_2.MOTION_MS.base}ms step-start`;
33
+ const isPlainClick = (event) => event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
34
+ /** One notification as a list row: lead avatar or tile, title, context, decisions with undo, and hover actions. */
35
+ const NotificationRow = ({ item, variant = "panel", isSelected = false, isChecked = false, onCheckedChange, isThreadChild = false, thread, isThreadOpen = false, onThreadToggle, initialReasonActionId, onOpen, linkRef, }) => {
36
+ var _a;
37
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
38
+ const shared = (0, NotificationCenterProvider_1.useNotificationShared)();
39
+ const { labels, format, now, categories, features, isOffline, actions } = shared;
40
+ const { entry, state } = item;
41
+ const [askingId, setAskingId] = (0, react_1.useState)(initialReasonActionId);
42
+ const rows = (0, react_1.useMemo)(() => (0, rowStates_1.listRowBackgrounds)(colors), [colors]);
43
+ const size = rowStyles_1.ROW_BUTTON_SIZE[variant];
44
+ const isPhone = variant === "phone";
45
+ const isUnread = entry.isRead === false;
46
+ const isHidden = state.isHidden;
47
+ const category = (0, category_1.categoryFor)(categories, entry.category, labels.otherCategory);
48
+ const title = (0, grouping_1.plainTitle)(entry.title);
49
+ const actionList = (0, rowMenu_1.visibleActionsFor)(entry, features);
50
+ const days = format.daysSince(entry.createdAt, now);
51
+ const hasDecision = actionList.some((action) => action.href === undefined);
52
+ const waitingDays = state.zone === "needsYou" && hasDecision && days >= rowStyles_1.WAITING_AFTER_DAYS ? days : null;
53
+ const request = state.reasonRequest;
54
+ const formActionId = askingId !== undefined ? askingId : request ? request.actionId : undefined;
55
+ const formAction = state.status === "open" && formActionId !== undefined
56
+ ? actionList.find((action) => action.id === formActionId)
57
+ : undefined;
58
+ const isQuiet = state.status === "open" && formAction === undefined;
59
+ const quick = isQuiet ? (0, rowMenu_1.quickActionsFor)(item, (0, rowMenu_1.rowScope)(item, thread, isThreadOpen), shared) : [];
60
+ const rest = thread ? thread.rest.length : 0;
61
+ const resting = isSelected || isChecked ? rows.selected : colors.surfaceRaised;
62
+ const hover = isSelected || isChecked ? rows.selectedActive : rows.active;
63
+ const open = (event) => {
64
+ if (onOpen)
65
+ onOpen(item, event);
66
+ else
67
+ actions.open(entry, event);
68
+ };
69
+ const onLinkClick = (event) => {
70
+ if (entry.href !== undefined) {
71
+ if (!isPlainClick(event))
72
+ return;
73
+ event.preventDefault();
74
+ }
75
+ open(event);
76
+ };
77
+ const closeForm = () => {
78
+ setAskingId(undefined);
79
+ if (request)
80
+ actions.clearReasonRequest(entry.id);
81
+ };
82
+ const sendForm = (action, reason) => {
83
+ setAskingId(undefined);
84
+ actions.decide([entry.id], action, reason);
85
+ };
86
+ const linkSx = {
87
+ flex: 1,
88
+ minW: 0,
89
+ textAlign: "left",
90
+ fontSize: "sm",
91
+ lineHeight: "1.43",
92
+ color: "inherit",
93
+ textDecoration: "none",
94
+ "&::after": {
95
+ content: '""',
96
+ position: "absolute",
97
+ inset: 0,
98
+ zIndex: 1,
99
+ borderRadius: radii_1.RADIUS_ROLE.option,
100
+ },
101
+ "&:focus-visible": { outline: "none" },
102
+ "&:focus-visible::after": {
103
+ boxShadow: (0, focusRing_styles_1.insetFocusRingShadow)(colors),
104
+ outline: "2px solid transparent",
105
+ outlineOffset: "-2px",
106
+ },
107
+ };
108
+ const linkBody = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [isUnread && (0, jsx_runtime_1.jsx)(VisuallyHidden_1.default, { children: `${labels.unread}. ` }), entry.eyebrow && ((0, jsx_runtime_1.jsxs)(react_2.chakra.span, { fontFamily: "mono", fontSize: "xs", fontWeight: 500, color: colors.textMuted, children: [entry.eyebrow, " "] })), (0, jsx_runtime_1.jsx)(rowParts_1.TitleText, { parts: entry.title, isUnread: isUnread })] }));
109
+ return ((0, jsx_runtime_1.jsx)(react_2.chakra.li, { listStyleType: "none", display: "grid", gridTemplateRows: isHidden ? "0fr" : "1fr", opacity: isHidden ? 0 : 1, visibility: isHidden ? "hidden" : "visible", "aria-hidden": isHidden ? true : undefined, "data-testid": entry.testId, "data-notification-id": entry.id, "data-status": state.status, sx: {
110
+ transition: isHidden ? HIDE : SHOW,
111
+ contentVisibility: "auto",
112
+ containIntrinsicSize: "auto 4.5rem",
113
+ ...(0, motion_1.reducedMotionSx)(),
114
+ }, children: (0, jsx_runtime_1.jsx)(Primitives_1.Box, { minH: 0, overflow: "hidden", children: (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { position: "relative", align: "flex-start", gap: variant === "inbox" ? 2.5 : 3, pt: isPhone ? 3 : 2.5, pb: isPhone ? 3 : 2.5, pr: isPhone ? 2 : 3, pl: isThreadChild ? 16 : 5, borderRadius: radii_1.RADIUS_ROLE.option, bg: resting, sx: {
115
+ [rowParts_1.ROW_PLANE_VAR]: resting,
116
+ transition: (0, motion_2.transitionFor)(["background-color"]),
117
+ "&:hover": { bg: hover, [rowParts_1.ROW_PLANE_VAR]: hover },
118
+ [`&:hover ${RowQuickActions_1.QUICK_SELECTOR}, &:focus-within ${RowQuickActions_1.QUICK_SELECTOR}`]: { opacity: 1 },
119
+ ...(0, motion_1.reducedMotionSx)(),
120
+ }, children: [isSelected && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { position: "absolute", left: 0, top: 2, bottom: 2, w: "0.1875rem", borderRightRadius: "sm", bg: colors.primary[500], "aria-hidden": "true" })), isUnread && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { position: "absolute", left: isThreadChild ? "3.125rem" : "0.4375rem", top: isThreadChild ? "0.875rem" : isPhone ? "1.125rem" : "1rem", boxSize: "0.5rem", borderRadius: "full", bg: colors.accentText, "aria-hidden": "true", "data-testid": (0, rowStyles_1.testIdFor)(entry, "dot") })), onCheckedChange && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { position: "relative", zIndex: 2, mt: 1, sx: rowStyles_1.CHECKBOX_TOUCH_TARGET_SX, children: (0, jsx_runtime_1.jsx)(Checkbox_1.default, { isChecked: isChecked, "aria-label": labels.select(title), onChange: (event) => onCheckedChange(item, event.target.checked) }) })), (0, jsx_runtime_1.jsx)(rowParts_1.RowLeading, { entry: entry, category: category, size: isThreadChild ? "xs" : isPhone ? "md" : "sm" }), (0, jsx_runtime_1.jsxs)(Primitives_1.Box, { flex: 1, minW: 0, children: [(0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { align: "baseline", gap: 2, children: [entry.href !== undefined ? ((0, jsx_runtime_1.jsx)(react_2.chakra.a, { ref: linkRef, href: entry.href, "aria-current": isSelected ? "true" : undefined, "data-testid": (0, rowStyles_1.testIdFor)(entry, "link"), onClick: onLinkClick, sx: linkSx, children: linkBody })) : ((0, jsx_runtime_1.jsx)(react_2.chakra.button, { ref: linkRef, type: "button", "aria-current": isSelected ? "true" : undefined, "data-testid": (0, rowStyles_1.testIdFor)(entry, "link"), onClick: onLinkClick, sx: linkSx, children: linkBody })), (0, jsx_runtime_1.jsx)(rowParts_1.RowTime, { at: entry.createdAt, now: now, format: format })] }), (0, jsx_runtime_1.jsx)(rowParts_1.RowContext, { entry: entry, waitingDays: waitingDays, labels: labels }), entry.preview && (0, jsx_runtime_1.jsx)(rowParts_1.RowPreview, { text: entry.preview, isLarge: isPhone }), entry.change && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { mt: 1.5, children: (0, jsx_runtime_1.jsx)(rowParts_1.ChangeChips, { change: entry.change, labels: labels }) })), formAction ? ((0, jsx_runtime_1.jsx)(ReasonForm_1.ReasonForm, { entry: entry, action: formAction, labels: labels, size: size, isOffline: isOffline, serverMessage: request ? ((_a = request.message) !== null && _a !== void 0 ? _a : labels.reasonRequiredMessage) : undefined, onCancel: closeForm, onSubmit: (reason) => sendForm(formAction, reason) })) : (state.status === "open" &&
121
+ actionList.length > 0 && ((0, jsx_runtime_1.jsx)(RowActions_1.RowActions, { entry: entry, actionList: actionList, shared: shared, size: size, emphasis: "row", onAsk: (action) => setAskingId(action.id) }))), (0, jsx_runtime_1.jsx)(RowStatus_1.RowStatus, { item: item, shared: shared, size: size }), thread && rest > 0 && onThreadToggle && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { position: "relative", zIndex: 2, mt: 2, children: (0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "link", leftIcon: isThreadOpen ? ((0, jsx_runtime_1.jsx)(lucide_react_1.ChevronDown, { size: (0, rowStyles_1.iconSizeFor)("xs"), "aria-hidden": "true" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { size: (0, rowStyles_1.iconSizeFor)("xs"), "aria-hidden": "true" })), label: isThreadOpen ? labels.threadHide(rest) : labels.threadShow(rest), "aria-expanded": isThreadOpen, "data-testid": (0, rowStyles_1.testIdFor)(entry, "thread"), onClick: () => onThreadToggle(thread) }) }))] }), quick.length > 0 &&
122
+ (isPhone ? ((0, jsx_runtime_1.jsx)(RowQuickActions_1.RowMoreMenu, { entry: entry, items: quick, isOffline: isOffline, label: labels.moreActions(title) })) : ((0, jsx_runtime_1.jsx)(RowQuickActions_1.RowQuickActions, { entry: entry, items: quick, isOffline: isOffline })))] }) }) }));
123
+ };
124
+ exports.default = (0, react_1.memo)(NotificationRow);
@@ -0,0 +1,33 @@
1
+ import type { KeyboardEvent, MouseEvent, RefCallback } from "react";
2
+ import type { LiveNotificationEntry, NotificationThread } from "../core/NotificationEngineProps";
3
+ /** Density: panel rows carry 24px buttons, inbox rows 32px, phone rows 40px with 44px touch targets. */
4
+ export type NotificationRowVariant = "panel" | "inbox" | "phone";
5
+ /** The click or key press that opened a row. */
6
+ export type NotificationRowOpenEvent = MouseEvent<HTMLElement> | KeyboardEvent<HTMLElement>;
7
+ /** One entry as a list row; reads labels and actions from the nearest `NotificationCenterProvider`. Render it inside a `ul`. */
8
+ export interface NotificationRowProps {
9
+ /** A live entry from `useNotificationCenter().lists`; rows skip re-rendering while it is unchanged. */
10
+ item: LiveNotificationEntry;
11
+ /** Defaults to "panel". */
12
+ variant?: NotificationRowVariant;
13
+ /** The entry shown in the reading pane: tinted, with a rail and `aria-current` on its link. */
14
+ isSelected?: boolean;
15
+ /** The bulk-selection checkbox state; only shown with `onCheckedChange`. */
16
+ isChecked?: boolean;
17
+ /** Shows the selection checkbox; pass one stable function for every row. */
18
+ onCheckedChange?: (item: LiveNotificationEntry, checked: boolean) => void;
19
+ /** An older entry inside an open thread: indented, with a 24px avatar. */
20
+ isThreadChild?: boolean;
21
+ /** Set on a thread's lead row; while closed, its read and archive buttons cover the whole thread. */
22
+ thread?: NotificationThread;
23
+ /** Whether the thread's older entries are showing. */
24
+ isThreadOpen?: boolean;
25
+ /** Shows the thread toggle; pass one stable function for every row. */
26
+ onThreadToggle?: (thread: NotificationThread) => void;
27
+ /** Opens the reason form for this action on mount, e.g. from a keyboard shortcut. */
28
+ initialReasonActionId?: string;
29
+ /** Replaces opening through `onOpen`, e.g. to show the entry in a reading pane; modifier clicks still open a new tab. */
30
+ onOpen?: (item: LiveNotificationEntry, event: NotificationRowOpenEvent) => void;
31
+ /** Callback ref to the row's link (an `a`, or a `button` without `href`), for roving focus in a list. */
32
+ linkRef?: RefCallback<HTMLElement>;
33
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ import type { NotificationAction, NotificationEntry, NotificationLabels } from "../core/NotificationSourceProps";
2
+ import { type RowButtonSize } from "./rowStyles";
3
+ interface ReasonFormProps {
4
+ entry: NotificationEntry;
5
+ action: NotificationAction;
6
+ labels: NotificationLabels;
7
+ size: RowButtonSize;
8
+ isOffline: boolean;
9
+ serverMessage?: string;
10
+ onCancel: () => void;
11
+ onSubmit: (reason: string) => void;
12
+ }
13
+ export declare const ReasonForm: ({ entry, action, labels, size, isOffline, serverMessage, onCancel, onSubmit, }: ReasonFormProps) => import("react/jsx-runtime").JSX.Element;
14
+ export {};
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ReasonForm = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = require("react");
9
+ const react_2 = require("@chakra-ui/react");
10
+ const lucide_react_1 = require("lucide-react");
11
+ const Primitives_1 = require("../../Primitives/Primitives");
12
+ const Button_1 = __importDefault(require("../../Button/Button"));
13
+ const InputTextArea_1 = __importDefault(require("../../InputTextArea/InputTextArea"));
14
+ const Kbd_1 = __importDefault(require("../../Kbd/Kbd"));
15
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
16
+ const rowStyles_1 = require("./rowStyles");
17
+ const ReasonForm = ({ entry, action, labels, size, isOffline, serverMessage, onCancel, onSubmit, }) => {
18
+ var _a;
19
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
20
+ const id = (0, react_1.useId)();
21
+ const hintId = `${id}-hint`;
22
+ const field = (0, react_1.useRef)(null);
23
+ const [text, setText] = (0, react_1.useState)("");
24
+ const [touched, setTouched] = (0, react_1.useState)(false);
25
+ const isServerRequest = serverMessage !== undefined;
26
+ const isRequired = action.reason === "required" || isServerRequest;
27
+ const isNegative = action.intent === "negative";
28
+ const isMissing = isRequired && !text.trim();
29
+ const missingMessage = isNegative ? labels.reasonMissingNegative : labels.reasonMissing;
30
+ const errorText = touched && isMissing ? missingMessage : isServerRequest && !text.trim() ? serverMessage : undefined;
31
+ (0, react_1.useEffect)(() => {
32
+ if (field.current)
33
+ field.current.focus();
34
+ }, []);
35
+ const submit = () => {
36
+ setTouched(true);
37
+ if (isMissing) {
38
+ if (field.current)
39
+ field.current.focus();
40
+ return;
41
+ }
42
+ onSubmit(text.trim());
43
+ };
44
+ const onKeyDown = (event) => {
45
+ if (event.key === "Escape") {
46
+ event.stopPropagation();
47
+ onCancel();
48
+ }
49
+ else if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) {
50
+ event.preventDefault();
51
+ submit();
52
+ }
53
+ };
54
+ return ((0, jsx_runtime_1.jsxs)(react_2.chakra.form, { noValidate: true, position: "relative", zIndex: 2, display: "grid", gap: 1.5, mt: 2.5, onSubmit: (event) => {
55
+ event.preventDefault();
56
+ submit();
57
+ }, children: [(0, jsx_runtime_1.jsxs)(react_2.chakra.label, { htmlFor: id, fontSize: "xs-plus", fontWeight: 500, color: colors.text[700], children: [(_a = action.reasonLabel) !== null && _a !== void 0 ? _a : labels.reasonLabel, !isRequired && ((0, jsx_runtime_1.jsxs)(react_2.chakra.span, { fontWeight: 400, color: colors.textMuted, children: [" ", labels.reasonOptional] }))] }), (0, jsx_runtime_1.jsx)(InputTextArea_1.default, { ref: field, id: id, rows: 2, size: size === "md" ? "md" : "sm", resize: "vertical", value: text, error: errorText !== undefined, "aria-describedby": hintId, placeholder: isNegative ? labels.reasonPlaceholder : undefined, onChange: (event) => setText(event.target.value), onKeyDown: onKeyDown }), (0, jsx_runtime_1.jsx)(Primitives_1.Flex, { id: hintId, align: "center", wrap: "wrap", gap: 1, fontSize: "xs", fontWeight: errorText !== undefined ? 500 : 400, color: errorText !== undefined ? colors.semanticText.error : colors.textMuted, children: errorText !== undefined ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.CircleAlert, boxSize: "0.75rem", "aria-hidden": "true" }), errorText] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Kbd_1.default, { size: "xs", children: labels.keyCtrl }), (0, jsx_runtime_1.jsx)(Kbd_1.default, { size: "xs", children: labels.keyEnter }), (0, jsx_runtime_1.jsxs)("span", { children: [labels.toSend, " \u00B7"] }), (0, jsx_runtime_1.jsx)(Kbd_1.default, { size: "xs", children: labels.keyEsc }), (0, jsx_runtime_1.jsx)("span", { children: labels.toCancel })] })) }), (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { justify: "flex-end", gap: 2, children: [(0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: "ghost", colorScheme: "gray", label: labels.cancel, sx: (0, rowStyles_1.touchTargetFor)(size), onClick: onCancel }), (0, jsx_runtime_1.jsx)(Button_1.default, { type: "submit", size: size, variant: "solid", colorScheme: isNegative ? "red" : "primary", label: action.label, "aria-label": labels.actionName(action.label, entry.subject), isDisabled: isOffline, sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": entry.testId ? `${entry.testId}-${action.id}-send` : undefined })] })] }));
58
+ };
59
+ exports.ReasonForm = ReasonForm;
@@ -0,0 +1,16 @@
1
+ import type { NotificationAction, NotificationEntry } from "../core/NotificationSourceProps";
2
+ import type { NotificationShared } from "../core/useNotificationEngine";
3
+ import { type RowButtonSize } from "./rowStyles";
4
+ interface RowActionsProps {
5
+ entry: NotificationEntry;
6
+ actionList: NotificationAction[];
7
+ shared: NotificationShared;
8
+ size: RowButtonSize;
9
+ emphasis: "row" | "detail";
10
+ onAsk: (action: NotificationAction) => void;
11
+ }
12
+ export declare const OfflineNote: ({ text }: {
13
+ text: string;
14
+ }) => import("react/jsx-runtime").JSX.Element;
15
+ export declare const RowActions: ({ entry, actionList, shared, size, emphasis, onAsk }: RowActionsProps) => import("react/jsx-runtime").JSX.Element;
16
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RowActions = exports.OfflineNote = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const lucide_react_1 = require("lucide-react");
9
+ const Primitives_1 = require("../../Primitives/Primitives");
10
+ const Button_1 = __importDefault(require("../../Button/Button"));
11
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
12
+ const rowMenu_1 = require("./rowMenu");
13
+ const rowStyles_1 = require("./rowStyles");
14
+ const OfflineNote = ({ text }) => {
15
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
16
+ return ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { as: "span", display: "inline-flex", align: "center", gap: 1, fontSize: "xs", color: colors.textMuted, children: [(0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.WifiOff, boxSize: "0.75rem", "aria-hidden": "true" }), text] }));
17
+ };
18
+ exports.OfflineNote = OfflineNote;
19
+ const RowActions = ({ entry, actionList, shared, size, emphasis, onAsk }) => {
20
+ const { labels, actions, isOffline } = shared;
21
+ const iconPx = (0, rowStyles_1.iconSizeFor)(size);
22
+ return ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { position: "relative", zIndex: 2, wrap: "wrap", align: "center", gap: 2, mt: emphasis === "row" ? 2.5 : 0, children: [actionList.map((action) => {
23
+ const isLink = !(0, rowMenu_1.isDecision)(action);
24
+ const isStrong = emphasis === "detail" && (action.intent === "positive" || action.intent === "primary");
25
+ return ((0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: isStrong ? "solid" : "outline", colorScheme: isStrong ? "primary" : "gray", label: action.label, "aria-label": labels.actionName(action.label, entry.subject), leftIcon: !isLink && action.intent === "positive" ? (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { size: iconPx, "aria-hidden": "true" }) : undefined, rightIcon: isLink ? (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronRight, { size: iconPx, "aria-hidden": "true" }) : undefined, isDisabled: isOffline && !isLink, sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, action.id), onClick: (event) => {
26
+ event.stopPropagation();
27
+ if (isLink)
28
+ actions.open(entry, event, action);
29
+ else if (action.reason)
30
+ onAsk(action);
31
+ else
32
+ actions.decide([entry.id], action);
33
+ } }, action.id));
34
+ }), isOffline && actionList.some(rowMenu_1.isDecision) && (0, jsx_runtime_1.jsx)(exports.OfflineNote, { text: labels.offlineNote })] }));
35
+ };
36
+ exports.RowActions = RowActions;
@@ -0,0 +1,17 @@
1
+ import type { NotificationEntry } from "../core/NotificationSourceProps";
2
+ import type { RowQuickAction } from "./rowMenu";
3
+ export declare const QUICK_SELECTOR = "[data-nc-quick]";
4
+ interface QuickActionsProps {
5
+ entry: NotificationEntry;
6
+ items: RowQuickAction[];
7
+ isOffline: boolean;
8
+ }
9
+ export declare const RowQuickActions: ({ entry, items, isOffline }: QuickActionsProps) => import("react/jsx-runtime").JSX.Element;
10
+ interface MoreMenuProps {
11
+ entry: NotificationEntry;
12
+ items: RowQuickAction[];
13
+ isOffline: boolean;
14
+ label: string;
15
+ }
16
+ export declare const RowMoreMenu: ({ entry, items, isOffline, label }: MoreMenuProps) => import("react/jsx-runtime").JSX.Element;
17
+ export {};
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RowMoreMenu = exports.RowQuickActions = exports.QUICK_SELECTOR = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const lucide_react_1 = require("lucide-react");
9
+ const Primitives_1 = require("../../Primitives/Primitives");
10
+ const IconButton_1 = __importDefault(require("../../IconButton/IconButton"));
11
+ const ToolTip_1 = __importDefault(require("../../ToolTip/ToolTip"));
12
+ const DropDown_1 = __importDefault(require("../../Dropdown/DropDown"));
13
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
14
+ const borderWidths_1 = require("../../../Theme/tokens/primitives/borderWidths");
15
+ const radii_1 = require("../../../Theme/tokens/primitives/radii");
16
+ const motion_1 = require("../../../Theme/tokens/primitives/motion");
17
+ const motion_2 = require("../../../Theme/chakra/motion");
18
+ const rowStyles_1 = require("./rowStyles");
19
+ exports.QUICK_SELECTOR = "[data-nc-quick]";
20
+ const RowQuickActions = ({ entry, items, isOffline }) => {
21
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
22
+ return ((0, jsx_runtime_1.jsx)(Primitives_1.Flex, { "data-nc-quick": "", position: "absolute", top: "0.375rem", right: "0.375rem", zIndex: 2, gap: "0.125rem", p: "0.125rem", borderRadius: radii_1.RADIUS_ROLE.control, bg: colors.surfaceRaised, border: `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${colors.boxborder[200]}`, boxShadow: "sm", opacity: 0, sx: {
23
+ transition: (0, motion_1.transitionFor)(["opacity"]),
24
+ "@media (hover: none)": {
25
+ position: "relative",
26
+ top: "auto",
27
+ right: "auto",
28
+ opacity: 1,
29
+ alignSelf: "flex-start",
30
+ border: "none",
31
+ boxShadow: "none",
32
+ bg: "transparent",
33
+ },
34
+ ...(0, motion_2.reducedMotionSx)(),
35
+ }, children: items.map((item) => ((0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: item.label, children: (0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "xs", variant: "ghost", colorScheme: "gray", "aria-label": item.label, icon: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: item.icon, boxSize: `${(0, rowStyles_1.iconSizeFor)("xs") / 16}rem`, "aria-hidden": "true" }), isDisabled: isOffline, "data-testid": (0, rowStyles_1.testIdFor)(entry, item.id), onClick: (event) => {
36
+ event.stopPropagation();
37
+ item.run();
38
+ } }) }, item.id))) }));
39
+ };
40
+ exports.RowQuickActions = RowQuickActions;
41
+ const RowMoreMenu = ({ entry, items, isOffline, label }) => {
42
+ const trigger = {
43
+ variant: "ghost",
44
+ colorScheme: "gray",
45
+ px: 0,
46
+ minW: "2.5rem",
47
+ isDisabled: isOffline,
48
+ sx: rowStyles_1.TOUCH_TARGET_SX,
49
+ "data-testid": (0, rowStyles_1.testIdFor)(entry, "more"),
50
+ };
51
+ return ((0, jsx_runtime_1.jsx)(Primitives_1.Flex, { position: "relative", zIndex: 2, flexShrink: 0, mt: "-0.5rem", mr: "-0.5rem", children: (0, jsx_runtime_1.jsx)(DropDown_1.default, { size: "md", options: items.map((item) => ({ id: item.id, label: item.label, image: item.icon })), handleOptionSelect: (id) => {
52
+ const hit = items.find((item) => item.id === id);
53
+ if (hit)
54
+ hit.run();
55
+ }, DropdownIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.Ellipsis, { size: (0, rowStyles_1.iconSizeFor)("md"), "aria-hidden": "true" }), isVisibleIconShow: false, ariaLabel: label, buttonProps: trigger }) }));
56
+ };
57
+ exports.RowMoreMenu = RowMoreMenu;
@@ -0,0 +1,10 @@
1
+ import type { LiveNotificationEntry } from "../core/NotificationEngineProps";
2
+ import type { NotificationShared } from "../core/useNotificationEngine";
3
+ import { type RowButtonSize } from "./rowStyles";
4
+ interface RowStatusProps {
5
+ item: LiveNotificationEntry;
6
+ shared: NotificationShared;
7
+ size: RowButtonSize;
8
+ }
9
+ export declare const RowStatus: ({ item, shared, size }: RowStatusProps) => import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RowStatus = void 0;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const react_1 = require("@chakra-ui/react");
9
+ const lucide_react_1 = require("lucide-react");
10
+ const Primitives_1 = require("../../Primitives/Primitives");
11
+ const Button_1 = __importDefault(require("../../Button/Button"));
12
+ const Spinner_1 = __importDefault(require("../../Spinner/Spinner"));
13
+ const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
14
+ const tone_1 = require("../../../Theme/tokens/builders/tone");
15
+ const radii_1 = require("../../../Theme/tokens/primitives/radii");
16
+ const rowStyles_1 = require("./rowStyles");
17
+ const StatusLine = ({ tone, icon, role, children }) => {
18
+ const { colors } = (0, useCustomTheme_1.useCustomTheme)();
19
+ const soft = (0, tone_1.resolveSoftTone)(colors, (0, tone_1.toneScale)(colors, tone), colors.surfaceRaised);
20
+ return ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { role: role, position: "relative", zIndex: 2, wrap: "wrap", align: "center", columnGap: 2, rowGap: 1.5, mt: 2.5, px: 2.5, py: 1.5, borderRadius: radii_1.RADIUS_ROLE.control, bg: soft.bg, color: soft.fg, fontSize: "xs-plus", lineHeight: "1.45", onClick: (event) => event.stopPropagation(), children: [icon, children] }));
21
+ };
22
+ const glyph = (as) => (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: as, boxSize: "0.875rem", flexShrink: 0, "aria-hidden": "true" });
23
+ const LINK_SX = { color: "inherit", fontWeight: 600 };
24
+ const RowStatus = ({ item, shared, size }) => {
25
+ const { entry, state } = item;
26
+ const { labels, actions, isOffline } = shared;
27
+ const { decision, error } = state;
28
+ if (!decision || state.status === "open")
29
+ return null;
30
+ if (state.status === "failed") {
31
+ return ((0, jsx_runtime_1.jsxs)(StatusLine, { tone: "error", icon: glyph(lucide_react_1.CircleAlert), role: "alert", children: [(0, jsx_runtime_1.jsxs)(react_1.chakra.span, { fontWeight: 500, children: [(0, jsx_runtime_1.jsx)(react_1.chakra.strong, { fontWeight: 600, children: labels.couldNot(decision.label) }), " ", error && error.message ? error.message : labels.failedMessage] }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: size, variant: "outline", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.RefreshCw, { size: (0, rowStyles_1.iconSizeFor)(size), "aria-hidden": "true" }), label: labels.retry, "aria-label": labels.actionName(labels.retry, entry.subject), isDisabled: isOffline, ml: "auto", sx: (0, rowStyles_1.touchTargetFor)(size), "data-testid": (0, rowStyles_1.testIdFor)(entry, "retry"), onClick: () => actions.retry(entry.id) })] }));
32
+ }
33
+ if (state.status === "denied") {
34
+ const isForbidden = error !== undefined && error.kind === "forbidden";
35
+ const fallback = isForbidden ? labels.forbiddenMessage : labels.conflictMessage;
36
+ return ((0, jsx_runtime_1.jsxs)(StatusLine, { tone: "info", icon: glyph(isForbidden ? lucide_react_1.Lock : lucide_react_1.Info), children: [(0, jsx_runtime_1.jsx)(react_1.chakra.span, { fontWeight: 500, children: error && error.message ? error.message : fallback }), (0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "link", label: labels.dismiss, "aria-label": labels.actionName(labels.dismiss, entry.subject), sx: LINK_SX, "data-testid": (0, rowStyles_1.testIdFor)(entry, "dismiss"), onClick: () => actions.dismiss(entry.id) })] }));
37
+ }
38
+ const isNegative = decision.intent === "negative";
39
+ const isSending = state.status === "sending";
40
+ return ((0, jsx_runtime_1.jsxs)(StatusLine, { tone: isNegative ? "neutral" : "success", icon: isSending ? (0, jsx_runtime_1.jsx)(Spinner_1.default, { size: "xs", color: "currentColor", "aria-hidden": "true" }) : glyph(isNegative ? lucide_react_1.CircleX : lucide_react_1.CircleCheck), children: [(0, jsx_runtime_1.jsx)(react_1.chakra.span, { fontWeight: 500, children: isSending ? labels.sending : decision.doneLabel }), state.status === "undo" && ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "xs", variant: "link", label: labels.undo, "aria-label": labels.actionName(labels.undo, entry.subject), sx: LINK_SX, "data-testid": (0, rowStyles_1.testIdFor)(entry, "undo"), onClick: () => actions.undo(entry.id) })), decision.reason && ((0, jsx_runtime_1.jsx)(react_1.chakra.span, { flexBasis: "100%", pl: "1.375rem", fontStyle: "italic", opacity: 0.85, children: labels.reasonQuote(decision.reason) }))] }));
41
+ };
42
+ exports.RowStatus = RowStatus;
@@ -0,0 +1,8 @@
1
+ import type { NotificationCategories, NotificationCategory } from "../core/NotificationSourceProps";
2
+ import type { Tone } from "../../../Theme/tokens/builders/tone";
3
+ export interface ResolvedCategory {
4
+ label: string;
5
+ icon: NotificationCategory["icon"];
6
+ tone: Tone;
7
+ }
8
+ export declare const categoryFor: (categories: NotificationCategories, key: string, otherLabel: string) => ResolvedCategory;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.categoryFor = void 0;
4
+ const lucide_react_1 = require("lucide-react");
5
+ const grouping_1 = require("../core/grouping");
6
+ const categoryFor = (categories, key, otherLabel) => {
7
+ var _a;
8
+ const category = (0, grouping_1.findCategory)(categories, key);
9
+ if (!category)
10
+ return { label: otherLabel, icon: lucide_react_1.Bell, tone: "neutral" };
11
+ return { label: category.label, icon: category.icon, tone: (_a = category.tone) !== null && _a !== void 0 ? _a : "neutral" };
12
+ };
13
+ exports.categoryFor = categoryFor;
@@ -0,0 +1,14 @@
1
+ import type { ElementType } from "react";
2
+ import type { NotificationAction, NotificationEntry } from "../core/NotificationSourceProps";
3
+ import type { LiveNotificationEntry, NotificationFeatures, NotificationThread } from "../core/NotificationEngineProps";
4
+ import type { NotificationShared } from "../core/useNotificationEngine";
5
+ export interface RowQuickAction {
6
+ id: string;
7
+ label: string;
8
+ icon: ElementType;
9
+ run: () => void;
10
+ }
11
+ export declare const rowScope: (item: LiveNotificationEntry, thread: NotificationThread | undefined, isThreadOpen: boolean) => LiveNotificationEntry[];
12
+ export declare const quickActionsFor: (item: LiveNotificationEntry, scope: LiveNotificationEntry[], shared: NotificationShared) => RowQuickAction[];
13
+ export declare const visibleActionsFor: (entry: NotificationEntry, features: NotificationFeatures) => NotificationAction[];
14
+ export declare const isDecision: (action: NotificationAction) => boolean;