@remit/web-client 0.0.56 → 0.0.58
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/package.json +1 -1
- package/src/components/mail/MailListHeader.tsx +26 -4
- package/src/components/mail/MailViewChrome.tsx +8 -0
- package/src/components/mail/MailboxPane.tsx +5 -0
- package/src/components/mail/MessageList.selection.test.ts +54 -0
- package/src/components/mail/MessageList.tsx +136 -66
- package/src/components/mail/SelectionToolbar.render.test.ts +129 -0
- package/src/components/mail/SelectionToolbar.stories.tsx +194 -0
- package/src/components/mail/SelectionToolbar.tsx +187 -73
- package/src/components/mail/organize/MobileOrganizeFlow.render.test.ts +45 -0
- package/src/components/mail/organize/MobileOrganizeFlow.tsx +138 -0
- package/src/components/mail/organize/OrganizePanel.render.test.ts +14 -1
- package/src/components/mail/organize/OrganizePanel.tsx +30 -4
- package/src/components/mail/organize/SomethingElsePanel.render.test.ts +54 -0
- package/src/components/mail/organize/SomethingElsePanel.tsx +159 -0
- package/src/components/mail/organize/smart-organize.stories.tsx +197 -0
- package/src/hooks/useEscalatedActions.ts +2 -2
- package/src/lib/organize/mobile-organize-flow.test.ts +96 -0
- package/src/lib/organize/mobile-organize-flow.ts +73 -0
- package/src/lib/search-surface.test.ts +74 -0
- package/src/lib/search-surface.ts +34 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, test } from "node:test";
|
|
3
|
+
import { showInlineSearchResults } from "./search-surface.js";
|
|
4
|
+
|
|
5
|
+
describe("showInlineSearchResults", () => {
|
|
6
|
+
test("phone never swaps in the inline panel — it keeps its takeover", () => {
|
|
7
|
+
assert.equal(
|
|
8
|
+
showInlineSearchResults({
|
|
9
|
+
tier: "phone",
|
|
10
|
+
hasLiveInput: true,
|
|
11
|
+
hasCommittedQuery: true,
|
|
12
|
+
bodyRendersCommittedResults: false,
|
|
13
|
+
}),
|
|
14
|
+
false,
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("no query means the normal list, on every tier", () => {
|
|
19
|
+
assert.equal(
|
|
20
|
+
showInlineSearchResults({
|
|
21
|
+
tier: "desktop",
|
|
22
|
+
hasLiveInput: false,
|
|
23
|
+
hasCommittedQuery: false,
|
|
24
|
+
bodyRendersCommittedResults: true,
|
|
25
|
+
}),
|
|
26
|
+
false,
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("a view without its own results body keeps the panel for any query", () => {
|
|
31
|
+
for (const hasCommittedQuery of [true, false]) {
|
|
32
|
+
for (const tier of ["tablet", "desktop"] as const) {
|
|
33
|
+
assert.equal(
|
|
34
|
+
showInlineSearchResults({
|
|
35
|
+
tier,
|
|
36
|
+
hasLiveInput: true,
|
|
37
|
+
hasCommittedQuery,
|
|
38
|
+
bodyRendersCommittedResults: false,
|
|
39
|
+
}),
|
|
40
|
+
true,
|
|
41
|
+
`${tier} committed=${hasCommittedQuery} should keep the panel`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("the mailbox route shows the panel while typing an uncommitted query", () => {
|
|
48
|
+
for (const tier of ["tablet", "desktop"] as const) {
|
|
49
|
+
assert.equal(
|
|
50
|
+
showInlineSearchResults({
|
|
51
|
+
tier,
|
|
52
|
+
hasLiveInput: true,
|
|
53
|
+
hasCommittedQuery: false,
|
|
54
|
+
bodyRendersCommittedResults: true,
|
|
55
|
+
}),
|
|
56
|
+
true,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("the mailbox route hands back to its selectable body once the query commits", () => {
|
|
62
|
+
for (const tier of ["tablet", "desktop"] as const) {
|
|
63
|
+
assert.equal(
|
|
64
|
+
showInlineSearchResults({
|
|
65
|
+
tier,
|
|
66
|
+
hasLiveInput: true,
|
|
67
|
+
hasCommittedQuery: true,
|
|
68
|
+
bodyRendersCommittedResults: true,
|
|
69
|
+
}),
|
|
70
|
+
false,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { LayoutTier } from "@/hooks/useLayoutTier";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which surface a list view shows its search on. Two surfaces exist:
|
|
5
|
+
*
|
|
6
|
+
* - the read-only two-engine `SearchResults` panel (literal "Top matches" +
|
|
7
|
+
* semantic "Related", cross-folder, spam offer), swapped into the list-pane
|
|
8
|
+
* body on tablet/desktop while searching; and
|
|
9
|
+
* - the view's own body — for the mailbox route a selectable `MessageList` whose
|
|
10
|
+
* threads filter to the committed search — which hosts multi-select and the
|
|
11
|
+
* "Select all N matching" escalation (#212).
|
|
12
|
+
*
|
|
13
|
+
* Phone never swaps: it shows the body and keeps the panel in its full-screen
|
|
14
|
+
* takeover instead, so this only decides tablet/desktop.
|
|
15
|
+
*
|
|
16
|
+
* A view whose body renders committed results itself (`bodyRendersCommittedResults`,
|
|
17
|
+
* the mailbox route) keeps the panel only while the query is still being typed —
|
|
18
|
+
* uncommitted, not yet mirrored to the URL — and hands back to the body the moment
|
|
19
|
+
* the query commits, so the committed search is a selectable list. Every other view
|
|
20
|
+
* (the brief, flagged, global search) leaves the flag off and keeps the panel for
|
|
21
|
+
* any query, committed or not.
|
|
22
|
+
*/
|
|
23
|
+
export const showInlineSearchResults = (input: {
|
|
24
|
+
tier: LayoutTier;
|
|
25
|
+
/** The live field value is non-empty (something is being searched). */
|
|
26
|
+
hasLiveInput: boolean;
|
|
27
|
+
/** The query has settled into the URL (`?q=`), i.e. it is committed. */
|
|
28
|
+
hasCommittedQuery: boolean;
|
|
29
|
+
/** This view's body renders the committed search as a selectable list. */
|
|
30
|
+
bodyRendersCommittedResults: boolean;
|
|
31
|
+
}): boolean =>
|
|
32
|
+
input.tier !== "phone" &&
|
|
33
|
+
input.hasLiveInput &&
|
|
34
|
+
!(input.bodyRendersCommittedResults && input.hasCommittedQuery);
|