@terreno/ui 0.14.0 → 0.14.2
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/ActionSheet.d.ts +1 -1
- package/dist/ActionSheet.js +17 -29
- package/dist/ActionSheet.js.map +1 -1
- package/dist/Common.d.ts +8 -2
- package/dist/Common.js +4 -4
- package/dist/Common.js.map +1 -1
- package/dist/ConsentFormScreen.js +3 -3
- package/dist/ConsentFormScreen.js.map +1 -1
- package/dist/DateUtilities.d.ts +25 -25
- package/dist/DateUtilities.js +31 -32
- package/dist/DateUtilities.js.map +1 -1
- package/dist/MarkdownView.js +20 -7
- package/dist/MarkdownView.js.map +1 -1
- package/dist/MediaQuery.d.ts +4 -4
- package/dist/MediaQuery.js +8 -8
- package/dist/MediaQuery.js.map +1 -1
- package/dist/Page.d.ts +1 -0
- package/dist/Page.js +6 -2
- package/dist/Page.js.map +1 -1
- package/dist/PickerSelect.d.ts +1 -1
- package/dist/PickerSelect.js +2 -2
- package/dist/PickerSelect.js.map +1 -1
- package/dist/TapToEdit.d.ts +1 -1
- package/dist/TapToEdit.js +2 -3
- package/dist/TapToEdit.js.map +1 -1
- package/dist/ToastNotifications.js +2 -2
- package/dist/ToastNotifications.js.map +1 -1
- package/dist/Tooltip.d.ts +24 -1
- package/dist/Tooltip.js +2 -2
- package/dist/Tooltip.js.map +1 -1
- package/dist/Unifier.d.ts +1 -1
- package/dist/Unifier.js +14 -11
- package/dist/Unifier.js.map +1 -1
- package/dist/Utilities.d.ts +8 -8
- package/dist/Utilities.js +12 -14
- package/dist/Utilities.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/signUp/PasswordRequirements.js +3 -3
- package/dist/signUp/PasswordRequirements.js.map +1 -1
- package/dist/table/TableHeaderCell.js +1 -9
- package/dist/table/TableHeaderCell.js.map +1 -1
- package/dist/table/tableContext.d.ts +1 -1
- package/dist/table/tableContext.js +2 -2
- package/dist/table/tableContext.js.map +1 -1
- package/dist/useConsentHistory.d.ts +6 -1
- package/dist/useConsentHistory.js +2 -1
- package/dist/useConsentHistory.js.map +1 -1
- package/package.json +1 -1
- package/src/ActionSheet.test.tsx +554 -0
- package/src/ActionSheet.tsx +26 -39
- package/src/Banner.test.tsx +107 -1
- package/src/Common.ts +10 -4
- package/src/ConsentFormScreen.test.tsx +22 -0
- package/src/ConsentFormScreen.tsx +9 -3
- package/src/DataTable.test.tsx +393 -1
- package/src/DateTimeField.test.tsx +716 -2
- package/src/DateUtilities.tsx +37 -38
- package/src/HeightActionSheet.test.tsx +17 -1
- package/src/HeightField.test.tsx +141 -1
- package/src/HeightFieldDesktop.test.tsx +19 -0
- package/src/MarkdownView.test.tsx +28 -0
- package/src/MarkdownView.tsx +69 -7
- package/src/MediaQuery.ts +8 -8
- package/src/MobileAddressAutoComplete.test.tsx +26 -3
- package/src/Page.test.tsx +28 -0
- package/src/Page.tsx +17 -2
- package/src/PickerSelect.test.tsx +243 -0
- package/src/PickerSelect.tsx +3 -3
- package/src/SplitPage.test.tsx +299 -43
- package/src/TapToEdit.test.tsx +44 -0
- package/src/TapToEdit.tsx +2 -3
- package/src/ToastNotifications.test.tsx +1412 -0
- package/src/ToastNotifications.tsx +2 -2
- package/src/Tooltip.test.tsx +1294 -3
- package/src/Tooltip.tsx +2 -2
- package/src/Unifier.ts +14 -11
- package/src/Utilities.tsx +14 -16
- package/src/WebAddressAutocomplete.test.tsx +237 -0
- package/src/WebDropdownMenu.test.tsx +51 -2
- package/src/__snapshots__/Banner.test.tsx.snap +125 -0
- package/src/__snapshots__/DataTable.test.tsx.snap +366 -0
- package/src/__snapshots__/MarkdownView.test.tsx.snap +284 -74
- package/src/__snapshots__/SplitPage.test.tsx.snap +698 -46
- package/src/bunSetup.ts +0 -4
- package/src/index.tsx +1 -1
- package/src/login/LoginScreen.test.tsx +35 -1
- package/src/signUp/PasswordRequirements.tsx +9 -6
- package/src/signUp/__snapshots__/PasswordRequirements.test.tsx.snap +50 -2
- package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +25 -1
- package/src/table/TableHeaderCell.tsx +8 -11
- package/src/table/TableRow.test.tsx +31 -1
- package/src/table/__snapshots__/TableHeaderCell.test.tsx.snap +2 -0
- package/src/table/tableContext.tsx +2 -2
- package/src/useConsentHistory.test.ts +20 -13
- package/src/useConsentHistory.ts +7 -2
- package/src/useStoredState.test.tsx +47 -0
package/src/Tooltip.tsx
CHANGED
|
@@ -39,7 +39,7 @@ interface ChildrenProps {
|
|
|
39
39
|
onHoverOut?: () => void;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const getTooltipPosition = ({
|
|
42
|
+
export const getTooltipPosition = ({
|
|
43
43
|
children,
|
|
44
44
|
tooltip,
|
|
45
45
|
measured,
|
|
@@ -117,7 +117,7 @@ const getTooltipPosition = ({
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
-
const Arrow: FC<{position: TooltipPosition; color: string}> = ({position, color}) => {
|
|
120
|
+
export const Arrow: FC<{position: TooltipPosition; color: string}> = ({position, color}) => {
|
|
121
121
|
const getArrowStyle = (): ViewStyle => {
|
|
122
122
|
const arrowStyles = {
|
|
123
123
|
bottom: {
|
package/src/Unifier.ts
CHANGED
|
@@ -18,13 +18,18 @@ export type PlatformOS = "ios" | "android" | "web";
|
|
|
18
18
|
type Luminance = "light" | "lighter" | "dark" | "darker";
|
|
19
19
|
|
|
20
20
|
// Changes a color luminance
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
export const changeColorLuminance = (hex: string, luminanceChange: Luminance) => {
|
|
22
|
+
let normalizedHex = String(hex).replace(/[^0-9a-f]/gi, "");
|
|
23
|
+
if (normalizedHex.length === 3) {
|
|
24
|
+
normalizedHex =
|
|
25
|
+
normalizedHex[0] +
|
|
26
|
+
normalizedHex[0] +
|
|
27
|
+
normalizedHex[1] +
|
|
28
|
+
normalizedHex[1] +
|
|
29
|
+
normalizedHex[2] +
|
|
30
|
+
normalizedHex[2];
|
|
31
|
+
} else if (normalizedHex.length !== 6) {
|
|
32
|
+
throw new Error(`Invalid color hex: ${normalizedHex}`);
|
|
28
33
|
}
|
|
29
34
|
let luminance: number;
|
|
30
35
|
switch (luminanceChange) {
|
|
@@ -44,19 +49,17 @@ export function changeColorLuminance(hex: string, luminanceChange: Luminance) {
|
|
|
44
49
|
throw new Error(`Cannot change luminance to ${luminanceChange}`);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
// Convert to decimal and change luminosity
|
|
48
52
|
let rgb = "#";
|
|
49
53
|
for (let i = 0; i < 3; i++) {
|
|
50
|
-
const decimal = parseInt(
|
|
54
|
+
const decimal = parseInt(normalizedHex.substr(i * 2, 2), 16);
|
|
51
55
|
const appliedLuminance = Math.round(
|
|
52
56
|
Math.min(Math.max(0, decimal + decimal * luminance), 255)
|
|
53
57
|
).toString(16);
|
|
54
|
-
// 0 pad, if necessary.
|
|
55
58
|
rgb += `00${appliedLuminance}`.substr(appliedLuminance.length);
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
return rgb;
|
|
59
|
-
}
|
|
62
|
+
};
|
|
60
63
|
|
|
61
64
|
class UnifierClass {
|
|
62
65
|
private _web = false;
|
package/src/Utilities.tsx
CHANGED
|
@@ -6,10 +6,10 @@ import {Platform} from "react-native";
|
|
|
6
6
|
import type {APIError, BaseProfile, IconSize} from "./Common";
|
|
7
7
|
import {COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES} from "./Constants";
|
|
8
8
|
|
|
9
|
-
export
|
|
9
|
+
export const mergeInlineStyles = (
|
|
10
10
|
inlineStyle?: {__style?: Record<string, unknown>} | undefined,
|
|
11
11
|
newStyle?: Record<string, unknown> | undefined
|
|
12
|
-
) {
|
|
12
|
+
) => {
|
|
13
13
|
const inline = get(inlineStyle, "__style");
|
|
14
14
|
return {
|
|
15
15
|
__style: {
|
|
@@ -17,14 +17,14 @@ export function mergeInlineStyles(
|
|
|
17
17
|
...newStyle,
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
|
-
}
|
|
20
|
+
};
|
|
21
21
|
|
|
22
|
-
export
|
|
22
|
+
export const isTestUser = (profile?: BaseProfile) => {
|
|
23
23
|
return (
|
|
24
24
|
profile?.email &&
|
|
25
25
|
(profile.email.indexOf("nang.io") > -1 || profile.email.indexOf("example.com") > -1)
|
|
26
26
|
);
|
|
27
|
-
}
|
|
27
|
+
};
|
|
28
28
|
|
|
29
29
|
export const iconNumberToSize = (size = 16): IconSize => {
|
|
30
30
|
let iconSize: IconSize;
|
|
@@ -170,17 +170,17 @@ export const rangeWithoutZero =
|
|
|
170
170
|
// Binds a string classname to the value in an object. Useful when interacting
|
|
171
171
|
// with ranges that need to come dynamically from a style object. This is
|
|
172
172
|
// similar to the NPM package 'classnames/bind'.
|
|
173
|
-
export
|
|
173
|
+
export const bind = <T,>(
|
|
174
174
|
fn: Functor<T>,
|
|
175
175
|
scope:
|
|
176
176
|
| {
|
|
177
177
|
readonly [key: string]: string;
|
|
178
178
|
}
|
|
179
179
|
| Record<string, string>
|
|
180
|
-
): (val: T) => Style {
|
|
180
|
+
): ((val: T) => Style) => {
|
|
181
181
|
const map = mapClassName((name) => scope[name]);
|
|
182
182
|
return (val: T): Style => map(fn(val));
|
|
183
|
-
}
|
|
183
|
+
};
|
|
184
184
|
|
|
185
185
|
// This takes a series of the previously defined functors, runs them all
|
|
186
186
|
// against a value and returns the set of their classnames.
|
|
@@ -294,15 +294,13 @@ export const isValidGoogleApiKey = (apiKey: string): boolean => {
|
|
|
294
294
|
return true;
|
|
295
295
|
};
|
|
296
296
|
|
|
297
|
-
export
|
|
298
|
-
// Remove whitespace and convert to lowercase for comparison
|
|
297
|
+
export const formattedCountyCode = (state: string, countyName: string): string => {
|
|
299
298
|
const stateKey = state
|
|
300
299
|
.replace(/\s+/g, "")
|
|
301
300
|
.toLowerCase() as keyof typeof COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES;
|
|
302
301
|
|
|
303
302
|
const stateData = COUNTY_AND_COUNTY_EQUIVALENT_ENTITIES[stateKey];
|
|
304
303
|
|
|
305
|
-
// Remove whitespace, periods, apostrophes, and dashes for comparison
|
|
306
304
|
const countyKey = countyName
|
|
307
305
|
.trim()
|
|
308
306
|
.toLowerCase()
|
|
@@ -317,16 +315,16 @@ export function formattedCountyCode(state: string, countyName: string): string {
|
|
|
317
315
|
}
|
|
318
316
|
|
|
319
317
|
return `${countyData.stateFP}${countyData.countyFP}`;
|
|
320
|
-
}
|
|
318
|
+
};
|
|
321
319
|
|
|
322
|
-
export
|
|
320
|
+
export const isAPIError = (error: unknown): error is APIError => {
|
|
323
321
|
return Boolean((error as {data?: {title?: unknown}} | null | undefined)?.data?.title);
|
|
324
|
-
}
|
|
322
|
+
};
|
|
325
323
|
|
|
326
|
-
export
|
|
324
|
+
export const printAPIError = (error: APIError, details = true): string => {
|
|
327
325
|
let message = error.data?.title;
|
|
328
326
|
if (error.data?.detail && details) {
|
|
329
327
|
message = `${message}: ${error.data?.detail}`;
|
|
330
328
|
}
|
|
331
329
|
return message;
|
|
332
|
-
}
|
|
330
|
+
};
|
|
@@ -313,5 +313,242 @@ describe("WebAddressAutocomplete", () => {
|
|
|
313
313
|
// The .catch path warns and falls back to plain TextField.
|
|
314
314
|
expect(warnings.length).toBeGreaterThan(0);
|
|
315
315
|
});
|
|
316
|
+
|
|
317
|
+
it("cleans up the global callback on unmount", async () => {
|
|
318
|
+
const {unmount} = renderWithTheme(
|
|
319
|
+
<WebAddressAutocomplete
|
|
320
|
+
googleMapsApiKey="my-api-key"
|
|
321
|
+
handleAddressChange={() => {}}
|
|
322
|
+
handleAutoCompleteChange={() => {}}
|
|
323
|
+
inputValue=""
|
|
324
|
+
/>
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const win = testGlobal.window as GoogleMapsWindow;
|
|
328
|
+
expect(win.initAutocomplete).toBeDefined();
|
|
329
|
+
|
|
330
|
+
unmount();
|
|
331
|
+
|
|
332
|
+
expect(win.initAutocomplete).toBeNull();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it("re-runs effect when googleMapsApiKey changes", async () => {
|
|
336
|
+
const handleAutoCompleteChange = mock((_arg: AddressInterface) => {});
|
|
337
|
+
|
|
338
|
+
renderWithTheme(
|
|
339
|
+
<WebAddressAutocomplete
|
|
340
|
+
googleMapsApiKey="key-1"
|
|
341
|
+
handleAddressChange={() => {}}
|
|
342
|
+
handleAutoCompleteChange={handleAutoCompleteChange}
|
|
343
|
+
inputValue=""
|
|
344
|
+
/>
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
expect(appendedScripts.length).toBe(1);
|
|
348
|
+
|
|
349
|
+
// Simulate successful load for the second key
|
|
350
|
+
const win = testGlobal.window as GoogleMapsWindow;
|
|
351
|
+
const autocompleteConstructor = mock((_input: unknown, _opts: unknown) => ({
|
|
352
|
+
addListener: () => {},
|
|
353
|
+
getPlace: () => null,
|
|
354
|
+
}));
|
|
355
|
+
win.google = {
|
|
356
|
+
maps: {
|
|
357
|
+
places: {
|
|
358
|
+
Autocomplete: autocompleteConstructor,
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
await act(async () => {
|
|
364
|
+
(win.initAutocomplete as () => void)?.();
|
|
365
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
expect(autocompleteConstructor).toHaveBeenCalled();
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("processes address components with includeCounty", async () => {
|
|
372
|
+
const handleAutoCompleteChange = mock((_arg: AddressInterface) => {});
|
|
373
|
+
let placeChangedCb: (() => void) | undefined;
|
|
374
|
+
let localPlaceResult: PlaceResult | null = null;
|
|
375
|
+
|
|
376
|
+
const autocompleteConstructor = mock((_input: unknown, _opts: unknown) => ({
|
|
377
|
+
addListener: (event: string, cb: () => void) => {
|
|
378
|
+
if (event === "place_changed") {
|
|
379
|
+
placeChangedCb = cb;
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
getPlace: () => localPlaceResult,
|
|
383
|
+
}));
|
|
384
|
+
|
|
385
|
+
testGlobal.window = {
|
|
386
|
+
google: {
|
|
387
|
+
maps: {
|
|
388
|
+
places: {
|
|
389
|
+
Autocomplete: autocompleteConstructor,
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
renderWithTheme(
|
|
396
|
+
<WebAddressAutocomplete
|
|
397
|
+
googleMapsApiKey="test-key"
|
|
398
|
+
handleAddressChange={() => {}}
|
|
399
|
+
handleAutoCompleteChange={handleAutoCompleteChange}
|
|
400
|
+
includeCounty
|
|
401
|
+
inputValue=""
|
|
402
|
+
/>
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
await act(async () => {
|
|
406
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
localPlaceResult = {
|
|
410
|
+
address_components: [
|
|
411
|
+
{long_name: "10", short_name: "10", types: ["street_number"]},
|
|
412
|
+
{long_name: "Main St", short_name: "Main St", types: ["route"]},
|
|
413
|
+
{long_name: "Springfield", short_name: "Springfield", types: ["locality"]},
|
|
414
|
+
{
|
|
415
|
+
long_name: "Sangamon County",
|
|
416
|
+
short_name: "Sangamon County",
|
|
417
|
+
types: ["administrative_area_level_2"],
|
|
418
|
+
},
|
|
419
|
+
{long_name: "Illinois", short_name: "IL", types: ["administrative_area_level_1"]},
|
|
420
|
+
{long_name: "62701", short_name: "62701", types: ["postal_code"]},
|
|
421
|
+
],
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
await act(async () => {
|
|
425
|
+
placeChangedCb?.();
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
expect(handleAutoCompleteChange).toHaveBeenCalled();
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
describe("no API key behavior", () => {
|
|
433
|
+
it("sets scriptLoaded to false and renders plain TextField", async () => {
|
|
434
|
+
const handleAddressChange = mock(() => {});
|
|
435
|
+
const {UNSAFE_getAllByType} = renderWithTheme(
|
|
436
|
+
<WebAddressAutocomplete
|
|
437
|
+
handleAddressChange={handleAddressChange}
|
|
438
|
+
handleAutoCompleteChange={() => {}}
|
|
439
|
+
inputValue="test"
|
|
440
|
+
/>
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
await act(async () => {
|
|
444
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
const {TextInput} = require("react-native");
|
|
448
|
+
const inputs = UNSAFE_getAllByType(TextInput);
|
|
449
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
450
|
+
const {fireEvent: fe} = require("@testing-library/react-native");
|
|
451
|
+
fe.changeText(inputs[0], "new value");
|
|
452
|
+
expect(handleAddressChange).toHaveBeenCalledWith("new value");
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it("cleans up the global callback on unmount", async () => {
|
|
456
|
+
const handleAutoCompleteChange = mock((_arg: AddressInterface) => {});
|
|
457
|
+
|
|
458
|
+
const {unmount} = renderWithTheme(
|
|
459
|
+
<WebAddressAutocomplete
|
|
460
|
+
googleMapsApiKey="cleanup-key"
|
|
461
|
+
handleAddressChange={() => {}}
|
|
462
|
+
handleAutoCompleteChange={handleAutoCompleteChange}
|
|
463
|
+
inputValue=""
|
|
464
|
+
/>
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
await act(async () => {
|
|
468
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
const win = (globalThis as Record<string, Record<string, unknown>>).window;
|
|
472
|
+
expect(win.initAutocomplete).toBeDefined();
|
|
473
|
+
|
|
474
|
+
unmount();
|
|
475
|
+
|
|
476
|
+
expect(win.initAutocomplete).toBeNull();
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("handles place_changed with includeCounty flag", async () => {
|
|
480
|
+
const handleAutoCompleteChange = mock((_arg: AddressInterface) => {});
|
|
481
|
+
|
|
482
|
+
let placeChangedCb: (() => void) | undefined;
|
|
483
|
+
const autocompleteConstructor = mock((_input: unknown, _opts: unknown) => ({
|
|
484
|
+
addListener: (event: string, cb: () => void) => {
|
|
485
|
+
if (event === "place_changed") {
|
|
486
|
+
placeChangedCb = cb;
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
getPlace: () => ({
|
|
490
|
+
address_components: [
|
|
491
|
+
{long_name: "10", short_name: "10", types: ["street_number"]},
|
|
492
|
+
{long_name: "Oak St", short_name: "Oak St", types: ["route"]},
|
|
493
|
+
{long_name: "Portland", short_name: "Portland", types: ["locality"]},
|
|
494
|
+
{long_name: "Oregon", short_name: "OR", types: ["administrative_area_level_1"]},
|
|
495
|
+
{long_name: "97201", short_name: "97201", types: ["postal_code"]},
|
|
496
|
+
{
|
|
497
|
+
long_name: "Multnomah County",
|
|
498
|
+
short_name: "Multnomah",
|
|
499
|
+
types: ["administrative_area_level_2"],
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
}),
|
|
503
|
+
}));
|
|
504
|
+
|
|
505
|
+
const win = (globalThis as Record<string, Record<string, unknown>>).window;
|
|
506
|
+
win.google = {
|
|
507
|
+
maps: {places: {Autocomplete: autocompleteConstructor}},
|
|
508
|
+
};
|
|
509
|
+
|
|
510
|
+
renderWithTheme(
|
|
511
|
+
<WebAddressAutocomplete
|
|
512
|
+
googleMapsApiKey="county-key"
|
|
513
|
+
handleAddressChange={() => {}}
|
|
514
|
+
handleAutoCompleteChange={handleAutoCompleteChange}
|
|
515
|
+
includeCounty
|
|
516
|
+
inputValue=""
|
|
517
|
+
/>
|
|
518
|
+
);
|
|
519
|
+
|
|
520
|
+
await act(async () => {
|
|
521
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
expect(autocompleteConstructor).toHaveBeenCalled();
|
|
525
|
+
expect(placeChangedCb).toBeDefined();
|
|
526
|
+
|
|
527
|
+
placeChangedCb?.();
|
|
528
|
+
expect(handleAutoCompleteChange).toHaveBeenCalled();
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
describe("without googleMapsApiKey", () => {
|
|
533
|
+
it("sets scriptLoaded to false and renders plain TextField", async () => {
|
|
534
|
+
const handleAddressChange = mock(() => {});
|
|
535
|
+
const {UNSAFE_getAllByType} = renderWithTheme(
|
|
536
|
+
<WebAddressAutocomplete
|
|
537
|
+
handleAddressChange={handleAddressChange}
|
|
538
|
+
handleAutoCompleteChange={() => {}}
|
|
539
|
+
inputValue="test value"
|
|
540
|
+
/>
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
await act(async () => {
|
|
544
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const {TextInput} = require("react-native");
|
|
548
|
+
const inputs = UNSAFE_getAllByType(TextInput);
|
|
549
|
+
expect(inputs.length).toBeGreaterThan(0);
|
|
550
|
+
fireEvent.changeText(inputs[0], "new value");
|
|
551
|
+
expect(handleAddressChange).toHaveBeenCalledWith("new value");
|
|
552
|
+
});
|
|
316
553
|
});
|
|
317
554
|
});
|
|
@@ -141,6 +141,29 @@ describe("WebDropdownMenu", () => {
|
|
|
141
141
|
expect(getByText("Placeholder").props.style.fontWeight).toBe("400");
|
|
142
142
|
expect(getByText("Real").props.style.fontWeight).toBe("400");
|
|
143
143
|
});
|
|
144
|
+
|
|
145
|
+
it("applies dynamic background via the Pressable style callback", () => {
|
|
146
|
+
const {getByTestId} = renderWithTheme(
|
|
147
|
+
<WebDropdownMenu
|
|
148
|
+
anchor={anchor}
|
|
149
|
+
onClose={() => {}}
|
|
150
|
+
onSelect={() => {}}
|
|
151
|
+
options={options}
|
|
152
|
+
selectedValue="b"
|
|
153
|
+
visible
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
const optionPressable = getByTestId("web_dropdown_option_a");
|
|
157
|
+
const styleFn = optionPressable.props.style;
|
|
158
|
+
expect(typeof styleFn).toBe("function");
|
|
159
|
+
const defaultStyle = styleFn({hovered: false, pressed: false});
|
|
160
|
+
const hoveredStyle = styleFn({hovered: true, pressed: false});
|
|
161
|
+
const pressedStyle = styleFn({hovered: false, pressed: true});
|
|
162
|
+
expect(defaultStyle.paddingHorizontal).toBe(12);
|
|
163
|
+
expect(defaultStyle.paddingVertical).toBe(10);
|
|
164
|
+
expect(hoveredStyle.backgroundColor).toBeDefined();
|
|
165
|
+
expect(pressedStyle.backgroundColor).toBeDefined();
|
|
166
|
+
});
|
|
144
167
|
});
|
|
145
168
|
|
|
146
169
|
describe("useWebDropdownAnchor", () => {
|
|
@@ -162,8 +185,6 @@ describe("useWebDropdownAnchor", () => {
|
|
|
162
185
|
|
|
163
186
|
it("measures the trigger and updates anchor state when the ref has measureInWindow", () => {
|
|
164
187
|
const {result} = renderHook(() => useWebDropdownAnchor());
|
|
165
|
-
// Simulate a mounted native View by assigning a measureInWindow shim to the
|
|
166
|
-
// ref. The hook does not care whether the node is a real View instance.
|
|
167
188
|
const measureInWindow = mock((cb: (x: number, y: number, w: number, h: number) => void) => {
|
|
168
189
|
cb(10, 20, 100, 40);
|
|
169
190
|
});
|
|
@@ -177,4 +198,32 @@ describe("useWebDropdownAnchor", () => {
|
|
|
177
198
|
expect(onMeasured.mock.calls[0][0]).toEqual({height: 40, width: 100, x: 10, y: 20});
|
|
178
199
|
expect(result.current.anchor).toEqual({height: 40, width: 100, x: 10, y: 20});
|
|
179
200
|
});
|
|
201
|
+
|
|
202
|
+
it("exercises the Pressable style callback for hover/pressed states", () => {
|
|
203
|
+
const {root} = renderWithTheme(
|
|
204
|
+
<WebDropdownMenu
|
|
205
|
+
anchor={{height: 40, width: 100, x: 0, y: 50}}
|
|
206
|
+
onClose={() => {}}
|
|
207
|
+
onSelect={() => {}}
|
|
208
|
+
options={[
|
|
209
|
+
{label: "A", value: "a"},
|
|
210
|
+
{label: "B", value: "b"},
|
|
211
|
+
]}
|
|
212
|
+
visible
|
|
213
|
+
/>
|
|
214
|
+
);
|
|
215
|
+
// Find a Pressable with the style callback
|
|
216
|
+
const pressables = root.findAll(
|
|
217
|
+
(n) => typeof n.props.style === "function" && n.props["aria-role"] === "button"
|
|
218
|
+
);
|
|
219
|
+
expect(pressables.length).toBeGreaterThan(0);
|
|
220
|
+
// Call the style function with different states to exercise all branches
|
|
221
|
+
const styleFn = pressables[0].props.style;
|
|
222
|
+
const normalStyle = styleFn({hovered: false, pressed: false});
|
|
223
|
+
expect(normalStyle).toHaveProperty("paddingHorizontal");
|
|
224
|
+
const hoveredStyle = styleFn({hovered: true, pressed: false});
|
|
225
|
+
expect(hoveredStyle).toHaveProperty("paddingHorizontal");
|
|
226
|
+
const pressedStyle = styleFn({hovered: false, pressed: true});
|
|
227
|
+
expect(pressedStyle).toHaveProperty("paddingHorizontal");
|
|
228
|
+
});
|
|
180
229
|
});
|
|
@@ -544,3 +544,128 @@ exports[`Banner renders with button and icon 1`] = `
|
|
|
544
544
|
"type": "View",
|
|
545
545
|
}
|
|
546
546
|
`;
|
|
547
|
+
|
|
548
|
+
exports[`Banner renders with button loading state 1`] = `
|
|
549
|
+
{
|
|
550
|
+
"$$typeof": Symbol(react.test.json),
|
|
551
|
+
"children": [
|
|
552
|
+
{
|
|
553
|
+
"$$typeof": Symbol(react.test.json),
|
|
554
|
+
"children": [
|
|
555
|
+
{
|
|
556
|
+
"$$typeof": Symbol(react.test.json),
|
|
557
|
+
"children": [
|
|
558
|
+
"Banner loading",
|
|
559
|
+
],
|
|
560
|
+
"props": {
|
|
561
|
+
"style": {
|
|
562
|
+
"color": "#FFFFFF",
|
|
563
|
+
"flexShrink": 1,
|
|
564
|
+
"flexWrap": "wrap",
|
|
565
|
+
"fontWeight": "bold",
|
|
566
|
+
"textAlign": "center",
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
"type": "Text",
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
"$$typeof": Symbol(react.test.json),
|
|
573
|
+
"children": [
|
|
574
|
+
{
|
|
575
|
+
"$$typeof": Symbol(react.test.json),
|
|
576
|
+
"children": [
|
|
577
|
+
{
|
|
578
|
+
"$$typeof": Symbol(react.test.json),
|
|
579
|
+
"children": [
|
|
580
|
+
{
|
|
581
|
+
"$$typeof": Symbol(react.test.json),
|
|
582
|
+
"children": [
|
|
583
|
+
{
|
|
584
|
+
"$$typeof": Symbol(react.test.json),
|
|
585
|
+
"children": [
|
|
586
|
+
"Loading",
|
|
587
|
+
],
|
|
588
|
+
"props": {
|
|
589
|
+
"style": {
|
|
590
|
+
"fontSize": 12,
|
|
591
|
+
},
|
|
592
|
+
},
|
|
593
|
+
"type": "Text",
|
|
594
|
+
},
|
|
595
|
+
],
|
|
596
|
+
"props": {
|
|
597
|
+
"style": {
|
|
598
|
+
"flexDirection": "row-reverse",
|
|
599
|
+
},
|
|
600
|
+
"testID": undefined,
|
|
601
|
+
},
|
|
602
|
+
"type": "View",
|
|
603
|
+
},
|
|
604
|
+
],
|
|
605
|
+
"props": {
|
|
606
|
+
"style": {
|
|
607
|
+
"flexDirection": "row",
|
|
608
|
+
},
|
|
609
|
+
"testID": undefined,
|
|
610
|
+
},
|
|
611
|
+
"type": "View",
|
|
612
|
+
},
|
|
613
|
+
],
|
|
614
|
+
"props": {
|
|
615
|
+
"accessibilityHint": "Press to perform action Loading",
|
|
616
|
+
"aria-label": "Loading",
|
|
617
|
+
"aria-role": "button",
|
|
618
|
+
"onPress": [Function: debounced],
|
|
619
|
+
"style": {
|
|
620
|
+
"alignItems": "center",
|
|
621
|
+
"alignSelf": "stretch",
|
|
622
|
+
"backgroundColor": "#FFFFFF",
|
|
623
|
+
"borderRadius": 360,
|
|
624
|
+
"flexDirection": "column",
|
|
625
|
+
"justifyContent": "center",
|
|
626
|
+
"paddingHorizontal": 12,
|
|
627
|
+
"paddingVertical": 4,
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
"type": "Pressable",
|
|
631
|
+
},
|
|
632
|
+
],
|
|
633
|
+
"props": {
|
|
634
|
+
"style": {
|
|
635
|
+
"paddingLeft": 16,
|
|
636
|
+
"paddingRight": 10,
|
|
637
|
+
},
|
|
638
|
+
"testID": undefined,
|
|
639
|
+
},
|
|
640
|
+
"type": "View",
|
|
641
|
+
},
|
|
642
|
+
],
|
|
643
|
+
"props": {
|
|
644
|
+
"style": {
|
|
645
|
+
"alignItems": "center",
|
|
646
|
+
"flex": 1,
|
|
647
|
+
"flexDirection": "row",
|
|
648
|
+
"justifyContent": "center",
|
|
649
|
+
},
|
|
650
|
+
"testID": undefined,
|
|
651
|
+
},
|
|
652
|
+
"type": "View",
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
"props": {
|
|
656
|
+
"style": {
|
|
657
|
+
"alignItems": "center",
|
|
658
|
+
"backgroundColor": "#2B6072",
|
|
659
|
+
"borderRadius": 4,
|
|
660
|
+
"flexDirection": "row",
|
|
661
|
+
"height": "auto",
|
|
662
|
+
"margin": "auto",
|
|
663
|
+
"minHeight": 32,
|
|
664
|
+
"padding": 4,
|
|
665
|
+
"width": "100%",
|
|
666
|
+
},
|
|
667
|
+
"testID": undefined,
|
|
668
|
+
},
|
|
669
|
+
"type": "View",
|
|
670
|
+
}
|
|
671
|
+
`;
|