@rapidmx/web-client 0.27.0 → 0.29.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/README.md +3 -0
- package/apps/shared/components/admin/diagnostics/DiagnosticsManager.tsx +22 -10
- package/apps/shared/components/admin/diagnostics/InformationPanel.tsx +60 -0
- package/apps/shared/components/admin/diagnostics/SettingsTable.tsx +108 -0
- package/apps/shared/components/admin/diagnostics/diagnosticsApi.ts +25 -1
- package/apps/shared/components/calendar/CalendarSearchBox.tsx +83 -0
- package/apps/shared/components/calendar/EventMatchNav.tsx +72 -0
- package/apps/shared/components/calendar/EventModal.tsx +33 -12
- package/apps/shared/components/calendar/ListView.tsx +207 -0
- package/apps/shared/components/calendar/MonthView.tsx +14 -2
- package/apps/shared/components/calendar/SlideIn.tsx +47 -0
- package/apps/shared/components/calendar/SplitDayView.tsx +5 -0
- package/apps/shared/components/calendar/TimeGridView.tsx +23 -12
- package/apps/shared/components/calendar/activeOccurrence.ts +28 -0
- package/apps/shared/components/calendar/allDay.ts +16 -1
- package/apps/shared/components/calendar/calendarView.ts +41 -0
- package/apps/shared/components/layout/AppShell.tsx +13 -6
- package/apps/shared/components/mail/ConversationList.tsx +32 -6
- package/apps/shared/components/mail/ConversationThreadPane.tsx +15 -0
- package/apps/shared/components/mail/MailSelectionBar.tsx +117 -55
- package/apps/shared/components/mail/MessageDetailPane.tsx +3 -0
- package/apps/shared/components/mail/compose/ComposeContext.tsx +193 -35
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +62 -11
- package/apps/shared/components/mail/compose/ComposeWindowPlaceholder.tsx +21 -10
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +2 -1
- package/apps/shared/components/mail/compose/quotedBody.ts +45 -2
- package/apps/shared/components/mail/labelMenu.tsx +4 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +9 -2
- package/apps/shared/components/mail/reading/MessageBody.tsx +1 -1
- package/apps/shared/components/mail/reading/bodyContent.ts +15 -13
- package/apps/shared/components/mail/reading/bodyHtml.ts +12 -7
- package/apps/shared/gestures/useEnterSlide.ts +1 -1
- package/apps/shared/keyboard/keymap.ts +2 -0
- package/apps/shared/mail/rangeSelection.ts +45 -0
- package/apps/shared/mail/rowExit.ts +39 -0
- package/apps/shared/mail/usePermanentDelete.tsx +14 -7
- package/apps/www/calendar/index.tsx +251 -53
- package/apps/www/index.tsx +563 -376
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.d.ts +3 -3
- package/dist/apps/shared/components/admin/diagnostics/DiagnosticsManager.js +15 -9
- package/dist/apps/shared/components/admin/diagnostics/InformationPanel.d.ts +15 -0
- package/dist/apps/shared/components/admin/diagnostics/InformationPanel.js +16 -0
- package/dist/apps/shared/components/admin/diagnostics/SettingsTable.d.ts +20 -0
- package/dist/apps/shared/components/admin/diagnostics/SettingsTable.js +31 -0
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.d.ts +20 -1
- package/dist/apps/shared/components/admin/diagnostics/diagnosticsApi.js +7 -0
- package/dist/apps/shared/components/calendar/CalendarSearchBox.d.ts +22 -0
- package/dist/apps/shared/components/calendar/CalendarSearchBox.js +24 -0
- package/dist/apps/shared/components/calendar/EventMatchNav.d.ts +17 -0
- package/dist/apps/shared/components/calendar/EventMatchNav.js +37 -0
- package/dist/apps/shared/components/calendar/EventModal.d.ts +17 -1
- package/dist/apps/shared/components/calendar/EventModal.js +13 -11
- package/dist/apps/shared/components/calendar/ListView.d.ts +30 -0
- package/dist/apps/shared/components/calendar/ListView.js +111 -0
- package/dist/apps/shared/components/calendar/MonthView.js +12 -3
- package/dist/apps/shared/components/calendar/SlideIn.d.ts +16 -0
- package/dist/apps/shared/components/calendar/SlideIn.js +32 -0
- package/dist/apps/shared/components/calendar/SplitDayView.js +5 -1
- package/dist/apps/shared/components/calendar/TimeGridView.js +11 -3
- package/dist/apps/shared/components/calendar/activeOccurrence.d.ts +15 -0
- package/dist/apps/shared/components/calendar/activeOccurrence.js +21 -0
- package/dist/apps/shared/components/calendar/allDay.d.ts +4 -0
- package/dist/apps/shared/components/calendar/allDay.js +14 -1
- package/dist/apps/shared/components/calendar/calendarView.d.ts +16 -0
- package/dist/apps/shared/components/calendar/calendarView.js +36 -0
- package/dist/apps/shared/components/layout/AppShell.js +8 -4
- package/dist/apps/shared/components/mail/ConversationList.d.ts +11 -3
- package/dist/apps/shared/components/mail/ConversationList.js +11 -3
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +9 -1
- package/dist/apps/shared/components/mail/MailSelectionBar.js +11 -4
- package/dist/apps/shared/components/mail/MessageDetailPane.js +3 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +31 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +123 -11
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +6 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +37 -11
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.d.ts +5 -1
- package/dist/apps/shared/components/mail/compose/ComposeWindowPlaceholder.js +10 -6
- package/dist/apps/shared/components/mail/compose/RichTextEditor.js +2 -1
- package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +3 -0
- package/dist/apps/shared/components/mail/compose/quotedBody.js +43 -1
- package/dist/apps/shared/components/mail/labelMenu.d.ts +3 -1
- package/dist/apps/shared/components/mail/labelMenu.js +2 -2
- package/dist/apps/shared/components/mail/layout/MailShell.js +7 -1
- package/dist/apps/shared/components/mail/reading/MessageBody.js +1 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.d.ts +5 -1
- package/dist/apps/shared/components/mail/reading/bodyContent.js +11 -11
- package/dist/apps/shared/components/mail/reading/bodyHtml.d.ts +3 -2
- package/dist/apps/shared/components/mail/reading/bodyHtml.js +8 -4
- package/dist/apps/shared/gestures/useEnterSlide.d.ts +2 -0
- package/dist/apps/shared/gestures/useEnterSlide.js +1 -1
- package/dist/apps/shared/keyboard/keymap.d.ts +12 -0
- package/dist/apps/shared/keyboard/keymap.js +2 -0
- package/dist/apps/shared/mail/rangeSelection.d.ts +20 -0
- package/dist/apps/shared/mail/rangeSelection.js +34 -0
- package/dist/apps/shared/mail/rowExit.d.ts +12 -0
- package/dist/apps/shared/mail/rowExit.js +33 -0
- package/dist/apps/shared/mail/usePermanentDelete.d.ts +2 -0
- package/dist/apps/shared/mail/usePermanentDelete.js +13 -8
- package/dist/apps/www/calendar/index.js +177 -18
- package/dist/apps/www/index.js +257 -93
- package/dist/lib/calendar/eventSearch.d.ts +42 -0
- package/dist/lib/calendar/eventSearch.js +152 -0
- package/dist/lib/components/navigation/BottomTabBar.d.ts +15 -3
- package/dist/lib/components/navigation/BottomTabBar.js +52 -15
- package/dist/lib/components/navigation/NavBadge.d.ts +13 -0
- package/dist/lib/components/navigation/NavBadge.js +18 -0
- package/dist/lib/mail/compose/quotedImages.d.ts +21 -0
- package/dist/lib/mail/compose/quotedImages.js +41 -0
- package/dist/lib/mail/inlineImages.d.ts +38 -0
- package/dist/lib/mail/inlineImages.js +90 -0
- package/dist/lib/mail/mailApi.d.ts +8 -1
- package/dist/lib/mail/mailApi.js +57 -5
- package/lib/calendar/eventSearch.ts +172 -0
- package/lib/components/navigation/BottomTabBar.tsx +107 -22
- package/lib/components/navigation/NavBadge.tsx +33 -0
- package/lib/mail/compose/quotedImages.ts +49 -0
- package/lib/mail/inlineImages.ts +104 -0
- package/lib/mail/mailApi.ts +64 -5
- package/package.json +1 -1
- package/apps/shared/components/admin/diagnostics/VersionsPanel.tsx +0 -36
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.d.ts +0 -10
- package/dist/apps/shared/components/admin/diagnostics/VersionsPanel.js +0 -11
|
@@ -15,6 +15,7 @@ import { useApiClient } from "../../../../lib/util/apiClientContext.js";
|
|
|
15
15
|
import { ROW_FOCUS_CLASS, UnreadBar, UnreadLabel, dateClass, isUnread, rowClass, senderClass, subjectClass } from "./unreadStyle.js";
|
|
16
16
|
import SwipeRow from "./SwipeRow.js";
|
|
17
17
|
import InviteRowChip from "./invite/InviteRowChip.js";
|
|
18
|
+
import { ClickModifiers, isSelectionClick } from "../../mail/rangeSelection.js";
|
|
18
19
|
|
|
19
20
|
/** A conversation row of the list. `mailboxUid` is set only by a view that merges several mailboxes ("All Mailboxes"), whose rows are
|
|
20
21
|
* each from a different one; a list of one mailbox's own leaves it out and every row is that mailbox's. */
|
|
@@ -47,9 +48,16 @@ export interface ConversationListProps {
|
|
|
47
48
|
* conversation is what this list's rows are. A child row stays a plain "open this message" button - a
|
|
48
49
|
* mixed conversation/message selection has no sensible bulk semantics (see `MailListToolbar`). */
|
|
49
50
|
selectMode?: boolean;
|
|
50
|
-
/** The `
|
|
51
|
+
/** The `conversationRowKey()`s currently ticked. */
|
|
51
52
|
selectedConversationIds?: Set<string>;
|
|
52
|
-
onToggleSelected?: (conversation:
|
|
53
|
+
onToggleSelected?: (conversation: ListedConversation) => void;
|
|
54
|
+
/**
|
|
55
|
+
* A Shift, Ctrl or Cmd click on a parent row (or on its checkbox): the caller extends or toggles the selection instead of this list opening or
|
|
56
|
+
* ticking the row itself (`onOpenMessage` / `onToggleSelected` are not called for it). Absent, those clicks behave as plain ones.
|
|
57
|
+
*/
|
|
58
|
+
onSelectWithModifier?: (conversation: ListedConversation, modifiers: ClickModifiers) => void;
|
|
59
|
+
/** The `conversationRowKey()`s of rows on their way out of the list (moved, deleted): drawn non-interactive and hidden from assistive technology while the page collapses them. */
|
|
60
|
+
exitingKeys?: Set<string>;
|
|
53
61
|
/**
|
|
54
62
|
* What swiping a parent row does on a phone: right to left archives the conversation (resolving whether it went through), left
|
|
55
63
|
* to right asks where to move it. Absent, or `enabled: false` (a desktop), rows don't follow a finger.
|
|
@@ -95,6 +103,8 @@ export default function ConversationList({
|
|
|
95
103
|
selectMode,
|
|
96
104
|
selectedConversationIds,
|
|
97
105
|
onToggleSelected,
|
|
106
|
+
onSelectWithModifier,
|
|
107
|
+
exitingKeys,
|
|
98
108
|
swipe,
|
|
99
109
|
newestFirst,
|
|
100
110
|
}: ConversationListProps) {
|
|
@@ -175,9 +185,16 @@ export default function ConversationList({
|
|
|
175
185
|
// list itself is arranged in. Copied before reversing - the fetched array is cached.
|
|
176
186
|
const children = loaded && newestFirst ? [...loaded].reverse() : loaded;
|
|
177
187
|
const panelId = `conversation-messages-${conversation.mailboxUid ? `${conversation.mailboxUid}-` : ""}${conversation.conversationId}`;
|
|
178
|
-
const ticked = selectedConversationIds?.has(
|
|
188
|
+
const ticked = selectedConversationIds?.has(id) ?? false;
|
|
189
|
+
const exiting = exitingKeys?.has(id) ?? false;
|
|
179
190
|
return (
|
|
180
|
-
<li
|
|
191
|
+
<li
|
|
192
|
+
key={id}
|
|
193
|
+
data-exiting={exiting ? "true" : undefined}
|
|
194
|
+
aria-hidden={exiting ? "true" : undefined}
|
|
195
|
+
inert={exiting}
|
|
196
|
+
className={exiting ? "pointer-events-none" : undefined}
|
|
197
|
+
>
|
|
181
198
|
<SwipeRow
|
|
182
199
|
as="div"
|
|
183
200
|
enabled={!!swipe?.enabled && !selectMode}
|
|
@@ -193,7 +210,12 @@ export default function ConversationList({
|
|
|
193
210
|
<input
|
|
194
211
|
type="checkbox"
|
|
195
212
|
checked={ticked}
|
|
196
|
-
onChange={() =>
|
|
213
|
+
onChange={(event) =>
|
|
214
|
+
// The change of a checkbox is caused by a click (or the Space key, which makes one): its modifiers are that event's.
|
|
215
|
+
onSelectWithModifier && isSelectionClick(event.nativeEvent as MouseEvent)
|
|
216
|
+
? onSelectWithModifier(conversation, event.nativeEvent as MouseEvent)
|
|
217
|
+
: onToggleSelected?.(conversation)
|
|
218
|
+
}
|
|
197
219
|
aria-label={`Select conversation: ${conversation.subject || "(no subject)"}`}
|
|
198
220
|
className="w-4 h-4 accent-primary"
|
|
199
221
|
/>
|
|
@@ -218,7 +240,11 @@ export default function ConversationList({
|
|
|
218
240
|
<button
|
|
219
241
|
type="button"
|
|
220
242
|
data-row-open
|
|
221
|
-
onClick={() =>
|
|
243
|
+
onClick={(event) =>
|
|
244
|
+
onSelectWithModifier && isSelectionClick(event)
|
|
245
|
+
? onSelectWithModifier(conversation, event)
|
|
246
|
+
: onOpenMessage(conversation, conversation.latestMessageUid)
|
|
247
|
+
}
|
|
222
248
|
className={["w-full text-left pr-4 py-3", ROW_FOCUS_CLASS].join(" ")}
|
|
223
249
|
>
|
|
224
250
|
<UnreadLabel unread={unread} />
|
|
@@ -15,6 +15,7 @@ import { ENCRYPTED_SUBJECT_PLACEHOLDER, EncryptedPreview, displaySubject } from
|
|
|
15
15
|
import { useDecryptedMessages } from "../../mail/decryptedMessages.js";
|
|
16
16
|
import { CollapsedCard, SkeletonCards, SubjectCard } from "./reading/MessageCard.js";
|
|
17
17
|
import PendingMessageCard from "./reading/PendingMessageCard.js";
|
|
18
|
+
import { InlineComposeSlot, useInlineCompose } from "./compose/ComposeContext.js";
|
|
18
19
|
import { useMailShell } from "./layout/MailShell.js";
|
|
19
20
|
import { setReadState } from "../../mail/messageReadState.js";
|
|
20
21
|
import { adoptedOutgoing, belongsToThread, settleOutgoing, useOutgoingReplies } from "../../mail/outbox/outgoingReplies.js";
|
|
@@ -202,6 +203,9 @@ export default function ConversationThreadPane({
|
|
|
202
203
|
const [error, setError] = useState<string | null>(null);
|
|
203
204
|
/** The message to scroll to and focus once it has rendered, or `null` once that has happened. */
|
|
204
205
|
const [pendingFocusUid, setPendingFocusUid] = useState<string | null>(null);
|
|
206
|
+
// The Reply / Reply all / Forward compose windows of this thread's messages, drawn as cards at the top of the list; the thread's messages are
|
|
207
|
+
// what makes the compose provider open a reply here rather than floating at the bottom right.
|
|
208
|
+
const inlineSessions = useInlineCompose(messages.map((message) => message.uid));
|
|
205
209
|
|
|
206
210
|
// Bumped on every conversation switch - an in-flight load/attachments/mark-read response carrying an
|
|
207
211
|
// older generation belongs to a superseded conversation and is dropped rather than applied.
|
|
@@ -538,6 +542,17 @@ export default function ConversationThreadPane({
|
|
|
538
542
|
</div>
|
|
539
543
|
) : (
|
|
540
544
|
<ul className="flex-1 min-h-0 overflow-y-auto p-2 sm:p-3 flex flex-col gap-3">
|
|
545
|
+
{inlineSessions.map((session) => (
|
|
546
|
+
<InlineComposeSlot
|
|
547
|
+
key={session.id}
|
|
548
|
+
id={session.id}
|
|
549
|
+
onPlaced={(slot) => {
|
|
550
|
+
// Brought into view like a message that has just been sent: the same scroll, inside the list.
|
|
551
|
+
rowRefs.current[session.id] = slot;
|
|
552
|
+
setPendingFocusUid(session.id);
|
|
553
|
+
}}
|
|
554
|
+
/>
|
|
555
|
+
))}
|
|
541
556
|
{pendingCards.map((reply) => (
|
|
542
557
|
<li
|
|
543
558
|
key={reply.uid}
|
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
// SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
///////////////////////////////////////////////////////////////////////////////
|
|
5
5
|
import React, { useState } from "react";
|
|
6
|
+
import {
|
|
7
|
+
HiOutlineArchiveBox,
|
|
8
|
+
HiOutlineCheckCircle,
|
|
9
|
+
HiOutlineEnvelope,
|
|
10
|
+
HiOutlineEnvelopeOpen,
|
|
11
|
+
HiOutlineFlag,
|
|
12
|
+
HiOutlineFolderArrowDown,
|
|
13
|
+
HiOutlineMinusCircle,
|
|
14
|
+
HiOutlineNoSymbol,
|
|
15
|
+
HiOutlineTrash,
|
|
16
|
+
HiOutlineXMark,
|
|
17
|
+
} from "react-icons/hi2";
|
|
6
18
|
import { Folder, Message } from "../../../../lib/mail/mailApi.js";
|
|
7
19
|
import { Label } from "../../../../lib/mail/labelsApi.js";
|
|
8
20
|
import LabelMenuButton from "./labelMenu.js";
|
|
@@ -65,8 +77,43 @@ export interface MailSelectionBarProps {
|
|
|
65
77
|
labelsDisabledReason?: string;
|
|
66
78
|
}
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
/** The look of the bar's icon buttons - the reading pane's own command row (`ICON_BUTTON_CLASS` in `MessageDetailPane`), without its border, which nine of them in a row don't need. */
|
|
81
|
+
function iconClassName(destructive = false): string {
|
|
82
|
+
return `inline-flex items-center justify-center p-1.5 rounded-md text-sm ${destructive ? "text-danger" : "text-text"} hover:bg-surface-alt disabled:opacity-50 disabled:hover:bg-transparent`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** One of the bar's actions as an icon button: the action's name is its `aria-label` (so it has the accessible name its text button had) and its tooltip,
|
|
86
|
+
* unless there is a `reason` it is unavailable, or a keyboard shortcut to name (`title` and `aria-keyshortcuts` from `hint()`). */
|
|
87
|
+
function BarAction({
|
|
88
|
+
icon,
|
|
89
|
+
label,
|
|
90
|
+
onClick,
|
|
91
|
+
disabled,
|
|
92
|
+
reason,
|
|
93
|
+
destructive,
|
|
94
|
+
hint,
|
|
95
|
+
}: {
|
|
96
|
+
icon: React.ReactNode;
|
|
97
|
+
label: string;
|
|
98
|
+
onClick: () => void;
|
|
99
|
+
disabled?: boolean;
|
|
100
|
+
reason?: string;
|
|
101
|
+
destructive?: boolean;
|
|
102
|
+
hint?: { title?: string; "aria-keyshortcuts"?: string };
|
|
103
|
+
}) {
|
|
104
|
+
return (
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
aria-label={label}
|
|
108
|
+
onClick={onClick}
|
|
109
|
+
disabled={disabled}
|
|
110
|
+
className={iconClassName(destructive)}
|
|
111
|
+
{...hint}
|
|
112
|
+
title={reason ?? hint?.title ?? label}
|
|
113
|
+
>
|
|
114
|
+
{icon}
|
|
115
|
+
</button>
|
|
116
|
+
);
|
|
70
117
|
}
|
|
71
118
|
|
|
72
119
|
/**
|
|
@@ -148,47 +195,67 @@ export default function MailSelectionBar({
|
|
|
148
195
|
onMove={onMoveTo}
|
|
149
196
|
onFolderCreated={onFolderCreated}
|
|
150
197
|
/>
|
|
151
|
-
<div className="flex items-center gap-
|
|
152
|
-
<span aria-live="polite" className="text-sm font-semibold text-text">
|
|
198
|
+
<div className="flex items-center gap-1 px-3 py-1.5 bg-surface-alt">
|
|
199
|
+
<span aria-live="polite" className="text-sm font-semibold text-text mr-auto">
|
|
153
200
|
{selectedCount}
|
|
154
201
|
{totals ? ` ${totals.noun}${selectedCount === 1 ? "" : "s"}` : ""} selected
|
|
155
202
|
</span>
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
<
|
|
163
|
-
|
|
164
|
-
</button>
|
|
203
|
+
<BarAction
|
|
204
|
+
icon={<HiOutlineCheckCircle size={16} aria-hidden="true" />}
|
|
205
|
+
label="Select all"
|
|
206
|
+
onClick={onSelectAll}
|
|
207
|
+
disabled={allSelected || listedCount === 0}
|
|
208
|
+
/>
|
|
209
|
+
<BarAction icon={<HiOutlineMinusCircle size={16} aria-hidden="true" />} label="Clear" onClick={onClearSelection} disabled={selectedCount === 0} />
|
|
210
|
+
<BarAction icon={<HiOutlineXMark size={16} aria-hidden="true" />} label="Cancel" onClick={onCancel} />
|
|
165
211
|
</div>
|
|
212
|
+
{/* Icon-only, so all nine fit one row of the 24rem list column; wraps if the column is ever narrower. */}
|
|
166
213
|
<div className="flex flex-wrap items-center gap-0.5 px-1.5 py-1">
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
214
|
+
<BarAction
|
|
215
|
+
icon={<HiOutlineEnvelopeOpen size={16} aria-hidden="true" />}
|
|
216
|
+
label="Mark read"
|
|
217
|
+
onClick={() => onSetRead(true)}
|
|
218
|
+
disabled={none || busy}
|
|
219
|
+
hint={hint("Mark read", SHORTCUTS.mail.markRead)}
|
|
220
|
+
/>
|
|
221
|
+
<BarAction
|
|
222
|
+
icon={<HiOutlineEnvelope size={16} aria-hidden="true" />}
|
|
223
|
+
label="Mark unread"
|
|
224
|
+
onClick={() => onSetRead(false)}
|
|
225
|
+
disabled={none || busy}
|
|
226
|
+
hint={hint("Mark unread", SHORTCUTS.mail.markUnread)}
|
|
227
|
+
/>
|
|
228
|
+
<BarAction
|
|
229
|
+
icon={<HiOutlineFlag size={16} aria-hidden="true" />}
|
|
230
|
+
label="Flag"
|
|
231
|
+
onClick={() => onSetFlagged(true)}
|
|
232
|
+
disabled={none || busy}
|
|
233
|
+
hint={hint("Flag", SHORTCUTS.mail.flag)}
|
|
234
|
+
/>
|
|
235
|
+
<BarAction
|
|
236
|
+
icon={
|
|
237
|
+
// `hi2` has no flag-with-a-line-through glyph: the flag, struck through.
|
|
238
|
+
<span className="relative inline-flex" aria-hidden="true">
|
|
239
|
+
<HiOutlineFlag size={16} />
|
|
240
|
+
<span className="absolute left-1/2 top-[-1px] h-[18px] w-[1.5px] -translate-x-1/2 rotate-45 rounded bg-current" />
|
|
241
|
+
</span>
|
|
242
|
+
}
|
|
243
|
+
label="Unflag"
|
|
244
|
+
onClick={() => onSetFlagged(false)}
|
|
245
|
+
disabled={none || busy}
|
|
246
|
+
/>
|
|
247
|
+
<BarAction
|
|
248
|
+
icon={<HiOutlineArchiveBox size={16} aria-hidden="true" />}
|
|
249
|
+
label="Archive"
|
|
181
250
|
onClick={onArchive}
|
|
182
251
|
disabled={none || busy || !!archiveReason}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
>
|
|
186
|
-
Archive
|
|
187
|
-
</button>
|
|
252
|
+
reason={archiveReason}
|
|
253
|
+
/>
|
|
188
254
|
<LabelMenuButton
|
|
189
255
|
aria-label="Apply label"
|
|
190
256
|
label="Apply label"
|
|
191
|
-
|
|
257
|
+
iconOnly
|
|
258
|
+
className={iconClassName()}
|
|
192
259
|
labels={labels}
|
|
193
260
|
mailboxUid={mailboxUid}
|
|
194
261
|
onLabelCreated={onLabelCreated}
|
|
@@ -197,7 +264,7 @@ export default function MailSelectionBar({
|
|
|
197
264
|
onCommit={onApplyLabels}
|
|
198
265
|
busy={busy}
|
|
199
266
|
disabled={none || busy || !!labelsDisabledReason}
|
|
200
|
-
title={labelsDisabledReason}
|
|
267
|
+
title={labelsDisabledReason ?? "Apply label"}
|
|
201
268
|
note={
|
|
202
269
|
selected.length === 1
|
|
203
270
|
? "Ticked labels are applied, unticked ones removed."
|
|
@@ -207,33 +274,28 @@ export default function MailSelectionBar({
|
|
|
207
274
|
commit={{ label: "Apply" }}
|
|
208
275
|
clear={{ label: "Remove all labels" }}
|
|
209
276
|
/>
|
|
210
|
-
<
|
|
211
|
-
|
|
277
|
+
<BarAction
|
|
278
|
+
icon={<HiOutlineFolderArrowDown size={16} aria-hidden="true" />}
|
|
279
|
+
label="Move to"
|
|
212
280
|
onClick={() => setMovePrompt(true)}
|
|
213
281
|
disabled={none || busy || !!moveDisabledReason}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
<button
|
|
220
|
-
type="button"
|
|
282
|
+
reason={moveDisabledReason}
|
|
283
|
+
/>
|
|
284
|
+
<BarAction
|
|
285
|
+
icon={<HiOutlineNoSymbol size={16} aria-hidden="true" />}
|
|
286
|
+
label="Report junk"
|
|
221
287
|
onClick={onReportJunk}
|
|
222
288
|
disabled={none || busy || !!junkReason}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
<button
|
|
229
|
-
type="button"
|
|
289
|
+
reason={junkReason}
|
|
290
|
+
/>
|
|
291
|
+
<BarAction
|
|
292
|
+
icon={<HiOutlineTrash size={16} aria-hidden="true" />}
|
|
293
|
+
label={deleteLabel}
|
|
230
294
|
onClick={onDelete}
|
|
231
295
|
disabled={none || busy}
|
|
232
|
-
|
|
233
|
-
{
|
|
234
|
-
|
|
235
|
-
{deleteLabel}
|
|
236
|
-
</button>
|
|
296
|
+
destructive={deletesPermanently}
|
|
297
|
+
hint={hint(deleteLabel, SHORTCUTS.mail.delete)}
|
|
298
|
+
/>
|
|
237
299
|
</div>
|
|
238
300
|
</div>
|
|
239
301
|
);
|
|
@@ -830,6 +830,7 @@ function MessageDetailContent({
|
|
|
830
830
|
mailboxUid: message.mailboxUid,
|
|
831
831
|
subject: forwardSubject(message.subject),
|
|
832
832
|
signatureContext: "reply_forward",
|
|
833
|
+
inlineFor: message.uid,
|
|
833
834
|
encrypt,
|
|
834
835
|
threading,
|
|
835
836
|
pending: late,
|
|
@@ -843,6 +844,8 @@ function MessageDetailContent({
|
|
|
843
844
|
subject: replySubject(message.subject),
|
|
844
845
|
signatureContext: "reply_forward",
|
|
845
846
|
suppressSigning: isLikelyMailingList({ listUnsubscribe: message.listUnsubscribeHeader }),
|
|
847
|
+
// A card above this message in the reading pane when it is in one, else the floating window (see `OpenComposeInput.inlineFor`).
|
|
848
|
+
inlineFor: message.uid,
|
|
846
849
|
encrypt,
|
|
847
850
|
threading,
|
|
848
851
|
pending: late,
|