@alepha/react 0.14.2 → 0.14.4
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/dist/auth/index.browser.js +29 -14
- package/dist/auth/index.browser.js.map +1 -1
- package/dist/auth/index.js +960 -195
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +7 -4
- package/dist/core/index.js.map +1 -1
- package/dist/head/index.browser.js +59 -19
- package/dist/head/index.browser.js.map +1 -1
- package/dist/head/index.d.ts +99 -560
- package/dist/head/index.d.ts.map +1 -1
- package/dist/head/index.js +92 -87
- package/dist/head/index.js.map +1 -1
- package/dist/router/index.browser.js +30 -15
- package/dist/router/index.browser.js.map +1 -1
- package/dist/router/index.d.ts +616 -192
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +961 -196
- package/dist/router/index.js.map +1 -1
- package/package.json +4 -4
- package/src/auth/__tests__/$auth.spec.ts +188 -0
- package/src/core/__tests__/Router.spec.tsx +169 -0
- package/src/core/hooks/useAction.browser.spec.tsx +569 -0
- package/src/core/hooks/useAction.ts +11 -0
- package/src/form/hooks/useForm.browser.spec.tsx +366 -0
- package/src/head/helpers/SeoExpander.spec.ts +203 -0
- package/src/head/hooks/useHead.spec.tsx +288 -0
- package/src/head/index.ts +11 -28
- package/src/head/providers/BrowserHeadProvider.browser.spec.ts +196 -0
- package/src/head/providers/BrowserHeadProvider.ts +25 -19
- package/src/head/providers/HeadProvider.ts +76 -10
- package/src/head/providers/ServerHeadProvider.ts +22 -138
- package/src/i18n/__tests__/integration.spec.tsx +239 -0
- package/src/i18n/components/Localize.spec.tsx +357 -0
- package/src/i18n/hooks/useI18n.browser.spec.tsx +438 -0
- package/src/i18n/providers/I18nProvider.spec.ts +389 -0
- package/src/router/__tests__/page-head-browser.browser.spec.ts +91 -0
- package/src/router/__tests__/page-head.spec.ts +44 -0
- package/src/router/__tests__/seo-head.spec.ts +121 -0
- package/src/router/atoms/ssrManifestAtom.ts +60 -0
- package/src/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
- package/src/router/errors/Redirection.ts +1 -1
- package/src/router/index.shared.ts +1 -0
- package/src/router/index.ts +16 -2
- package/src/router/primitives/$page.browser.spec.tsx +702 -0
- package/src/router/primitives/$page.spec.tsx +702 -0
- package/src/router/primitives/$page.ts +46 -10
- package/src/router/providers/ReactBrowserProvider.ts +14 -29
- package/src/router/providers/ReactBrowserRouterProvider.ts +5 -0
- package/src/router/providers/ReactPageProvider.ts +11 -4
- package/src/router/providers/ReactServerProvider.spec.tsx +316 -0
- package/src/router/providers/ReactServerProvider.ts +331 -315
- package/src/router/providers/ReactServerTemplateProvider.ts +775 -0
- package/src/router/providers/SSRManifestProvider.ts +365 -0
- package/src/router/services/ReactPageServerService.ts +5 -3
- package/src/router/services/ReactRouter.ts +3 -3
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { AlephaContext } from "@alepha/react";
|
|
2
|
+
import { I18nProvider, Localize } from "../index.ts";
|
|
3
|
+
import { Alepha, t } from "alepha";
|
|
4
|
+
import { DateTimeProvider } from "alepha/datetime";
|
|
5
|
+
import type { ReactNode } from "react";
|
|
6
|
+
import { renderToString } from "react-dom/server";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
|
|
9
|
+
describe("<Localize/>", () => {
|
|
10
|
+
const setup = () => {
|
|
11
|
+
const alepha = Alepha.create();
|
|
12
|
+
return {
|
|
13
|
+
i18n: alepha.inject(I18nProvider),
|
|
14
|
+
dateTime: alepha.inject(DateTimeProvider),
|
|
15
|
+
alepha,
|
|
16
|
+
render: (children: ReactNode) =>
|
|
17
|
+
renderToString(
|
|
18
|
+
<AlephaContext value={alepha}>{children}</AlephaContext>,
|
|
19
|
+
),
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
it("should format date", () => {
|
|
24
|
+
const { render, i18n } = setup();
|
|
25
|
+
const date = new Date("2024-09-23T23:45:00Z");
|
|
26
|
+
expect(render(<Localize value={date} />)).toBe("9/24/2024");
|
|
27
|
+
i18n.setLang("fr");
|
|
28
|
+
expect(render(<Localize value={date} />)).toBe("24/09/2024");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("should format number", () => {
|
|
32
|
+
const { render, i18n } = setup();
|
|
33
|
+
const number = 1234567.89;
|
|
34
|
+
expect(render(<Localize value={number} />)).toBe("1,234,567.89");
|
|
35
|
+
i18n.setLang("de");
|
|
36
|
+
expect(render(<Localize value={number} />)).toBe("1.234.567,89");
|
|
37
|
+
i18n.setLang("fr");
|
|
38
|
+
expect(render(<Localize value={number} />)).toBe("1\u202f234\u202f567,89");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// it("should format typebox error", async () => {
|
|
42
|
+
// const { render, i18n, alepha } = setup();
|
|
43
|
+
// const boom = async () => alepha.codec.decode(t.number(), "..");
|
|
44
|
+
// const error = await boom().catch((err) => err);
|
|
45
|
+
// expect(render(<Localize value={error} />)).toBe("must be number");
|
|
46
|
+
// await i18n.setLang("fr");
|
|
47
|
+
// expect(render(<Localize value={error} />)).toBe("doit être number");
|
|
48
|
+
// });
|
|
49
|
+
|
|
50
|
+
describe("number formatting options", () => {
|
|
51
|
+
it("should format currency", () => {
|
|
52
|
+
const { render } = setup();
|
|
53
|
+
const number = 1234.56;
|
|
54
|
+
expect(
|
|
55
|
+
render(
|
|
56
|
+
<Localize
|
|
57
|
+
value={number}
|
|
58
|
+
number={{ style: "currency", currency: "USD" }}
|
|
59
|
+
/>,
|
|
60
|
+
),
|
|
61
|
+
).toBe("$1,234.56");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should format currency with locale", () => {
|
|
65
|
+
const { render, i18n } = setup();
|
|
66
|
+
const number = 1234.56;
|
|
67
|
+
i18n.setLang("fr");
|
|
68
|
+
expect(
|
|
69
|
+
render(
|
|
70
|
+
<Localize
|
|
71
|
+
value={number}
|
|
72
|
+
number={{ style: "currency", currency: "EUR" }}
|
|
73
|
+
/>,
|
|
74
|
+
),
|
|
75
|
+
).toBe("1\u202f234,56\u00a0€");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should format percentage", () => {
|
|
79
|
+
const { render } = setup();
|
|
80
|
+
const number = 0.1234;
|
|
81
|
+
expect(
|
|
82
|
+
render(<Localize value={number} number={{ style: "percent" }} />),
|
|
83
|
+
).toBe("12%");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("should format with minimum fraction digits", () => {
|
|
87
|
+
const { render } = setup();
|
|
88
|
+
const number = 10;
|
|
89
|
+
expect(
|
|
90
|
+
render(
|
|
91
|
+
<Localize value={number} number={{ minimumFractionDigits: 2 }} />,
|
|
92
|
+
),
|
|
93
|
+
).toBe("10.00");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should format with maximum fraction digits", () => {
|
|
97
|
+
const { render } = setup();
|
|
98
|
+
const number = 10.123456;
|
|
99
|
+
expect(
|
|
100
|
+
render(
|
|
101
|
+
<Localize value={number} number={{ maximumFractionDigits: 2 }} />,
|
|
102
|
+
),
|
|
103
|
+
).toBe("10.12");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should format with notation", () => {
|
|
107
|
+
const { render } = setup();
|
|
108
|
+
const number = 1000000;
|
|
109
|
+
expect(
|
|
110
|
+
render(<Localize value={number} number={{ notation: "compact" }} />),
|
|
111
|
+
).toBe("1M");
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("date formatting options", () => {
|
|
116
|
+
it("should format with dayjs format string - LLL", () => {
|
|
117
|
+
const { render, i18n, dateTime } = setup();
|
|
118
|
+
const date = dateTime.utc("2024-09-24T00:45:00Z").toDate();
|
|
119
|
+
const formatted = render(<Localize value={date} date="LLL" />);
|
|
120
|
+
// Format depends on local timezone, so just check it contains the key parts
|
|
121
|
+
expect(formatted).toContain("September");
|
|
122
|
+
expect(formatted).toContain("2024");
|
|
123
|
+
i18n.setLang("fr");
|
|
124
|
+
const frFormatted = render(<Localize value={date} date="LLL" />);
|
|
125
|
+
expect(frFormatted).toContain("septembre");
|
|
126
|
+
expect(frFormatted).toContain("2024");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should format with dayjs format string - YYYY-MM-DD", () => {
|
|
130
|
+
const { render } = setup();
|
|
131
|
+
const date = new Date("2024-09-23T23:45:00Z");
|
|
132
|
+
expect(render(<Localize value={date} date="YYYY-MM-DD" />)).toBe(
|
|
133
|
+
"2024-09-24",
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should format with dayjs format string - dddd, MMMM D YYYY", () => {
|
|
138
|
+
const { render } = setup();
|
|
139
|
+
const date = new Date("2024-09-23T23:45:00Z");
|
|
140
|
+
expect(render(<Localize value={date} date="dddd, MMMM D YYYY" />)).toBe(
|
|
141
|
+
"Tuesday, September 24 2024",
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should format with fromNow for Date", () => {
|
|
146
|
+
const { render, dateTime } = setup();
|
|
147
|
+
dateTime.pause();
|
|
148
|
+
const date = dateTime.now().subtract(2, "hour").toDate();
|
|
149
|
+
const result = render(<Localize value={date} date="fromNow" />);
|
|
150
|
+
expect(result).toBe("2 hours ago");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should format with fromNow for DateTime", () => {
|
|
154
|
+
const { render, dateTime } = setup();
|
|
155
|
+
dateTime.pause();
|
|
156
|
+
const date = dateTime.now().subtract(3, "day");
|
|
157
|
+
const result = render(<Localize value={date} date="fromNow" />);
|
|
158
|
+
expect(result).toBe("3 days ago");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should format DateTime with dayjs format string", () => {
|
|
162
|
+
const { render, dateTime } = setup();
|
|
163
|
+
const date = dateTime.of("2024-09-23T23:45:00Z");
|
|
164
|
+
expect(render(<Localize value={date} date="YYYY-MM-DD" />)).toBe(
|
|
165
|
+
"2024-09-24",
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should format with Intl.DateTimeFormatOptions", () => {
|
|
170
|
+
const { render } = setup();
|
|
171
|
+
const date = new Date("2024-09-23T23:45:00Z");
|
|
172
|
+
expect(
|
|
173
|
+
render(
|
|
174
|
+
<Localize
|
|
175
|
+
value={date}
|
|
176
|
+
date={{
|
|
177
|
+
weekday: "long",
|
|
178
|
+
year: "numeric",
|
|
179
|
+
month: "long",
|
|
180
|
+
day: "numeric",
|
|
181
|
+
}}
|
|
182
|
+
/>,
|
|
183
|
+
),
|
|
184
|
+
).toBe("Tuesday, September 24, 2024");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("should format with Intl.DateTimeFormatOptions and locale", () => {
|
|
188
|
+
const { render, i18n } = setup();
|
|
189
|
+
const date = new Date("2024-09-23T23:45:00Z");
|
|
190
|
+
i18n.setLang("fr");
|
|
191
|
+
expect(
|
|
192
|
+
render(
|
|
193
|
+
<Localize
|
|
194
|
+
value={date}
|
|
195
|
+
date={{
|
|
196
|
+
weekday: "long",
|
|
197
|
+
year: "numeric",
|
|
198
|
+
month: "long",
|
|
199
|
+
day: "numeric",
|
|
200
|
+
}}
|
|
201
|
+
/>,
|
|
202
|
+
),
|
|
203
|
+
).toBe("mardi 24 septembre 2024");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("should format DateTime with Intl.DateTimeFormatOptions", () => {
|
|
207
|
+
const { render, dateTime } = setup();
|
|
208
|
+
const date = dateTime.utc("2024-09-24T00:45:00Z");
|
|
209
|
+
const formatted = render(
|
|
210
|
+
<Localize
|
|
211
|
+
value={date}
|
|
212
|
+
date={{
|
|
213
|
+
hour: "2-digit",
|
|
214
|
+
minute: "2-digit",
|
|
215
|
+
hour12: true,
|
|
216
|
+
}}
|
|
217
|
+
/>,
|
|
218
|
+
);
|
|
219
|
+
// Format depends on local timezone, so just verify it contains time parts
|
|
220
|
+
expect(formatted).toMatch(/\d{1,2}:\d{2}\s(AM|PM)/);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe("string date parsing", () => {
|
|
225
|
+
it("should parse string date when dateOptions is provided", () => {
|
|
226
|
+
const { render } = setup();
|
|
227
|
+
const dateString = "2024-09-24T12:00:00Z";
|
|
228
|
+
expect(render(<Localize value={dateString} date="YYYY-MM-DD" />)).toBe(
|
|
229
|
+
"2024-09-24",
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("should parse string date with format options", () => {
|
|
234
|
+
const { render } = setup();
|
|
235
|
+
const dateString = "2024-09-24T12:00:00Z";
|
|
236
|
+
expect(render(<Localize value={dateString} date="LLL" />)).toContain(
|
|
237
|
+
"September",
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should parse string date with timezone", () => {
|
|
242
|
+
const { render } = setup();
|
|
243
|
+
const dateString = "2024-09-24T12:00:00Z";
|
|
244
|
+
expect(
|
|
245
|
+
render(
|
|
246
|
+
<Localize
|
|
247
|
+
value={dateString}
|
|
248
|
+
timezone="America/New_York"
|
|
249
|
+
date="YYYY-MM-DD HH:mm"
|
|
250
|
+
/>,
|
|
251
|
+
),
|
|
252
|
+
).toBe("2024-09-24 08:00");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should return string as-is when no dateOptions provided", () => {
|
|
256
|
+
const { render } = setup();
|
|
257
|
+
const dateString = "2024-09-24T12:00:00Z";
|
|
258
|
+
expect(render(<Localize value={dateString} />)).toBe(dateString);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
describe("timezone formatting", () => {
|
|
263
|
+
it("should format Date with timezone using Intl", () => {
|
|
264
|
+
const { render } = setup();
|
|
265
|
+
const date = new Date("2024-09-24T12:00:00Z");
|
|
266
|
+
expect(
|
|
267
|
+
render(<Localize value={date} timezone="America/New_York" />),
|
|
268
|
+
).toBe("9/24/2024");
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("should format Date with timezone and dateOptions", () => {
|
|
272
|
+
const { render } = setup();
|
|
273
|
+
const date = new Date("2024-09-24T12:00:00Z");
|
|
274
|
+
expect(
|
|
275
|
+
render(
|
|
276
|
+
<Localize
|
|
277
|
+
value={date}
|
|
278
|
+
timezone="America/New_York"
|
|
279
|
+
date={{
|
|
280
|
+
hour: "2-digit",
|
|
281
|
+
minute: "2-digit",
|
|
282
|
+
hour12: true,
|
|
283
|
+
timeZoneName: "short",
|
|
284
|
+
}}
|
|
285
|
+
/>,
|
|
286
|
+
),
|
|
287
|
+
).toContain("EDT");
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should format Date with timezone using dayjs format", () => {
|
|
291
|
+
const { render } = setup();
|
|
292
|
+
const date = new Date("2024-09-24T12:00:00Z");
|
|
293
|
+
const formatted = render(
|
|
294
|
+
<Localize
|
|
295
|
+
value={date}
|
|
296
|
+
timezone="America/New_York"
|
|
297
|
+
date="YYYY-MM-DD HH:mm"
|
|
298
|
+
/>,
|
|
299
|
+
);
|
|
300
|
+
expect(formatted).toBe("2024-09-24 08:00");
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("should format DateTime with timezone using dayjs format", () => {
|
|
304
|
+
const { render, dateTime } = setup();
|
|
305
|
+
const date = dateTime.utc("2024-09-24T12:00:00Z");
|
|
306
|
+
const formatted = render(
|
|
307
|
+
<Localize
|
|
308
|
+
value={date}
|
|
309
|
+
timezone="Europe/Paris"
|
|
310
|
+
date="YYYY-MM-DD HH:mm"
|
|
311
|
+
/>,
|
|
312
|
+
);
|
|
313
|
+
expect(formatted).toBe("2024-09-24 14:00");
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it("should format DateTime with timezone and Intl options", () => {
|
|
317
|
+
const { render, dateTime } = setup();
|
|
318
|
+
const date = dateTime.utc("2024-09-24T12:00:00Z");
|
|
319
|
+
const formatted = render(
|
|
320
|
+
<Localize
|
|
321
|
+
value={date}
|
|
322
|
+
timezone="Asia/Tokyo"
|
|
323
|
+
date={{
|
|
324
|
+
hour: "2-digit",
|
|
325
|
+
minute: "2-digit",
|
|
326
|
+
hour12: false,
|
|
327
|
+
}}
|
|
328
|
+
/>,
|
|
329
|
+
);
|
|
330
|
+
expect(formatted).toBe("21:00");
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("should format DateTime with timezone using LLL format", () => {
|
|
334
|
+
const { render, dateTime } = setup();
|
|
335
|
+
const date = dateTime.utc("2024-09-24T12:00:00Z");
|
|
336
|
+
const formatted = render(
|
|
337
|
+
<Localize value={date} timezone="America/Los_Angeles" date="LLL" />,
|
|
338
|
+
);
|
|
339
|
+
expect(formatted).toContain("September");
|
|
340
|
+
expect(formatted).toContain("2024");
|
|
341
|
+
expect(formatted).toContain("5:00 AM");
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("should respect locale and timezone together", () => {
|
|
345
|
+
const { render, i18n, dateTime } = setup();
|
|
346
|
+
const date = dateTime.utc("2024-09-24T12:00:00Z");
|
|
347
|
+
i18n.setLang("fr");
|
|
348
|
+
const formatted = render(
|
|
349
|
+
<Localize value={date} timezone="Europe/Paris" date="LLL" />,
|
|
350
|
+
);
|
|
351
|
+
console.log(formatted);
|
|
352
|
+
expect(formatted).toContain("septembre");
|
|
353
|
+
expect(formatted).toContain("2024");
|
|
354
|
+
expect(formatted).toContain("14:00");
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
});
|