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.
- package/CHANGELOG.md +64 -1
- package/COMPONENT-GOTCHAS.md +37 -13
- package/DESIGN-GUIDE.md +4 -1
- package/dist/Components/NotificationBell/NotificationBellProps.d.ts +3 -3
- package/dist/Components/NotificationBell/NotificationItem.d.ts +1 -1
- package/dist/Components/NotificationBell/NotificationItem.js +1 -1
- package/dist/Components/NotificationBell/NotificationList.d.ts +1 -1
- package/dist/Components/NotificationBell/NotificationList.js +1 -1
- package/dist/Components/NotificationBell/NotificationPanel.d.ts +1 -1
- package/dist/Components/NotificationBell/NotificationPanel.js +1 -1
- package/dist/Components/NotificationCenter/center/CenterPanel.d.ts +15 -0
- package/dist/Components/NotificationCenter/center/CenterPanel.js +87 -0
- package/dist/Components/NotificationCenter/center/NotificationCenter.d.ts +4 -0
- package/dist/Components/NotificationCenter/center/NotificationCenter.js +130 -0
- package/dist/Components/NotificationCenter/center/NotificationCenterProps.d.ts +71 -0
- package/dist/Components/NotificationCenter/center/NotificationCenterProps.js +2 -0
- package/dist/Components/NotificationCenter/center/PanelRows.d.ts +10 -0
- package/dist/Components/NotificationCenter/center/PanelRows.js +35 -0
- package/dist/Components/NotificationCenter/center/PanelStates.d.ts +17 -0
- package/dist/Components/NotificationCenter/center/PanelStates.js +21 -0
- package/dist/Components/NotificationCenter/center/centerLabels.d.ts +4 -0
- package/dist/Components/NotificationCenter/center/centerLabels.js +38 -0
- package/dist/Components/NotificationCenter/center/useArrivals.d.ts +14 -0
- package/dist/Components/NotificationCenter/center/useArrivals.js +71 -0
- package/dist/Components/NotificationCenter/center/useIsSheet.d.ts +2 -0
- package/dist/Components/NotificationCenter/center/useIsSheet.js +20 -0
- package/dist/Components/NotificationCenter/core/NotificationCenterProvider.d.ts +17 -0
- package/dist/Components/NotificationCenter/core/NotificationCenterProvider.js +46 -0
- package/dist/Components/NotificationCenter/core/NotificationEngineProps.d.ts +182 -0
- package/dist/Components/NotificationCenter/core/NotificationEngineProps.js +2 -0
- package/dist/Components/NotificationCenter/core/NotificationSourceProps.d.ts +284 -0
- package/dist/Components/NotificationCenter/core/NotificationSourceProps.js +2 -0
- package/dist/Components/NotificationCenter/core/actionError.d.ts +4 -0
- package/dist/Components/NotificationCenter/core/actionError.js +45 -0
- package/dist/Components/NotificationCenter/core/format.d.ts +4 -0
- package/dist/Components/NotificationCenter/core/format.js +91 -0
- package/dist/Components/NotificationCenter/core/grouping.d.ts +14 -0
- package/dist/Components/NotificationCenter/core/grouping.js +102 -0
- package/dist/Components/NotificationCenter/core/labels.d.ts +6 -0
- package/dist/Components/NotificationCenter/core/labels.js +94 -0
- package/dist/Components/NotificationCenter/core/overlay.d.ts +109 -0
- package/dist/Components/NotificationCenter/core/overlay.js +281 -0
- package/dist/Components/NotificationCenter/core/useNotificationEngine.d.ts +13 -0
- package/dist/Components/NotificationCenter/core/useNotificationEngine.js +415 -0
- package/dist/Components/NotificationCenter/inbox/InboxList.d.ts +17 -0
- package/dist/Components/NotificationCenter/inbox/InboxList.js +25 -0
- package/dist/Components/NotificationCenter/inbox/InboxStates.d.ts +17 -0
- package/dist/Components/NotificationCenter/inbox/InboxStates.js +27 -0
- package/dist/Components/NotificationCenter/inbox/NotificationInbox.d.ts +4 -0
- package/dist/Components/NotificationCenter/inbox/NotificationInbox.js +434 -0
- package/dist/Components/NotificationCenter/inbox/NotificationInboxProps.d.ts +106 -0
- package/dist/Components/NotificationCenter/inbox/NotificationInboxProps.js +2 -0
- package/dist/Components/NotificationCenter/inbox/ShortcutsDialog.d.ts +8 -0
- package/dist/Components/NotificationCenter/inbox/ShortcutsDialog.js +63 -0
- package/dist/Components/NotificationCenter/inbox/inboxLabels.d.ts +4 -0
- package/dist/Components/NotificationCenter/inbox/inboxLabels.js +56 -0
- package/dist/Components/NotificationCenter/inbox/inboxModel.d.ts +17 -0
- package/dist/Components/NotificationCenter/inbox/inboxModel.js +47 -0
- package/dist/Components/NotificationCenter/inbox/useControllable.d.ts +1 -0
- package/dist/Components/NotificationCenter/inbox/useControllable.js +15 -0
- package/dist/Components/NotificationCenter/index.d.ts +8 -0
- package/dist/Components/NotificationCenter/index.js +26 -0
- package/dist/Components/NotificationCenter/preferences/NotificationPreferences.d.ts +4 -0
- package/dist/Components/NotificationCenter/preferences/NotificationPreferences.js +72 -0
- package/dist/Components/NotificationCenter/preferences/NotificationPreferencesProps.d.ts +111 -0
- package/dist/Components/NotificationCenter/preferences/NotificationPreferencesProps.js +2 -0
- package/dist/Components/NotificationCenter/preferences/PreferenceCells.d.ts +16 -0
- package/dist/Components/NotificationCenter/preferences/PreferenceCells.js +35 -0
- package/dist/Components/NotificationCenter/preferences/PreferenceGroups.d.ts +15 -0
- package/dist/Components/NotificationCenter/preferences/PreferenceGroups.js +26 -0
- package/dist/Components/NotificationCenter/preferences/preferencesLabels.d.ts +2 -0
- package/dist/Components/NotificationCenter/preferences/preferencesLabels.js +28 -0
- package/dist/Components/NotificationCenter/preferences/useAutosave.d.ts +8 -0
- package/dist/Components/NotificationCenter/preferences/useAutosave.js +41 -0
- package/dist/Components/NotificationCenter/row/NotificationDetail.d.ts +4 -0
- package/dist/Components/NotificationCenter/row/NotificationDetail.js +65 -0
- package/dist/Components/NotificationCenter/row/NotificationDetailProps.d.ts +15 -0
- package/dist/Components/NotificationCenter/row/NotificationDetailProps.js +2 -0
- package/dist/Components/NotificationCenter/row/NotificationRow.d.ts +3 -0
- package/dist/Components/NotificationCenter/row/NotificationRow.js +124 -0
- package/dist/Components/NotificationCenter/row/NotificationRowProps.d.ts +33 -0
- package/dist/Components/NotificationCenter/row/NotificationRowProps.js +2 -0
- package/dist/Components/NotificationCenter/row/ReasonForm.d.ts +14 -0
- package/dist/Components/NotificationCenter/row/ReasonForm.js +59 -0
- package/dist/Components/NotificationCenter/row/RowActions.d.ts +16 -0
- package/dist/Components/NotificationCenter/row/RowActions.js +36 -0
- package/dist/Components/NotificationCenter/row/RowQuickActions.d.ts +17 -0
- package/dist/Components/NotificationCenter/row/RowQuickActions.js +57 -0
- package/dist/Components/NotificationCenter/row/RowStatus.d.ts +10 -0
- package/dist/Components/NotificationCenter/row/RowStatus.js +42 -0
- package/dist/Components/NotificationCenter/row/category.d.ts +8 -0
- package/dist/Components/NotificationCenter/row/category.js +13 -0
- package/dist/Components/NotificationCenter/row/rowMenu.d.ts +14 -0
- package/dist/Components/NotificationCenter/row/rowMenu.js +37 -0
- package/dist/Components/NotificationCenter/row/rowParts.d.ts +40 -0
- package/dist/Components/NotificationCenter/row/rowParts.js +72 -0
- package/dist/Components/NotificationCenter/row/rowStyles.d.ts +11 -0
- package/dist/Components/NotificationCenter/row/rowStyles.js +25 -0
- package/dist/Components/SegmentedControl/segmentedInk.d.ts +4 -0
- package/dist/Components/SegmentedControl/segmentedInk.js +16 -2
- package/dist/Components/SideBar/SecondaryBar.js +2 -2
- package/dist/Components/SideBar/SideBar.js +18 -8
- package/dist/Components/SideBar/SideBarProps.d.ts +4 -2
- package/dist/Components/SideBar/components/MenuItemBox.d.ts +0 -2
- package/dist/Components/SideBar/components/MenuItemBox.js +2 -3
- package/dist/Components/SideBar/components/MenuItems.js +2 -2
- package/dist/Components/SideBar/components/PinnedSection.js +3 -4
- package/dist/Components/SideBar/sidebarScale.d.ts +0 -2
- package/dist/Components/SideBar/sidebarScale.js +0 -2
- package/dist/Components/Switch/Switch.d.ts +1 -1
- package/dist/Components/Switch/Switch.js +2 -2
- package/dist/Components/Switch/SwitchProps.d.ts +3 -0
- package/dist/Components/Toggle/TableToggle.js +4 -5
- package/dist/Components/Toggle/tableToggleInk.d.ts +7 -0
- package/dist/Components/Toggle/tableToggleInk.js +28 -0
- package/dist/esm/Components/NotificationBell/NotificationItem.js +1 -1
- package/dist/esm/Components/NotificationBell/NotificationList.js +1 -1
- package/dist/esm/Components/NotificationBell/NotificationPanel.js +1 -1
- package/dist/esm/Components/NotificationCenter/center/CenterPanel.js +81 -0
- package/dist/esm/Components/NotificationCenter/center/NotificationCenter.js +92 -0
- package/dist/esm/Components/NotificationCenter/center/NotificationCenterProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/center/PanelRows.js +28 -0
- package/dist/esm/Components/NotificationCenter/center/PanelStates.js +11 -0
- package/dist/esm/Components/NotificationCenter/center/centerLabels.js +34 -0
- package/dist/esm/Components/NotificationCenter/center/useArrivals.js +67 -0
- package/dist/esm/Components/NotificationCenter/center/useIsSheet.js +16 -0
- package/dist/esm/Components/NotificationCenter/core/NotificationCenterProvider.js +35 -0
- package/dist/esm/Components/NotificationCenter/core/NotificationEngineProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/core/NotificationSourceProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/core/actionError.js +39 -0
- package/dist/esm/Components/NotificationCenter/core/format.js +87 -0
- package/dist/esm/Components/NotificationCenter/core/grouping.js +88 -0
- package/dist/esm/Components/NotificationCenter/core/labels.js +88 -0
- package/dist/esm/Components/NotificationCenter/core/overlay.js +274 -0
- package/dist/esm/Components/NotificationCenter/core/useNotificationEngine.js +408 -0
- package/dist/esm/Components/NotificationCenter/inbox/InboxList.js +18 -0
- package/dist/esm/Components/NotificationCenter/inbox/InboxStates.js +18 -0
- package/dist/esm/Components/NotificationCenter/inbox/NotificationInbox.js +396 -0
- package/dist/esm/Components/NotificationCenter/inbox/NotificationInboxProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/inbox/ShortcutsDialog.js +23 -0
- package/dist/esm/Components/NotificationCenter/inbox/inboxLabels.js +52 -0
- package/dist/esm/Components/NotificationCenter/inbox/inboxModel.js +37 -0
- package/dist/esm/Components/NotificationCenter/inbox/useControllable.js +11 -0
- package/dist/esm/Components/NotificationCenter/index.js +8 -0
- package/dist/esm/Components/NotificationCenter/preferences/NotificationPreferences.js +67 -0
- package/dist/esm/Components/NotificationCenter/preferences/NotificationPreferencesProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/preferences/PreferenceCells.js +27 -0
- package/dist/esm/Components/NotificationCenter/preferences/PreferenceGroups.js +21 -0
- package/dist/esm/Components/NotificationCenter/preferences/preferencesLabels.js +24 -0
- package/dist/esm/Components/NotificationCenter/preferences/useAutosave.js +37 -0
- package/dist/esm/Components/NotificationCenter/row/NotificationDetail.js +60 -0
- package/dist/esm/Components/NotificationCenter/row/NotificationDetailProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/row/NotificationRow.js +119 -0
- package/dist/esm/Components/NotificationCenter/row/NotificationRowProps.js +1 -0
- package/dist/esm/Components/NotificationCenter/row/ReasonForm.js +52 -0
- package/dist/esm/Components/NotificationCenter/row/RowActions.js +28 -0
- package/dist/esm/Components/NotificationCenter/row/RowQuickActions.js +49 -0
- package/dist/esm/Components/NotificationCenter/row/RowStatus.js +35 -0
- package/dist/esm/Components/NotificationCenter/row/category.js +9 -0
- package/dist/esm/Components/NotificationCenter/row/rowMenu.js +30 -0
- package/dist/esm/Components/NotificationCenter/row/rowParts.js +59 -0
- package/dist/esm/Components/NotificationCenter/row/rowStyles.js +19 -0
- package/dist/esm/Components/SegmentedControl/segmentedInk.js +15 -2
- package/dist/esm/Components/SideBar/SecondaryBar.js +3 -3
- package/dist/esm/Components/SideBar/SideBar.js +18 -8
- package/dist/esm/Components/SideBar/components/MenuItemBox.js +2 -3
- package/dist/esm/Components/SideBar/components/MenuItems.js +2 -2
- package/dist/esm/Components/SideBar/components/PinnedSection.js +3 -4
- package/dist/esm/Components/SideBar/sidebarScale.js +0 -2
- package/dist/esm/Components/Switch/Switch.js +2 -2
- package/dist/esm/Components/Toggle/TableToggle.js +4 -5
- package/dist/esm/Components/Toggle/tableToggleInk.js +24 -0
- package/dist/esm/index.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +16 -3
- package/package.json +1 -1
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
40
|
+
const react_1 = require("react");
|
|
41
|
+
const lucide_react_1 = require("lucide-react");
|
|
42
|
+
const Button_1 = __importDefault(require("../../Button/Button"));
|
|
43
|
+
const BulkSelectionBar_1 = __importDefault(require("../../BulkSelectionBar/BulkSelectionBar"));
|
|
44
|
+
const Drawer_1 = __importStar(require("../../Drawer/Drawer"));
|
|
45
|
+
const EmptyState_1 = __importDefault(require("../../EmptyState/EmptyState"));
|
|
46
|
+
const FilteredEmptyState_1 = __importDefault(require("../../EmptyState/FilteredEmptyState"));
|
|
47
|
+
const FilterBar_1 = __importDefault(require("../../FilterBar/FilterBar"));
|
|
48
|
+
const IconButton_1 = __importDefault(require("../../IconButton/IconButton"));
|
|
49
|
+
const PageHeader_1 = __importDefault(require("../../PageHeader/PageHeader"));
|
|
50
|
+
const Primitives_1 = require("../../Primitives/Primitives");
|
|
51
|
+
const Search_1 = __importDefault(require("../../Search/Search"));
|
|
52
|
+
const Select_1 = __importDefault(require("../../Select/Select"));
|
|
53
|
+
const Tabs_1 = __importDefault(require("../../Tabs/Tabs"));
|
|
54
|
+
const ToggleSwitch_1 = __importDefault(require("../../ToggleSwitch/ToggleSwitch"));
|
|
55
|
+
const ToolTip_1 = __importDefault(require("../../ToolTip/ToolTip"));
|
|
56
|
+
const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
|
|
57
|
+
const planeStep_1 = require("../../../Theme/tokens/builders/planeStep");
|
|
58
|
+
const scrollbar_1 = require("../../../Theme/tokens/builders/scrollbar");
|
|
59
|
+
const borderWidths_1 = require("../../../Theme/tokens/primitives/borderWidths");
|
|
60
|
+
const radii_1 = require("../../../Theme/tokens/primitives/radii");
|
|
61
|
+
const NotificationCenterProvider_1 = require("../core/NotificationCenterProvider");
|
|
62
|
+
const grouping_1 = require("../core/grouping");
|
|
63
|
+
const NotificationDetail_1 = __importDefault(require("../row/NotificationDetail"));
|
|
64
|
+
const InboxStates_1 = require("./InboxStates");
|
|
65
|
+
const InboxList_1 = require("./InboxList");
|
|
66
|
+
const ShortcutsDialog_1 = require("./ShortcutsDialog");
|
|
67
|
+
const inboxModel_1 = require("./inboxModel");
|
|
68
|
+
const inboxLabels_1 = require("./inboxLabels");
|
|
69
|
+
const useControllable_1 = require("./useControllable");
|
|
70
|
+
const TAB_BY_ID = { needsYou: "needsYou", activity: "activity", archived: "archived" };
|
|
71
|
+
const NotificationInboxBody = ({ variant = "desktop", tab: tabProp, onTabChange, selectedId: selectedProp, onSelectedChange, onOpenSettings, labels: labelOverrides, "data-testid": testId, }) => {
|
|
72
|
+
const { colors } = (0, useCustomTheme_1.useCustomTheme)();
|
|
73
|
+
const center = (0, NotificationCenterProvider_1.useNotificationCenter)();
|
|
74
|
+
const { lists, counts, categories, features, format, now, status, isOffline, hasMore, isLoadingMore, appName, actions, find } = center;
|
|
75
|
+
const labels = (0, react_1.useMemo)(() => (0, inboxLabels_1.withInboxLabels)(center.labels, format, labelOverrides), [center.labels, format, labelOverrides]);
|
|
76
|
+
const baseId = (0, react_1.useId)();
|
|
77
|
+
const isPhone = variant === "phone";
|
|
78
|
+
const plane = colors.surfaceRaised;
|
|
79
|
+
const rule = `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${(0, planeStep_1.ruleOn)(colors, plane)}`;
|
|
80
|
+
const outline = `${borderWidths_1.BORDER_WIDTHS.hairline} solid ${colors.boxborder[200]}`;
|
|
81
|
+
const [tabValue, setTab] = (0, useControllable_1.useControllable)(tabProp, "needsYou", onTabChange);
|
|
82
|
+
const [selectedId, setSelectedRaw, isSelectionControlled] = (0, useControllable_1.useControllable)(selectedProp, null, onSelectedChange);
|
|
83
|
+
const [query, setQuery] = (0, react_1.useState)("");
|
|
84
|
+
const [type, setType] = (0, react_1.useState)(inboxModel_1.ALL_TYPES);
|
|
85
|
+
const [unreadOnly, setUnreadOnly] = (0, react_1.useState)(false);
|
|
86
|
+
const [checked, setChecked] = (0, react_1.useState)(() => new Set());
|
|
87
|
+
const [openThreads, setOpenThreads] = (0, react_1.useState)(() => new Set());
|
|
88
|
+
const [keysOpen, setKeysOpen] = (0, react_1.useState)(false);
|
|
89
|
+
const [filtersOpen, setFiltersOpen] = (0, react_1.useState)(false);
|
|
90
|
+
const rootRef = (0, react_1.useRef)(null);
|
|
91
|
+
const searchRef = (0, react_1.useRef)(null);
|
|
92
|
+
const titleRef = (0, react_1.useRef)(null);
|
|
93
|
+
const links = (0, react_1.useRef)(new Map());
|
|
94
|
+
const linkRefs = (0, react_1.useRef)(new Map());
|
|
95
|
+
const pendingFocus = (0, react_1.useRef)(null);
|
|
96
|
+
const orderRef = (0, react_1.useRef)([]);
|
|
97
|
+
const activeTab = tabValue === "archived" && !features.archive ? "needsYou" : tabValue;
|
|
98
|
+
const showUnreadOnly = unreadOnly && activeTab !== "needsYou";
|
|
99
|
+
const selectedItem = selectedId === null ? undefined : find(selectedId);
|
|
100
|
+
const isDetailOpen = isPhone && selectedItem !== undefined;
|
|
101
|
+
const isReady = status === "ready";
|
|
102
|
+
const canSelect = features.decide || features.markRead || features.archive || features.restore;
|
|
103
|
+
const base = lists[activeTab];
|
|
104
|
+
const filtered = (0, react_1.useMemo)(() => (0, inboxModel_1.filterItems)(base, { type, unreadOnly: showUnreadOnly, query, keepId: selectedId }), [base, type, showUnreadOnly, query, selectedId]);
|
|
105
|
+
const groups = (0, react_1.useMemo)(() => activeTab === "needsYou"
|
|
106
|
+
? (0, grouping_1.groupByCategory)(filtered, categories, labels.otherCategory)
|
|
107
|
+
: (0, grouping_1.groupByDay)(filtered, format, now), [activeTab, filtered, categories, labels.otherCategory, format, now]);
|
|
108
|
+
const visibleItems = (0, react_1.useMemo)(() => filtered.filter(inboxModel_1.isShown), [filtered]);
|
|
109
|
+
const rowIds = (0, react_1.useMemo)(() => (0, inboxModel_1.visibleRowIds)(groups, openThreads), [groups, openThreads]);
|
|
110
|
+
const filterCount = (query.trim() === "" ? 0 : 1) + (type === inboxModel_1.ALL_TYPES ? 0 : 1) + (showUnreadOnly ? 1 : 0);
|
|
111
|
+
const typeOptions = (0, react_1.useMemo)(() => {
|
|
112
|
+
const tally = new Map();
|
|
113
|
+
base.filter(inboxModel_1.isShown).forEach(({ entry }) => { var _a; return tally.set(entry.category, ((_a = tally.get(entry.category)) !== null && _a !== void 0 ? _a : 0) + 1); });
|
|
114
|
+
const present = Object.keys(categories).filter((key) => tally.has(key) || key === type);
|
|
115
|
+
return [
|
|
116
|
+
{ id: inboxModel_1.ALL_TYPES, label: labels.allTypes },
|
|
117
|
+
...present.map((key) => { var _a; return ({ id: key, label: `${categories[key].label} (${format.number((_a = tally.get(key)) !== null && _a !== void 0 ? _a : 0)})` }); }),
|
|
118
|
+
];
|
|
119
|
+
}, [base, categories, type, labels.allTypes, format]);
|
|
120
|
+
const visibleIds = (0, react_1.useMemo)(() => new Set(visibleItems.map((item) => item.entry.id)), [visibleItems]);
|
|
121
|
+
const leadThreads = (0, react_1.useMemo)(() => (0, inboxModel_1.threadsByLead)(groups), [groups]);
|
|
122
|
+
const checkedIds = (0, react_1.useMemo)(() => [...checked].filter((id) => visibleIds.has(id)), [checked, visibleIds]);
|
|
123
|
+
const checkedItems = (0, react_1.useMemo)(() => checkedIds.flatMap((id) => {
|
|
124
|
+
const item = find(id);
|
|
125
|
+
if (!item)
|
|
126
|
+
return [];
|
|
127
|
+
const thread = leadThreads.get(id);
|
|
128
|
+
return thread && !openThreads.has(id) ? (0, grouping_1.threadEntries)(thread).filter(inboxModel_1.isShown) : [item];
|
|
129
|
+
}), [checkedIds, find, leadThreads, openThreads]);
|
|
130
|
+
const select = (id, isExplicit) => {
|
|
131
|
+
setSelectedRaw(id);
|
|
132
|
+
if (id === null || !isExplicit)
|
|
133
|
+
return;
|
|
134
|
+
const item = find(id);
|
|
135
|
+
if (item && item.state.zone === "activity" && item.entry.isRead === false)
|
|
136
|
+
actions.setRead([id], true);
|
|
137
|
+
if (isPhone)
|
|
138
|
+
pendingFocus.current = { kind: "title" };
|
|
139
|
+
};
|
|
140
|
+
const clearChecked = () => setChecked(new Set());
|
|
141
|
+
const clearFilters = () => {
|
|
142
|
+
setQuery("");
|
|
143
|
+
setType(inboxModel_1.ALL_TYPES);
|
|
144
|
+
setUnreadOnly(false);
|
|
145
|
+
};
|
|
146
|
+
const latest = (0, react_1.useRef)({ select });
|
|
147
|
+
latest.current = { select };
|
|
148
|
+
const onOpenRow = (0, react_1.useCallback)((item) => latest.current.select(item.entry.id, true), []);
|
|
149
|
+
const onCheckedChange = (0, react_1.useCallback)((item, isChecked) => {
|
|
150
|
+
setChecked((current) => {
|
|
151
|
+
const next = new Set(current);
|
|
152
|
+
if (isChecked)
|
|
153
|
+
next.add(item.entry.id);
|
|
154
|
+
else
|
|
155
|
+
next.delete(item.entry.id);
|
|
156
|
+
return next;
|
|
157
|
+
});
|
|
158
|
+
}, []);
|
|
159
|
+
const onThreadToggle = (0, react_1.useCallback)((thread) => {
|
|
160
|
+
setOpenThreads((current) => {
|
|
161
|
+
const next = new Set(current);
|
|
162
|
+
if (!next.delete(thread.key))
|
|
163
|
+
next.add(thread.key);
|
|
164
|
+
return next;
|
|
165
|
+
});
|
|
166
|
+
}, []);
|
|
167
|
+
const linkRefFor = (0, react_1.useCallback)((id) => {
|
|
168
|
+
const cached = linkRefs.current.get(id);
|
|
169
|
+
if (cached)
|
|
170
|
+
return cached;
|
|
171
|
+
const ref = (element) => {
|
|
172
|
+
if (element)
|
|
173
|
+
links.current.set(id, element);
|
|
174
|
+
else
|
|
175
|
+
links.current.delete(id);
|
|
176
|
+
};
|
|
177
|
+
linkRefs.current.set(id, ref);
|
|
178
|
+
return ref;
|
|
179
|
+
}, []);
|
|
180
|
+
const goBack = () => {
|
|
181
|
+
if (selectedId !== null)
|
|
182
|
+
pendingFocus.current = { kind: "row", id: selectedId };
|
|
183
|
+
setSelectedRaw(null);
|
|
184
|
+
};
|
|
185
|
+
(0, react_1.useEffect)(() => {
|
|
186
|
+
clearChecked();
|
|
187
|
+
setType(inboxModel_1.ALL_TYPES);
|
|
188
|
+
}, [activeTab]);
|
|
189
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
190
|
+
var _a, _b;
|
|
191
|
+
const previous = orderRef.current;
|
|
192
|
+
orderRef.current = rowIds;
|
|
193
|
+
if (!isReady)
|
|
194
|
+
return;
|
|
195
|
+
if (selectedId === null) {
|
|
196
|
+
if (!isPhone && !isSelectionControlled && rowIds.length > 0)
|
|
197
|
+
setSelectedRaw(rowIds[0]);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!previous.includes(selectedId) || rowIds.includes(selectedId))
|
|
201
|
+
return;
|
|
202
|
+
if (isPhone) {
|
|
203
|
+
if (selectedItem === undefined || selectedItem.state.isHidden || selectedItem.state.zone === "archived") {
|
|
204
|
+
setSelectedRaw(null);
|
|
205
|
+
}
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const index = previous.indexOf(selectedId);
|
|
209
|
+
const after = previous.slice(index + 1).find((id) => rowIds.includes(id));
|
|
210
|
+
const before = previous.slice(0, index).reverse().find((id) => rowIds.includes(id));
|
|
211
|
+
const next = (_a = after !== null && after !== void 0 ? after : before) !== null && _a !== void 0 ? _a : null;
|
|
212
|
+
const active = document.activeElement;
|
|
213
|
+
const hadFocus = active === document.body || (((_b = rootRef.current) === null || _b === void 0 ? void 0 : _b.contains(active)) === true && !(0, inboxModel_1.isTypingTarget)(active));
|
|
214
|
+
if (next !== null && hadFocus)
|
|
215
|
+
pendingFocus.current = { kind: "row", id: next };
|
|
216
|
+
setSelectedRaw(next);
|
|
217
|
+
});
|
|
218
|
+
(0, react_1.useEffect)(() => {
|
|
219
|
+
const pending = pendingFocus.current;
|
|
220
|
+
if (!pending)
|
|
221
|
+
return;
|
|
222
|
+
if (pending.kind === "title" && isDetailOpen && titleRef.current) {
|
|
223
|
+
pendingFocus.current = null;
|
|
224
|
+
titleRef.current.focus();
|
|
225
|
+
}
|
|
226
|
+
else if (pending.kind === "row" && !isDetailOpen) {
|
|
227
|
+
const link = links.current.get(pending.id);
|
|
228
|
+
if (link) {
|
|
229
|
+
pendingFocus.current = null;
|
|
230
|
+
link.focus();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const filtersKey = `${activeTab}|${type}|${query}|${showUnreadOnly}`;
|
|
235
|
+
const lastFiltersKey = (0, react_1.useRef)(filtersKey);
|
|
236
|
+
(0, react_1.useEffect)(() => {
|
|
237
|
+
if (lastFiltersKey.current === filtersKey)
|
|
238
|
+
return undefined;
|
|
239
|
+
lastFiltersKey.current = filtersKey;
|
|
240
|
+
const timer = setTimeout(() => actions.announce(labels.results(visibleItems.length)), 500);
|
|
241
|
+
return () => clearTimeout(timer);
|
|
242
|
+
}, [filtersKey, actions, labels, visibleItems.length]);
|
|
243
|
+
const focusSearch = () => { var _a, _b; return (_b = (_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("input")) === null || _b === void 0 ? void 0 : _b.focus(); };
|
|
244
|
+
const move = (direction) => {
|
|
245
|
+
var _a;
|
|
246
|
+
if (rowIds.length === 0)
|
|
247
|
+
return;
|
|
248
|
+
const index = selectedId === null ? -1 : rowIds.indexOf(selectedId);
|
|
249
|
+
const next = rowIds[Math.max(0, Math.min(rowIds.length - 1, index < 0 ? 0 : index + direction))];
|
|
250
|
+
if (!isPhone)
|
|
251
|
+
select(next, true);
|
|
252
|
+
(_a = links.current.get(next)) === null || _a === void 0 ? void 0 : _a.focus();
|
|
253
|
+
};
|
|
254
|
+
const onKey = (event) => {
|
|
255
|
+
var _a, _b, _c;
|
|
256
|
+
const target = event.target;
|
|
257
|
+
const inside = target instanceof Node && rootRef.current !== null && rootRef.current.contains(target);
|
|
258
|
+
if (event.defaultPrevented || keysOpen || filtersOpen || (!inside && target !== document.body))
|
|
259
|
+
return;
|
|
260
|
+
const typing = (0, inboxModel_1.isTypingTarget)(target);
|
|
261
|
+
const isUndo = (event.ctrlKey || event.metaKey) && !event.altKey && event.key.toLowerCase() === "z";
|
|
262
|
+
if (typing) {
|
|
263
|
+
if (event.key === "Escape" && target instanceof HTMLInputElement && ((_a = searchRef.current) === null || _a === void 0 ? void 0 : _a.contains(target))) {
|
|
264
|
+
setQuery("");
|
|
265
|
+
target.blur();
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (isUndo) {
|
|
270
|
+
if (!actions.undoLast())
|
|
271
|
+
actions.announce(labels.nothingToUndo);
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (event.metaKey || event.ctrlKey || event.altKey)
|
|
276
|
+
return;
|
|
277
|
+
const inList = target instanceof Node && ((_c = (_b = rootRef.current) === null || _b === void 0 ? void 0 : _b.querySelector('[role="tabpanel"]')) === null || _c === void 0 ? void 0 : _c.contains(target)) === true;
|
|
278
|
+
const handled = (() => {
|
|
279
|
+
switch (event.key) {
|
|
280
|
+
case "/":
|
|
281
|
+
focusSearch();
|
|
282
|
+
return true;
|
|
283
|
+
case "j":
|
|
284
|
+
move(1);
|
|
285
|
+
return true;
|
|
286
|
+
case "k":
|
|
287
|
+
move(-1);
|
|
288
|
+
return true;
|
|
289
|
+
case "ArrowDown":
|
|
290
|
+
if (inList)
|
|
291
|
+
move(1);
|
|
292
|
+
return inList;
|
|
293
|
+
case "ArrowUp":
|
|
294
|
+
if (inList)
|
|
295
|
+
move(-1);
|
|
296
|
+
return inList;
|
|
297
|
+
case "?":
|
|
298
|
+
setKeysOpen(true);
|
|
299
|
+
return true;
|
|
300
|
+
case "z":
|
|
301
|
+
if (!actions.undoLast())
|
|
302
|
+
actions.announce(labels.nothingToUndo);
|
|
303
|
+
return true;
|
|
304
|
+
case "Escape":
|
|
305
|
+
if (checked.size === 0)
|
|
306
|
+
return false;
|
|
307
|
+
clearChecked();
|
|
308
|
+
return true;
|
|
309
|
+
default:
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
if (!selectedItem || isOffline)
|
|
313
|
+
return false;
|
|
314
|
+
const { entry, state } = selectedItem;
|
|
315
|
+
switch (event.key) {
|
|
316
|
+
case "o":
|
|
317
|
+
actions.open(entry);
|
|
318
|
+
return true;
|
|
319
|
+
case "u":
|
|
320
|
+
if (!features.markRead || entry.isRead === undefined)
|
|
321
|
+
return false;
|
|
322
|
+
actions.setRead([entry.id], !entry.isRead);
|
|
323
|
+
return true;
|
|
324
|
+
case "e":
|
|
325
|
+
if (state.zone === "activity" && features.archive)
|
|
326
|
+
actions.archive([entry.id]);
|
|
327
|
+
else if (state.zone === "archived" && features.restore)
|
|
328
|
+
actions.restore([entry.id]);
|
|
329
|
+
else
|
|
330
|
+
return false;
|
|
331
|
+
return true;
|
|
332
|
+
case "x":
|
|
333
|
+
if (!canSelect || !visibleIds.has(entry.id))
|
|
334
|
+
return false;
|
|
335
|
+
onCheckedChange(selectedItem, !checked.has(entry.id));
|
|
336
|
+
return true;
|
|
337
|
+
default:
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
})();
|
|
341
|
+
if (handled)
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
};
|
|
344
|
+
const keyRef = (0, react_1.useRef)(onKey);
|
|
345
|
+
keyRef.current = onKey;
|
|
346
|
+
(0, react_1.useEffect)(() => {
|
|
347
|
+
const listener = (event) => keyRef.current(event);
|
|
348
|
+
document.addEventListener("keydown", listener);
|
|
349
|
+
return () => document.removeEventListener("keydown", listener);
|
|
350
|
+
}, []);
|
|
351
|
+
const unreadHere = visibleItems.some((item) => item.entry.isRead === false);
|
|
352
|
+
const markAllRead = () => {
|
|
353
|
+
if (activeTab === "archived")
|
|
354
|
+
return;
|
|
355
|
+
actions.markAllRead({
|
|
356
|
+
zone: activeTab,
|
|
357
|
+
category: type === inboxModel_1.ALL_TYPES ? undefined : type,
|
|
358
|
+
query: query.trim() === "" ? undefined : query.trim(),
|
|
359
|
+
});
|
|
360
|
+
};
|
|
361
|
+
const bulkActions = (0, react_1.useMemo)(() => {
|
|
362
|
+
const ids = checkedItems.map((item) => item.entry.id);
|
|
363
|
+
const afterwards = (run) => () => {
|
|
364
|
+
run();
|
|
365
|
+
clearChecked();
|
|
366
|
+
};
|
|
367
|
+
const result = [];
|
|
368
|
+
if (checkedIds.length < visibleItems.length) {
|
|
369
|
+
result.push({ id: "select-all", label: labels.selectAll, onClick: () => setChecked(new Set(visibleIds)) });
|
|
370
|
+
}
|
|
371
|
+
const decision = features.decide ? (0, inboxModel_1.bulkDecision)(checkedItems) : undefined;
|
|
372
|
+
if (decision) {
|
|
373
|
+
result.push({
|
|
374
|
+
id: "decide",
|
|
375
|
+
label: labels.bulkDecide(decision.label, checkedIds.length),
|
|
376
|
+
tone: "primary",
|
|
377
|
+
icon: lucide_react_1.Check,
|
|
378
|
+
isDisabled: isOffline,
|
|
379
|
+
onClick: afterwards(() => actions.decide(ids, decision)),
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
const unread = checkedItems.filter((item) => item.entry.isRead === false).map((item) => item.entry.id);
|
|
383
|
+
const read = checkedItems.filter((item) => item.entry.isRead === true).map((item) => item.entry.id);
|
|
384
|
+
if (features.markRead && unread.length > 0) {
|
|
385
|
+
result.push({ id: "read", label: labels.markRead, icon: lucide_react_1.MailOpen, isDisabled: isOffline, onClick: afterwards(() => actions.setRead(unread, true)) });
|
|
386
|
+
}
|
|
387
|
+
else if (features.markRead && read.length > 0) {
|
|
388
|
+
result.push({ id: "unread", label: labels.markUnread, icon: lucide_react_1.Mail, isDisabled: isOffline, onClick: afterwards(() => actions.setRead(read, false)) });
|
|
389
|
+
}
|
|
390
|
+
if (activeTab === "activity" && features.archive) {
|
|
391
|
+
result.push({ id: "archive", label: labels.archive, icon: lucide_react_1.Archive, isDisabled: isOffline, onClick: afterwards(() => actions.archive(ids)) });
|
|
392
|
+
}
|
|
393
|
+
if (activeTab === "archived" && features.restore) {
|
|
394
|
+
result.push({ id: "restore", label: labels.restore, icon: lucide_react_1.Archive, isDisabled: isOffline, onClick: afterwards(() => actions.restore(ids)) });
|
|
395
|
+
}
|
|
396
|
+
return result;
|
|
397
|
+
}, [checkedItems, checkedIds.length, visibleItems.length, visibleIds, features, labels, isOffline, activeTab, actions]);
|
|
398
|
+
const tabItems = [
|
|
399
|
+
{ id: "needsYou", label: labels.needsYouTab, count: counts.needsYou > 0 ? counts.needsYou : undefined },
|
|
400
|
+
{ id: "activity", label: labels.activityTab, count: counts.unread > 0 ? counts.unread : undefined },
|
|
401
|
+
...(features.archive ? [{ id: "archived", label: labels.archivedTab }] : []),
|
|
402
|
+
];
|
|
403
|
+
const typeSelect = ((0, jsx_runtime_1.jsx)(Select_1.default, { native: false, isSearchable: false, size: isPhone ? "md" : "sm", "aria-label": labels.typeFilter, options: typeOptions, value: type, isDisabled: !isReady, width: isPhone ? "100%" : "11rem", onChange: (option) => setType(option === undefined ? inboxModel_1.ALL_TYPES : String(option.id)) }));
|
|
404
|
+
const unreadSwitch = activeTab !== "needsYou" && ((0, jsx_runtime_1.jsx)(ToggleSwitch_1.default, { size: isPhone ? "md" : "sm", label: labels.unreadOnly, isChecked: showUnreadOnly, isDisabled: !isReady, onChange: setUnreadOnly }));
|
|
405
|
+
const search = ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { ref: searchRef, minW: isPhone ? 0 : "15rem", flex: isPhone ? 1 : undefined, children: (0, jsx_runtime_1.jsx)(Search_1.default, { size: isPhone ? "md" : "sm", placeholder: labels.search, "aria-label": labels.search, shortcut: false, query: query, isDisabled: !isReady, onSearch: (event) => setQuery(event.target.value), onClear: () => {
|
|
406
|
+
setQuery("");
|
|
407
|
+
focusSearch();
|
|
408
|
+
} }) }));
|
|
409
|
+
const bulkBar = ((0, jsx_runtime_1.jsx)(BulkSelectionBar_1.default, { placement: "inline", selectedCount: checkedIds.length, countLabel: labels.selected(checkedIds.length), actions: bulkActions, clearLabel: labels.clearSelection, onClearSelection: clearChecked, "data-testid": testId ? `${testId}-bulk` : undefined }));
|
|
410
|
+
const toolbar = checkedIds.length > 0 ? ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { flex: 1, minW: 0, py: 2, children: bulkBar })) : isPhone ? ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { gap: 2, align: "center", w: "100%", py: 2, children: [search, (0, jsx_runtime_1.jsxs)(Primitives_1.Box, { position: "relative", flexShrink: 0, children: [(0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "md", variant: "ghost", colorScheme: "gray", "aria-label": labels.filters, "aria-haspopup": "dialog", icon: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.SlidersHorizontal, boxSize: 5, "aria-hidden": "true" }), onClick: () => setFiltersOpen(true) }), (type !== inboxModel_1.ALL_TYPES || showUnreadOnly) && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { position: "absolute", top: 2, right: 2, boxSize: 2, borderRadius: "full", bg: colors.primary[500], "aria-hidden": "true" }))] })] })) : ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { ml: "auto", py: 2, children: (0, jsx_runtime_1.jsxs)(FilterBar_1.default, { search: search, searchLabel: labels.search, children: [typeSelect, unreadSwitch] }) }));
|
|
411
|
+
const showMarkAll = features.markAllRead && isReady && activeTab !== "archived";
|
|
412
|
+
const headerActions = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showMarkAll &&
|
|
413
|
+
(isPhone ? ((0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: labels.markAllRead, children: (0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "md", variant: "ghost", colorScheme: "gray", "aria-label": labels.markAllRead, icon: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.CheckCheck, boxSize: 5, "aria-hidden": "true" }), isDisabled: !unreadHere || isOffline, onClick: markAllRead }) })) : ((0, jsx_runtime_1.jsx)(Button_1.default, { size: "sm", variant: "outline", colorScheme: "gray", leftIcon: (0, jsx_runtime_1.jsx)(lucide_react_1.CheckCheck, { size: 16, "aria-hidden": "true" }), label: labels.markAllRead, isDisabled: !unreadHere || isOffline, onClick: markAllRead }))), !isPhone && ((0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: labels.keyboardShortcuts, children: (0, jsx_runtime_1.jsx)(IconButton_1.default, { size: "sm", variant: "ghost", colorScheme: "gray", "aria-label": labels.keyboardShortcuts, icon: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.Keyboard, boxSize: 4, "aria-hidden": "true" }), onClick: () => setKeysOpen(true) }) })), onOpenSettings && ((0, jsx_runtime_1.jsx)(ToolTip_1.default, { label: labels.settings, children: (0, jsx_runtime_1.jsx)(IconButton_1.default, { size: isPhone ? "md" : "sm", variant: "ghost", colorScheme: "gray", "aria-label": labels.settings, icon: (0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.Settings, boxSize: isPhone ? 5 : 4, "aria-hidden": "true" }), onClick: onOpenSettings }) }))] }));
|
|
414
|
+
const loadMore = hasMore && features.loadMore ? ((0, jsx_runtime_1.jsx)(Primitives_1.Flex, { justify: "center", p: 3, children: (0, jsx_runtime_1.jsx)(Button_1.default, { size: isPhone ? "md" : "sm", variant: "outline", colorScheme: "gray", label: labels.loadMore, isLoading: isLoadingMore, onClick: actions.loadMore }) })) : null;
|
|
415
|
+
let listBody;
|
|
416
|
+
if (status === "loading")
|
|
417
|
+
listBody = (0, jsx_runtime_1.jsx)(InboxStates_1.InboxSkeleton, { isPhone: isPhone, label: labels.loading });
|
|
418
|
+
else if (status === "error" || status === "noAccess") {
|
|
419
|
+
listBody = (0, jsx_runtime_1.jsx)(InboxStates_1.InboxLoadFailure, { kind: status, labels: labels, appName: appName, onRetry: actions.retryLoad });
|
|
420
|
+
}
|
|
421
|
+
else if (visibleItems.length === 0) {
|
|
422
|
+
listBody =
|
|
423
|
+
filterCount > 0 && base.some(inboxModel_1.isShown) ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FilteredEmptyState_1.default, { scale: "card", filterCount: filterCount, onClearFilters: clearFilters }), loadMore] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(InboxStates_1.InboxEmpty, { tab: activeTab, labels: labels }), loadMore] }));
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
listBody = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(InboxList_1.InboxList, { groups: groups, isPhone: isPhone, selectedId: selectedId, checked: checked, openThreads: openThreads, idPrefix: baseId, onOpenRow: onOpenRow, onCheckedChange: canSelect ? onCheckedChange : undefined, onThreadToggle: onThreadToggle, linkRefFor: linkRefFor }), loadMore] }));
|
|
427
|
+
}
|
|
428
|
+
const detail = selectedItem ? ((0, jsx_runtime_1.jsx)(NotificationDetail_1.default, { item: selectedItem, variant: isPhone ? "phone" : "desktop", onBack: goBack, titleRef: titleRef }, selectedItem.entry.id)) : ((0, jsx_runtime_1.jsx)(EmptyState_1.default, { size: "md", icon: lucide_react_1.Inbox, colorScheme: "gray", title: labels.nothingSelected, description: labels.nothingSelectedHint, minH: "100%" }));
|
|
429
|
+
const scroll = (0, scrollbar_1.scrollbarStyles)(colors, "hover");
|
|
430
|
+
return ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { ref: rootRef, direction: "column", h: "100%", minH: isPhone ? undefined : "32rem", "data-testid": testId, children: [(0, jsx_runtime_1.jsxs)(Primitives_1.Box, { display: isDetailOpen ? "none" : "block", flexShrink: 0, px: isPhone ? 4 : 0, pt: isPhone ? 4 : 0, pb: isPhone ? 3 : 0, children: [(0, jsx_runtime_1.jsx)(PageHeader_1.default, { title: labels.title, subtitle: isReady ? labels.subtitle(counts) : appName, actions: headerActions }), isOffline && ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { align: "flex-start", gap: 2, mt: 3, px: 4, py: 2, fontSize: "xs", bg: colors.backgroundColor.subtle, color: colors.text[800], borderRadius: isPhone ? undefined : radii_1.RADIUS_ROLE.control, children: [(0, jsx_runtime_1.jsx)(Primitives_1.Icon, { as: lucide_react_1.WifiOff, boxSize: 3.5, mt: 0.5, "aria-hidden": "true" }), (0, jsx_runtime_1.jsx)(Primitives_1.Text, { children: labels.offlineMessage })] }))] }), (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { direction: "column", flex: 1, minH: 0, mt: isPhone ? 0 : 4, bg: plane, border: isPhone ? undefined : outline, borderRadius: isPhone ? undefined : radii_1.RADIUS_ROLE.card, overflow: "hidden", children: [(0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { display: isDetailOpen ? "none" : "flex", flexShrink: 0, direction: isPhone ? "column" : "row", wrap: "wrap", align: isPhone ? "stretch" : "flex-end", justify: "space-between", columnGap: 4, px: isPhone ? 2 : 3, pt: isPhone ? 0 : 2, pb: 0, borderBottom: rule, children: [(0, jsx_runtime_1.jsx)(Tabs_1.default, { id: baseId, "aria-label": labels.listsLabel, size: isPhone ? "md" : "sm", items: tabItems, value: activeTab, onChange: (value) => setTab(TAB_BY_ID[value]) }), toolbar] }), (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { flex: 1, minH: 0, display: isDetailOpen ? "none" : "flex", children: [(0, jsx_runtime_1.jsx)(Primitives_1.Box, { role: "tabpanel", id: `${baseId}-panel`, "aria-labelledby": `${baseId}-tab-${activeTab}`, "aria-busy": status === "loading" ? true : undefined, flex: isPhone ? 1 : undefined, w: isPhone ? undefined : "clamp(17.5rem, 32%, 22.5rem)", flexShrink: 0, minW: 0, overflowY: "auto", borderRight: isPhone ? undefined : rule, pt: 1, sx: scroll, children: listBody }), !isPhone && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { flex: 1, minW: 0, overflowY: "auto", sx: scroll, children: isReady ? detail : null }))] }), isDetailOpen && ((0, jsx_runtime_1.jsx)(Primitives_1.Box, { flex: 1, overflowY: "auto", sx: scroll, children: detail }))] }), (0, jsx_runtime_1.jsx)(ShortcutsDialog_1.ShortcutsDialog, { isOpen: keysOpen, onClose: () => setKeysOpen(false), labels: labels }), isPhone && ((0, jsx_runtime_1.jsxs)(Drawer_1.default, { isOpen: filtersOpen, onClose: () => setFiltersOpen(false), placement: "bottom", size: "md", children: [(0, jsx_runtime_1.jsx)(Drawer_1.DrawerHeader, { children: labels.filters }), (0, jsx_runtime_1.jsx)(Drawer_1.DrawerBody, { children: (0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { direction: "column", gap: 4, children: [typeSelect, unreadSwitch] }) })] }))] }));
|
|
431
|
+
};
|
|
432
|
+
/** Full-page inbox: Needs you, Activity and Archived tabs, search, a type filter, bulk actions and a reading pane. */
|
|
433
|
+
const NotificationInbox = (props) => ((0, jsx_runtime_1.jsx)(NotificationCenterProvider_1.NotificationScope, { source: props, children: (0, jsx_runtime_1.jsx)(NotificationInboxBody, { ...props }) }));
|
|
434
|
+
exports.default = NotificationInbox;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { NotificationCounts, NotificationLabels, NotificationSourceBinding } from "../core/NotificationSourceProps";
|
|
2
|
+
/** Strings the inbox page adds to the shared ones; anything left out stays English. */
|
|
3
|
+
export interface NotificationInboxLabels extends NotificationLabels {
|
|
4
|
+
/** Page heading. */
|
|
5
|
+
title: string;
|
|
6
|
+
/** Muted line under the heading, built from the server counts. */
|
|
7
|
+
subtitle: (counts: NotificationCounts) => string;
|
|
8
|
+
/** Accessible name of the tab list. */
|
|
9
|
+
listsLabel: string;
|
|
10
|
+
/** Decisions and unread mentions. */
|
|
11
|
+
needsYouTab: string;
|
|
12
|
+
/** Everything else. */
|
|
13
|
+
activityTab: string;
|
|
14
|
+
/** Only with `onArchive`. */
|
|
15
|
+
archivedTab: string;
|
|
16
|
+
/** Search field label and placeholder. */
|
|
17
|
+
search: string;
|
|
18
|
+
/** Type filter label. */
|
|
19
|
+
typeFilter: string;
|
|
20
|
+
/** The type filter's first option. */
|
|
21
|
+
allTypes: string;
|
|
22
|
+
/** Unread-only switch. */
|
|
23
|
+
unreadOnly: string;
|
|
24
|
+
/** Phone button and sheet title for the type filter and the unread switch. */
|
|
25
|
+
filters: string;
|
|
26
|
+
/** Header action for the open tab and filters. */
|
|
27
|
+
markAllRead: string;
|
|
28
|
+
/** Header gear. */
|
|
29
|
+
settings: string;
|
|
30
|
+
/** Header button and dialog title for the keyboard shortcuts. */
|
|
31
|
+
keyboardShortcuts: string;
|
|
32
|
+
/** Muted line under the shortcuts dialog title. */
|
|
33
|
+
shortcutsHint: string;
|
|
34
|
+
/** One line per shortcut in the help dialog. */
|
|
35
|
+
shortcuts: {
|
|
36
|
+
next: string;
|
|
37
|
+
previous: string;
|
|
38
|
+
show: string;
|
|
39
|
+
openInApp: string;
|
|
40
|
+
toggleRead: string;
|
|
41
|
+
archive: string;
|
|
42
|
+
select: string;
|
|
43
|
+
undo: string;
|
|
44
|
+
search: string;
|
|
45
|
+
clear: string;
|
|
46
|
+
help: string;
|
|
47
|
+
};
|
|
48
|
+
/** The bulk bar's count. */
|
|
49
|
+
selected: (count: number) => string;
|
|
50
|
+
/** Bulk bar button that selects every row in view. */
|
|
51
|
+
selectAll: string;
|
|
52
|
+
/** Bulk bar button that drops the selection. */
|
|
53
|
+
clearSelection: string;
|
|
54
|
+
/** Bulk decision button, e.g. "Approve 3". */
|
|
55
|
+
bulkDecide: (actionLabel: string, count: number) => string;
|
|
56
|
+
/** Empty reading pane title. */
|
|
57
|
+
nothingSelected: string;
|
|
58
|
+
/** Empty reading pane hint. */
|
|
59
|
+
nothingSelectedHint: string;
|
|
60
|
+
/** Spoken when Undo has nothing left to undo. */
|
|
61
|
+
nothingToUndo: string;
|
|
62
|
+
/** Spoken after a search or filter change. */
|
|
63
|
+
results: (count: number) => string;
|
|
64
|
+
/** Needs you is empty. */
|
|
65
|
+
caughtUpTitle: string;
|
|
66
|
+
caughtUpBody: string;
|
|
67
|
+
/** Activity is empty. */
|
|
68
|
+
activityEmptyTitle: string;
|
|
69
|
+
activityEmptyBody: string;
|
|
70
|
+
/** Archived is empty. */
|
|
71
|
+
archivedEmptyTitle: string;
|
|
72
|
+
archivedEmptyBody: string;
|
|
73
|
+
/** The list failed to load. */
|
|
74
|
+
loadErrorTitle: string;
|
|
75
|
+
loadErrorBody: string;
|
|
76
|
+
/** The person's role cannot see notifications. */
|
|
77
|
+
noAccessTitle: string;
|
|
78
|
+
noAccessBody: (appName?: string) => string;
|
|
79
|
+
/** Accessible name of the list while it loads. */
|
|
80
|
+
loading: string;
|
|
81
|
+
/** Button below the list when `hasMore`. */
|
|
82
|
+
loadMore: string;
|
|
83
|
+
}
|
|
84
|
+
/** The inbox lists; Archived exists only with `onArchive`. */
|
|
85
|
+
export type NotificationInboxTab = "needsYou" | "activity" | "archived";
|
|
86
|
+
/** "desktop" is list plus reading pane; "phone" shows one at a time with a Back button. */
|
|
87
|
+
export type NotificationInboxVariant = "desktop" | "phone";
|
|
88
|
+
/** Full-page inbox: tabs, type filter, search, bulk actions and a reading pane; pass the source props or use a provider. */
|
|
89
|
+
export type NotificationInboxProps = NotificationSourceBinding & {
|
|
90
|
+
/** Defaults to "desktop". */
|
|
91
|
+
variant?: NotificationInboxVariant;
|
|
92
|
+
/** Controlled tab; leave it out to start on Needs you. */
|
|
93
|
+
tab?: NotificationInboxTab;
|
|
94
|
+
/** Called when the person switches tabs. */
|
|
95
|
+
onTabChange?: (tab: NotificationInboxTab) => void;
|
|
96
|
+
/** Controlled reading-pane entry id, e.g. from the URL; null shows nothing. Leave it out and desktop opens the first row. */
|
|
97
|
+
selectedId?: string | null;
|
|
98
|
+
/** Called when the reading pane opens or closes an entry. */
|
|
99
|
+
onSelectedChange?: (id: string | null) => void;
|
|
100
|
+
/** Shows the settings gear in the header. */
|
|
101
|
+
onOpenSettings?: () => void;
|
|
102
|
+
/** Page strings; shared keys override the provider's for this component only. */
|
|
103
|
+
labels?: Partial<NotificationInboxLabels>;
|
|
104
|
+
/** Test id root for the page. */
|
|
105
|
+
"data-testid"?: string;
|
|
106
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { NotificationInboxLabels } from "./NotificationInboxProps";
|
|
2
|
+
interface ShortcutsDialogProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
labels: NotificationInboxLabels;
|
|
6
|
+
}
|
|
7
|
+
export declare const ShortcutsDialog: ({ isOpen, onClose, labels }: ShortcutsDialogProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.ShortcutsDialog = void 0;
|
|
40
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
41
|
+
const react_1 = require("react");
|
|
42
|
+
const Primitives_1 = require("../../Primitives/Primitives");
|
|
43
|
+
const Kbd_1 = __importDefault(require("../../Kbd/Kbd"));
|
|
44
|
+
const Modal_1 = __importStar(require("../../Modal/Modal"));
|
|
45
|
+
const useCustomTheme_1 = require("../../../Theme/useCustomTheme");
|
|
46
|
+
const ShortcutsDialog = ({ isOpen, onClose, labels }) => {
|
|
47
|
+
const { colors } = (0, useCustomTheme_1.useCustomTheme)();
|
|
48
|
+
const rows = [
|
|
49
|
+
[["j", "↓"], labels.shortcuts.next],
|
|
50
|
+
[["k", "↑"], labels.shortcuts.previous],
|
|
51
|
+
[[labels.keyEnter], labels.shortcuts.show],
|
|
52
|
+
[["o"], labels.shortcuts.openInApp],
|
|
53
|
+
[["u"], labels.shortcuts.toggleRead],
|
|
54
|
+
[["e"], labels.shortcuts.archive],
|
|
55
|
+
[["x"], labels.shortcuts.select],
|
|
56
|
+
[["z"], labels.shortcuts.undo],
|
|
57
|
+
[["/"], labels.shortcuts.search],
|
|
58
|
+
[[labels.keyEsc], labels.shortcuts.clear],
|
|
59
|
+
[["?"], labels.shortcuts.help],
|
|
60
|
+
];
|
|
61
|
+
return ((0, jsx_runtime_1.jsx)(Modal_1.default, { isOpen: isOpen, onClose: onClose, size: "sm", isCentered: true, title: labels.keyboardShortcuts, subtitle: labels.shortcutsHint, children: (0, jsx_runtime_1.jsx)(Modal_1.ModalBody, { children: (0, jsx_runtime_1.jsx)(Primitives_1.Flex, { as: "dl", direction: "column", gap: 2, m: 0, children: rows.map(([keys, name]) => ((0, jsx_runtime_1.jsxs)(Primitives_1.Flex, { justify: "space-between", align: "center", gap: 4, children: [(0, jsx_runtime_1.jsx)(Primitives_1.Text, { as: "dt", fontSize: "sm", color: colors.text[800], children: name }), (0, jsx_runtime_1.jsx)(Primitives_1.Flex, { as: "dd", gap: 1, align: "center", m: 0, children: keys.map((key, index) => ((0, jsx_runtime_1.jsxs)(react_1.Fragment, { children: [index > 0 && (0, jsx_runtime_1.jsx)(Primitives_1.Text, { color: colors.textMuted, children: "/" }), (0, jsx_runtime_1.jsx)(Kbd_1.default, { children: key })] }, key))) })] }, name))) }) }) }));
|
|
62
|
+
};
|
|
63
|
+
exports.ShortcutsDialog = ShortcutsDialog;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { NotificationFormatter } from "../core/NotificationEngineProps";
|
|
2
|
+
import type { NotificationLabels } from "../core/NotificationSourceProps";
|
|
3
|
+
import type { NotificationInboxLabels } from "./NotificationInboxProps";
|
|
4
|
+
export declare const withInboxLabels: (shared: NotificationLabels, format: NotificationFormatter, overrides?: Partial<NotificationInboxLabels>) => NotificationInboxLabels;
|