@remit/web-client 0.0.308 → 0.0.310
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/web-client",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.310",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Remit web client, published as composable primitives — the app shell, auth shells, and runtime config. A distributor imports what it composes and bundles it.",
|
|
6
6
|
"exports": {
|
|
@@ -73,6 +73,7 @@ export const OpenEvent: Story = {
|
|
|
73
73
|
export const RecurrenceScope: Story = {
|
|
74
74
|
args: { url: `${STORY_WEEK}/${STANDUP_OBJECT}/${STANDUP_RECURRENCE}` },
|
|
75
75
|
play: async () => {
|
|
76
|
+
await expect((await page().findAllByText("Standup"))[0]).toBeVisible();
|
|
76
77
|
await userEvent.click(await page().findByRole("button", { name: "Edit" }));
|
|
77
78
|
await expect(
|
|
78
79
|
await page().findByText("What should the change apply to?"),
|
|
@@ -327,57 +327,67 @@ const WiredComposeHeader = ({
|
|
|
327
327
|
// the keyboard down with it and started the cycle over.
|
|
328
328
|
const [expandedFor, setExpandedFor] = useState<number | undefined>(undefined);
|
|
329
329
|
const expanded = expandedFor === documentGeneration;
|
|
330
|
+
const [focusWithin, setFocusWithin] = useState(false);
|
|
330
331
|
|
|
331
332
|
return (
|
|
332
|
-
<
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
onPendingChange={onToPendingChange}
|
|
354
|
-
ref={fieldHandles.to}
|
|
355
|
-
/>
|
|
356
|
-
}
|
|
357
|
-
cc={
|
|
358
|
-
showCc ? (
|
|
359
|
-
<AddressField
|
|
360
|
-
label="Cc"
|
|
361
|
-
addresses={ccAddresses}
|
|
362
|
-
onChange={setCcAddresses}
|
|
363
|
-
ref={fieldHandles.cc}
|
|
333
|
+
<div
|
|
334
|
+
className="contents"
|
|
335
|
+
onFocusCapture={() => setFocusWithin(true)}
|
|
336
|
+
onBlurCapture={(event) => {
|
|
337
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
338
|
+
setFocusWithin(false);
|
|
339
|
+
}}
|
|
340
|
+
>
|
|
341
|
+
<ComposeHeader
|
|
342
|
+
collapsed={!isDesktop && isKeyboardOpen && !expanded && !focusWithin}
|
|
343
|
+
onExpand={() => setExpandedFor(documentGeneration)}
|
|
344
|
+
summary={composeHeaderSummary({
|
|
345
|
+
to: toAddresses,
|
|
346
|
+
cc: ccAddresses,
|
|
347
|
+
bcc: bccAddresses,
|
|
348
|
+
subject,
|
|
349
|
+
})}
|
|
350
|
+
from={
|
|
351
|
+
<FromSelector
|
|
352
|
+
selectedAccountId={selectedAccountId}
|
|
353
|
+
onSelect={onAccountChange}
|
|
364
354
|
/>
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
bcc={
|
|
368
|
-
showBcc ? (
|
|
355
|
+
}
|
|
356
|
+
to={
|
|
369
357
|
<AddressField
|
|
370
|
-
label="
|
|
371
|
-
addresses={
|
|
372
|
-
onChange={
|
|
373
|
-
|
|
358
|
+
label="To"
|
|
359
|
+
addresses={toAddresses}
|
|
360
|
+
onChange={setToAddresses}
|
|
361
|
+
placeholder="Recipients"
|
|
362
|
+
onPendingChange={onToPendingChange}
|
|
363
|
+
ref={fieldHandles.to}
|
|
374
364
|
/>
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
365
|
+
}
|
|
366
|
+
cc={
|
|
367
|
+
showCc ? (
|
|
368
|
+
<AddressField
|
|
369
|
+
label="Cc"
|
|
370
|
+
addresses={ccAddresses}
|
|
371
|
+
onChange={setCcAddresses}
|
|
372
|
+
ref={fieldHandles.cc}
|
|
373
|
+
/>
|
|
374
|
+
) : undefined
|
|
375
|
+
}
|
|
376
|
+
bcc={
|
|
377
|
+
showBcc ? (
|
|
378
|
+
<AddressField
|
|
379
|
+
label="Bcc"
|
|
380
|
+
addresses={bccAddresses}
|
|
381
|
+
onChange={setBccAddresses}
|
|
382
|
+
ref={fieldHandles.bcc}
|
|
383
|
+
/>
|
|
384
|
+
) : undefined
|
|
385
|
+
}
|
|
386
|
+
subject={<ComposeSubjectField value={subject} onChange={setSubject} />}
|
|
387
|
+
onShowCc={() => setShowCc(true)}
|
|
388
|
+
onShowBcc={() => setShowBcc(true)}
|
|
389
|
+
/>
|
|
390
|
+
</div>
|
|
381
391
|
);
|
|
382
392
|
};
|
|
383
393
|
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
import assert from "node:assert/strict";
|
|
16
16
|
import { afterEach, describe, it } from "node:test";
|
|
17
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
RemitImapAccountResponse,
|
|
19
|
+
RemitImapDescribeMessageResponse,
|
|
20
|
+
} from "@remit/api-http-client/types.gen.ts";
|
|
18
21
|
import {
|
|
19
22
|
type AnyRouter,
|
|
20
23
|
createMemoryHistory,
|
|
@@ -44,6 +47,20 @@ const account = {
|
|
|
44
47
|
smtpEnabled: true,
|
|
45
48
|
} as unknown as RemitImapAccountResponse;
|
|
46
49
|
|
|
50
|
+
const sourceMessage = {
|
|
51
|
+
message: { messageId: "msg-1" },
|
|
52
|
+
envelope: {
|
|
53
|
+
subject: "Lunch",
|
|
54
|
+
messageIdValue: "<m1@example.com>",
|
|
55
|
+
from: [{ normalizedEmail: "them@example.com", displayName: "Them" }],
|
|
56
|
+
replyTo: [],
|
|
57
|
+
to: [],
|
|
58
|
+
cc: [],
|
|
59
|
+
},
|
|
60
|
+
references: [],
|
|
61
|
+
bodyParts: [],
|
|
62
|
+
} as unknown as RemitImapDescribeMessageResponse;
|
|
63
|
+
|
|
47
64
|
interface VisualViewportStub {
|
|
48
65
|
height: number;
|
|
49
66
|
addEventListener: (type: string, listener: () => void) => void;
|
|
@@ -97,15 +114,22 @@ const testRouter = (): AnyRouter =>
|
|
|
97
114
|
history: createMemoryHistory({ initialEntries: ["/mail/mbx-1"] }),
|
|
98
115
|
}) as unknown as AnyRouter;
|
|
99
116
|
|
|
100
|
-
const Opened = () =>
|
|
117
|
+
const Opened = ({ mode }: { mode: "new" | "reply" }) =>
|
|
101
118
|
createElement(ComposeForm, {
|
|
102
|
-
mode
|
|
119
|
+
mode,
|
|
103
120
|
account,
|
|
121
|
+
sourceMessage: mode === "reply" ? sourceMessage : undefined,
|
|
104
122
|
onDraftCreated: () => {},
|
|
105
123
|
onClose: () => {},
|
|
106
124
|
});
|
|
107
125
|
|
|
108
|
-
const mount = async (
|
|
126
|
+
const mount = async ({
|
|
127
|
+
mode = "new",
|
|
128
|
+
keyboardOpen = true,
|
|
129
|
+
}: {
|
|
130
|
+
mode?: "new" | "reply";
|
|
131
|
+
keyboardOpen?: boolean;
|
|
132
|
+
} = {}): Promise<void> => {
|
|
109
133
|
http = mockFetch(async (call) => {
|
|
110
134
|
if (call.path.endsWith("/config")) return { accounts: [account] };
|
|
111
135
|
return { items: [] };
|
|
@@ -115,7 +139,9 @@ const mount = async (): Promise<void> => {
|
|
|
115
139
|
configurable: true,
|
|
116
140
|
value: viewport,
|
|
117
141
|
});
|
|
118
|
-
viewport.height =
|
|
142
|
+
viewport.height = keyboardOpen
|
|
143
|
+
? globalThis.window.innerHeight - KEYBOARD_HEIGHT
|
|
144
|
+
: globalThis.window.innerHeight;
|
|
119
145
|
|
|
120
146
|
harness = createDomHarness(PHONE);
|
|
121
147
|
harness.renderApp(
|
|
@@ -125,7 +151,7 @@ const mount = async (): Promise<void> => {
|
|
|
125
151
|
children: createElement(
|
|
126
152
|
ComposeProvider,
|
|
127
153
|
null,
|
|
128
|
-
createElement(Opened,
|
|
154
|
+
createElement(Opened, { mode }),
|
|
129
155
|
),
|
|
130
156
|
}),
|
|
131
157
|
);
|
|
@@ -171,4 +197,33 @@ describe("the phone compose header and the software keyboard", () => {
|
|
|
171
197
|
"the header did not collapse over the field being typed into",
|
|
172
198
|
);
|
|
173
199
|
});
|
|
200
|
+
|
|
201
|
+
it("keeps To mounted when a reply brings the keyboard up over it", async () => {
|
|
202
|
+
await mount({ mode: "reply", keyboardOpen: false });
|
|
203
|
+
|
|
204
|
+
const input = recipientInput();
|
|
205
|
+
assert.ok(input, "the rows are there while the keyboard is down");
|
|
206
|
+
|
|
207
|
+
act(() => {
|
|
208
|
+
input.focus();
|
|
209
|
+
});
|
|
210
|
+
setKeyboard(true);
|
|
211
|
+
await harness?.flush();
|
|
212
|
+
|
|
213
|
+
assert.equal(
|
|
214
|
+
recipientInput(),
|
|
215
|
+
input,
|
|
216
|
+
"the recipient field stayed mounted under the keyboard",
|
|
217
|
+
);
|
|
218
|
+
assert.equal(
|
|
219
|
+
globalThis.document.activeElement,
|
|
220
|
+
input,
|
|
221
|
+
"the recipient field kept focus",
|
|
222
|
+
);
|
|
223
|
+
assert.equal(
|
|
224
|
+
collapsedBar(),
|
|
225
|
+
null,
|
|
226
|
+
"the header did not collapse over the field being typed into",
|
|
227
|
+
);
|
|
228
|
+
});
|
|
174
229
|
});
|