@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.
Files changed (98) hide show
  1. package/dist/ActionSheet.d.ts +1 -1
  2. package/dist/ActionSheet.js +17 -29
  3. package/dist/ActionSheet.js.map +1 -1
  4. package/dist/Common.d.ts +8 -2
  5. package/dist/Common.js +4 -4
  6. package/dist/Common.js.map +1 -1
  7. package/dist/ConsentFormScreen.js +3 -3
  8. package/dist/ConsentFormScreen.js.map +1 -1
  9. package/dist/DateUtilities.d.ts +25 -25
  10. package/dist/DateUtilities.js +31 -32
  11. package/dist/DateUtilities.js.map +1 -1
  12. package/dist/MarkdownView.js +20 -7
  13. package/dist/MarkdownView.js.map +1 -1
  14. package/dist/MediaQuery.d.ts +4 -4
  15. package/dist/MediaQuery.js +8 -8
  16. package/dist/MediaQuery.js.map +1 -1
  17. package/dist/Page.d.ts +1 -0
  18. package/dist/Page.js +6 -2
  19. package/dist/Page.js.map +1 -1
  20. package/dist/PickerSelect.d.ts +1 -1
  21. package/dist/PickerSelect.js +2 -2
  22. package/dist/PickerSelect.js.map +1 -1
  23. package/dist/TapToEdit.d.ts +1 -1
  24. package/dist/TapToEdit.js +2 -3
  25. package/dist/TapToEdit.js.map +1 -1
  26. package/dist/ToastNotifications.js +2 -2
  27. package/dist/ToastNotifications.js.map +1 -1
  28. package/dist/Tooltip.d.ts +24 -1
  29. package/dist/Tooltip.js +2 -2
  30. package/dist/Tooltip.js.map +1 -1
  31. package/dist/Unifier.d.ts +1 -1
  32. package/dist/Unifier.js +14 -11
  33. package/dist/Unifier.js.map +1 -1
  34. package/dist/Utilities.d.ts +8 -8
  35. package/dist/Utilities.js +12 -14
  36. package/dist/Utilities.js.map +1 -1
  37. package/dist/index.d.ts +1 -1
  38. package/dist/index.js +1 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/signUp/PasswordRequirements.js +3 -3
  41. package/dist/signUp/PasswordRequirements.js.map +1 -1
  42. package/dist/table/TableHeaderCell.js +1 -9
  43. package/dist/table/TableHeaderCell.js.map +1 -1
  44. package/dist/table/tableContext.d.ts +1 -1
  45. package/dist/table/tableContext.js +2 -2
  46. package/dist/table/tableContext.js.map +1 -1
  47. package/dist/useConsentHistory.d.ts +6 -1
  48. package/dist/useConsentHistory.js +2 -1
  49. package/dist/useConsentHistory.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/ActionSheet.test.tsx +554 -0
  52. package/src/ActionSheet.tsx +26 -39
  53. package/src/Banner.test.tsx +107 -1
  54. package/src/Common.ts +10 -4
  55. package/src/ConsentFormScreen.test.tsx +22 -0
  56. package/src/ConsentFormScreen.tsx +9 -3
  57. package/src/DataTable.test.tsx +393 -1
  58. package/src/DateTimeField.test.tsx +716 -2
  59. package/src/DateUtilities.tsx +37 -38
  60. package/src/HeightActionSheet.test.tsx +17 -1
  61. package/src/HeightField.test.tsx +141 -1
  62. package/src/HeightFieldDesktop.test.tsx +19 -0
  63. package/src/MarkdownView.test.tsx +28 -0
  64. package/src/MarkdownView.tsx +69 -7
  65. package/src/MediaQuery.ts +8 -8
  66. package/src/MobileAddressAutoComplete.test.tsx +26 -3
  67. package/src/Page.test.tsx +28 -0
  68. package/src/Page.tsx +17 -2
  69. package/src/PickerSelect.test.tsx +243 -0
  70. package/src/PickerSelect.tsx +3 -3
  71. package/src/SplitPage.test.tsx +299 -43
  72. package/src/TapToEdit.test.tsx +44 -0
  73. package/src/TapToEdit.tsx +2 -3
  74. package/src/ToastNotifications.test.tsx +1412 -0
  75. package/src/ToastNotifications.tsx +2 -2
  76. package/src/Tooltip.test.tsx +1294 -3
  77. package/src/Tooltip.tsx +2 -2
  78. package/src/Unifier.ts +14 -11
  79. package/src/Utilities.tsx +14 -16
  80. package/src/WebAddressAutocomplete.test.tsx +237 -0
  81. package/src/WebDropdownMenu.test.tsx +51 -2
  82. package/src/__snapshots__/Banner.test.tsx.snap +125 -0
  83. package/src/__snapshots__/DataTable.test.tsx.snap +366 -0
  84. package/src/__snapshots__/MarkdownView.test.tsx.snap +284 -74
  85. package/src/__snapshots__/SplitPage.test.tsx.snap +698 -46
  86. package/src/bunSetup.ts +0 -4
  87. package/src/index.tsx +1 -1
  88. package/src/login/LoginScreen.test.tsx +35 -1
  89. package/src/signUp/PasswordRequirements.tsx +9 -6
  90. package/src/signUp/__snapshots__/PasswordRequirements.test.tsx.snap +50 -2
  91. package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +25 -1
  92. package/src/table/TableHeaderCell.tsx +8 -11
  93. package/src/table/TableRow.test.tsx +31 -1
  94. package/src/table/__snapshots__/TableHeaderCell.test.tsx.snap +2 -0
  95. package/src/table/tableContext.tsx +2 -2
  96. package/src/useConsentHistory.test.ts +20 -13
  97. package/src/useConsentHistory.ts +7 -2
  98. package/src/useStoredState.test.tsx +47 -0
@@ -1,16 +1,11 @@
1
- import {afterAll, beforeAll, describe, expect, it, mock} from "bun:test";
1
+ // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
2
+ import {afterAll, afterEach, beforeEach, describe, expect, it, mock} from "bun:test";
2
3
  import {act} from "@testing-library/react-native";
3
- import type {ScaledSize} from "react-native";
4
- import {Dimensions, View} from "react-native";
4
+ import {View} from "react-native";
5
5
 
6
6
  import {SplitPage} from "./SplitPage";
7
7
  import {renderWithTheme} from "./test-utils";
8
8
 
9
- type DimensionsGetImpl = (dim: "window" | "screen") => ScaledSize;
10
- type MockableDimensionsGet = DimensionsGetImpl & {
11
- mockImplementation?: (impl: DimensionsGetImpl) => void;
12
- };
13
-
14
9
  // Mock react-native-swiper-flatlist
15
10
  mock.module("react-native-swiper-flatlist", () => ({
16
11
  SwiperFlatList: ({children}: {children: React.ReactNode}) => (
@@ -18,6 +13,37 @@ mock.module("react-native-swiper-flatlist", () => ({
18
13
  ),
19
14
  }));
20
15
 
16
+ const setDesktop = () => {
17
+ mock.module("./MediaQuery", () => ({
18
+ isMobileDevice: () => false,
19
+ mediaQuery: () => "lg" as const,
20
+ mediaQueryLargerThan: () => true,
21
+ mediaQuerySmallerThan: () => false,
22
+ }));
23
+ };
24
+
25
+ const setMobile = () => {
26
+ mock.module("./MediaQuery", () => ({
27
+ isMobileDevice: () => true,
28
+ mediaQuery: () => "xs" as const,
29
+ mediaQueryLargerThan: () => false,
30
+ mediaQuerySmallerThan: () => true,
31
+ }));
32
+ };
33
+
34
+ // Restore MediaQuery to bunSetup defaults after all tests to prevent cross-file pollution.
35
+ // bunSetup mocks: isMobileDevice → false, mediaQueryLargerThan → false.
36
+ const restoreDefault = () => {
37
+ mock.module("./MediaQuery", () => ({
38
+ isMobileDevice: mock(() => false),
39
+ mediaQueryLargerThan: mock(() => false),
40
+ }));
41
+ };
42
+
43
+ afterAll(() => {
44
+ restoreDefault();
45
+ });
46
+
21
47
  describe("SplitPage", () => {
22
48
  const defaultProps = {
23
49
  listViewData: [
@@ -29,6 +55,14 @@ describe("SplitPage", () => {
29
55
  ),
30
56
  };
31
57
 
58
+ beforeEach(() => {
59
+ setDesktop();
60
+ });
61
+
62
+ afterEach(() => {
63
+ setDesktop();
64
+ });
65
+
32
66
  it("renders correctly with renderContent", () => {
33
67
  const {toJSON} = renderWithTheme(
34
68
  <SplitPage
@@ -184,42 +218,8 @@ describe("SplitPage", () => {
184
218
  });
185
219
 
186
220
  describe("desktop viewport (mediaQueryLargerThan('sm') true)", () => {
187
- const desktopImpl: DimensionsGetImpl = () => ({
188
- fontScale: 1,
189
- height: 1000,
190
- scale: 2,
191
- width: 1400,
192
- });
193
- const mobileImpl: DimensionsGetImpl = () => ({
194
- fontScale: 1,
195
- height: 812,
196
- scale: 2,
197
- width: 375,
198
- });
199
- let originalGet: typeof Dimensions.get;
200
- beforeAll(() => {
201
- originalGet = Dimensions.get;
202
- const dimGet = Dimensions.get as MockableDimensionsGet;
203
- if (typeof dimGet.mockImplementation === "function") {
204
- dimGet.mockImplementation(desktopImpl);
205
- } else {
206
- (Dimensions as {get: DimensionsGetImpl}).get = desktopImpl;
207
- }
208
- });
209
- afterAll(() => {
210
- const dimGet = Dimensions.get as MockableDimensionsGet;
211
- if (typeof dimGet.mockImplementation === "function") {
212
- dimGet.mockImplementation(mobileImpl);
213
- } else {
214
- (Dimensions as {get: DimensionsGetImpl}).get = originalGet;
215
- }
216
- });
217
-
218
- it("verifies Dimensions mock is overridden", () => {
219
- expect(Dimensions.get("window").width).toBe(1400);
220
- });
221
-
222
221
  it("renders renderList/renderContent on desktop", () => {
222
+ setDesktop();
223
223
  const {toJSON} = renderWithTheme(
224
224
  <SplitPage
225
225
  {...defaultProps}
@@ -230,6 +230,7 @@ describe("SplitPage", () => {
230
230
  });
231
231
 
232
232
  it("renders renderList/renderChildrenContent on desktop with 2 children", () => {
233
+ setDesktop();
233
234
  const {toJSON} = renderWithTheme(
234
235
  <SplitPage {...defaultProps}>
235
236
  <View testID="child-1" />
@@ -240,6 +241,7 @@ describe("SplitPage", () => {
240
241
  });
241
242
 
242
243
  it("renders renderChildrenContent with >2 children and tabs on desktop", () => {
244
+ setDesktop();
243
245
  const {toJSON} = renderWithTheme(
244
246
  <SplitPage {...defaultProps} tabs={["A", "B", "C"]}>
245
247
  <View testID="child-1" />
@@ -251,6 +253,7 @@ describe("SplitPage", () => {
251
253
  });
252
254
 
253
255
  it("renders with listViewWidth/listViewMaxWidth applied", () => {
256
+ setDesktop();
254
257
  const {toJSON} = renderWithTheme(
255
258
  <SplitPage
256
259
  {...defaultProps}
@@ -263,8 +266,202 @@ describe("SplitPage", () => {
263
266
  });
264
267
  });
265
268
 
269
+ describe("mobile viewport (mediaQueryLargerThan('sm') false)", () => {
270
+ it("renders mobile list view when no item is selected", () => {
271
+ setMobile();
272
+ const {toJSON} = renderWithTheme(
273
+ <SplitPage
274
+ {...defaultProps}
275
+ renderContent={(selectedId) => <View testID={`content-${selectedId}`} />}
276
+ />
277
+ );
278
+ expect(toJSON()).toBeTruthy();
279
+ });
280
+
281
+ it("renders mobile list content when item is selected via renderContent", async () => {
282
+ setMobile();
283
+ const {fireEvent} = await import("@testing-library/react-native");
284
+ const {getAllByLabelText, queryByTestId} = renderWithTheme(
285
+ <SplitPage
286
+ {...defaultProps}
287
+ renderContent={(selectedId) => <View testID={`content-${selectedId}`} />}
288
+ />
289
+ );
290
+ const boxes = getAllByLabelText("Select");
291
+ await act(async () => {
292
+ fireEvent.press(boxes[0]);
293
+ });
294
+ expect(queryByTestId("content-0")).toBeTruthy();
295
+ });
296
+
297
+ it("renders mobile children content with swiper when item is selected", async () => {
298
+ setMobile();
299
+ const {fireEvent} = await import("@testing-library/react-native");
300
+ const {getAllByLabelText, queryByTestId} = renderWithTheme(
301
+ <SplitPage {...defaultProps}>
302
+ <View testID="child-1" />
303
+ <View testID="child-2" />
304
+ </SplitPage>
305
+ );
306
+ const boxes = getAllByLabelText("Select");
307
+ await act(async () => {
308
+ fireEvent.press(boxes[0]);
309
+ });
310
+ expect(queryByTestId("swiper-flatlist")).toBeTruthy();
311
+ });
312
+
313
+ it("returns null for mobile children content when no item selected", () => {
314
+ setMobile();
315
+ const {queryByTestId} = renderWithTheme(
316
+ <SplitPage {...defaultProps}>
317
+ <View testID="child-1" />
318
+ <View testID="child-2" />
319
+ </SplitPage>
320
+ );
321
+ expect(queryByTestId("swiper-flatlist")).toBeNull();
322
+ });
323
+
324
+ it("hides mobile list when item selected", async () => {
325
+ setMobile();
326
+ const {fireEvent} = await import("@testing-library/react-native");
327
+ const {getAllByLabelText, toJSON} = renderWithTheme(
328
+ <SplitPage
329
+ {...defaultProps}
330
+ renderContent={(selectedId) => <View testID={`content-${selectedId}`} />}
331
+ />
332
+ );
333
+ const boxes = getAllByLabelText("Select");
334
+ await act(async () => {
335
+ fireEvent.press(boxes[0]);
336
+ });
337
+ expect(toJSON()).toBeTruthy();
338
+ });
339
+
340
+ it("can deselect item via IconButton onClick on mobile", async () => {
341
+ setMobile();
342
+ const {fireEvent} = await import("@testing-library/react-native");
343
+ const onSelectionChange = mock(async (_arg: unknown) => {});
344
+ const {getAllByLabelText, UNSAFE_root} = renderWithTheme(
345
+ <SplitPage
346
+ {...defaultProps}
347
+ onSelectionChange={onSelectionChange}
348
+ renderContent={(selectedId) => <View testID={`content-${selectedId}`} />}
349
+ />
350
+ );
351
+ const boxes = getAllByLabelText("Select");
352
+ await act(async () => {
353
+ fireEvent.press(boxes[0]);
354
+ });
355
+ const iconButtons = UNSAFE_root.findAll(
356
+ (n: any) => n.props?.onClick && n.props?.iconName === "xmark"
357
+ );
358
+ if (iconButtons.length > 0) {
359
+ await act(async () => {
360
+ iconButtons[0].props.onClick();
361
+ });
362
+ expect(onSelectionChange).toHaveBeenCalledWith(undefined);
363
+ } else {
364
+ const closeButtons = UNSAFE_root.findAll(
365
+ (n: any) => n.props?.accessibilityLabel === "close"
366
+ );
367
+ if (closeButtons.length > 0) {
368
+ await act(async () => {
369
+ if (closeButtons[0].props.onClick) {
370
+ closeButtons[0].props.onClick();
371
+ } else if (closeButtons[0].props.onPress) {
372
+ closeButtons[0].props.onPress();
373
+ }
374
+ });
375
+ }
376
+ expect(onSelectionChange).toHaveBeenCalledWith(undefined);
377
+ }
378
+ });
379
+
380
+ it("renders mobile list view header when provided", () => {
381
+ setMobile();
382
+ const {toJSON} = renderWithTheme(
383
+ <SplitPage
384
+ {...defaultProps}
385
+ renderContent={(selectedId) => <View testID={`content-${selectedId}`} />}
386
+ renderListViewHeader={() => <View testID="mobile-header" />}
387
+ />
388
+ );
389
+ expect(toJSON()).toBeTruthy();
390
+ });
391
+
392
+ it("renders mobile with bottomNavBarHeight", async () => {
393
+ setMobile();
394
+ const {fireEvent} = await import("@testing-library/react-native");
395
+ const {getAllByLabelText, toJSON} = renderWithTheme(
396
+ <SplitPage {...defaultProps} bottomNavBarHeight={50}>
397
+ <View testID="child-1" />
398
+ <View testID="child-2" />
399
+ </SplitPage>
400
+ );
401
+ const boxes = getAllByLabelText("Select");
402
+ await act(async () => {
403
+ fireEvent.press(boxes[0]);
404
+ });
405
+ expect(toJSON()).toBeTruthy();
406
+ });
407
+ });
408
+
409
+ describe("desktop renderChildrenContent >2 children with tabs", () => {
410
+ it("renders segmented control tabs and content on desktop with >2 children", () => {
411
+ setDesktop();
412
+ const {toJSON} = renderWithTheme(
413
+ <SplitPage {...defaultProps} tabs={["Tab A", "Tab B", "Tab C"]}>
414
+ <View testID="child-a" />
415
+ <View testID="child-b" />
416
+ <View testID="child-c" />
417
+ </SplitPage>
418
+ );
419
+ expect(toJSON()).toBeTruthy();
420
+ });
421
+
422
+ it("renders renderContent path on desktop (renderSplitPage)", () => {
423
+ setDesktop();
424
+ const {toJSON} = renderWithTheme(
425
+ <SplitPage
426
+ {...defaultProps}
427
+ renderContent={(id) => <View testID={`desktop-content-${id}`} />}
428
+ />
429
+ );
430
+ expect(toJSON()).toBeTruthy();
431
+ });
432
+
433
+ it("renders <= 2 children content with scroll views on desktop", () => {
434
+ setDesktop();
435
+ const {toJSON} = renderWithTheme(
436
+ <SplitPage {...defaultProps}>
437
+ <View testID="child-1" />
438
+ </SplitPage>
439
+ );
440
+ expect(toJSON()).toBeTruthy();
441
+ });
442
+
443
+ it("triggers segmented control onChange on desktop with >2 children", async () => {
444
+ setDesktop();
445
+ const {toJSON, UNSAFE_root} = renderWithTheme(
446
+ <SplitPage {...defaultProps} tabs={["Tab A", "Tab B", "Tab C"]}>
447
+ <View testID="child-a" />
448
+ <View testID="child-b" />
449
+ <View testID="child-c" />
450
+ </SplitPage>
451
+ );
452
+ const segmented = UNSAFE_root.findAll((n: any) => n.props?.onChange && n.props?.items);
453
+ if (segmented.length > 0) {
454
+ await act(async () => {
455
+ segmented[0].props.onChange(2);
456
+ });
457
+ }
458
+ expect(toJSON()).toBeTruthy();
459
+ });
460
+ });
461
+
266
462
  describe("item selection callbacks", () => {
267
463
  it("onItemSelect runs onSelectionChange when item clicked via Box press", async () => {
464
+ setMobile();
268
465
  const {fireEvent} = await import("@testing-library/react-native");
269
466
  const onSelectionChange = mock(async (_arg: unknown) => {});
270
467
  const {getAllByLabelText} = renderWithTheme(
@@ -284,6 +481,7 @@ describe("SplitPage", () => {
284
481
  });
285
482
 
286
483
  it("selecting an item shows mobile children content when no renderContent", async () => {
484
+ setMobile();
287
485
  const {fireEvent} = await import("@testing-library/react-native");
288
486
  const {getAllByLabelText, queryByTestId} = renderWithTheme(
289
487
  <SplitPage {...defaultProps}>
@@ -298,7 +496,48 @@ describe("SplitPage", () => {
298
496
  expect(queryByTestId("swiper-flatlist")).toBeTruthy();
299
497
  });
300
498
 
499
+ it("uses default onSelectionChange without throwing", async () => {
500
+ setMobile();
501
+ const {fireEvent} = await import("@testing-library/react-native");
502
+ const {getAllByLabelText, toJSON} = renderWithTheme(
503
+ <SplitPage {...defaultProps} renderContent={(id) => <View testID={`content-${id}`} />} />
504
+ );
505
+ const boxes = getAllByLabelText("Select");
506
+ await act(async () => {
507
+ fireEvent.press(boxes[0]);
508
+ });
509
+ expect(toJSON()).toBeTruthy();
510
+ });
511
+
512
+ it("covers elementArray.map in renderMobileChildrenContent", async () => {
513
+ setMobile();
514
+ const {fireEvent} = await import("@testing-library/react-native");
515
+ const {getAllByLabelText, queryByTestId} = renderWithTheme(
516
+ <SplitPage {...defaultProps} bottomNavBarHeight={50}>
517
+ <View testID="child-1" />
518
+ </SplitPage>
519
+ );
520
+ const boxes = getAllByLabelText("Select");
521
+ await act(async () => {
522
+ fireEvent.press(boxes[0]);
523
+ });
524
+ expect(queryByTestId("swiper-flatlist")).toBeTruthy();
525
+ });
526
+
527
+ it("covers activeTabs.map in renderChildrenContent on desktop", () => {
528
+ setDesktop();
529
+ const {toJSON} = renderWithTheme(
530
+ <SplitPage {...defaultProps} tabs={["Tab A", "Tab B", "Tab C"]}>
531
+ <View testID="child-a" />
532
+ <View testID="child-b" />
533
+ <View testID="child-c" />
534
+ </SplitPage>
535
+ );
536
+ expect(toJSON()).toBeTruthy();
537
+ });
538
+
301
539
  it("selection deselect when showItemList becomes true", async () => {
540
+ setMobile();
302
541
  const onSelectionChange = mock(async () => {});
303
542
  const {rerender} = renderWithTheme(
304
543
  <SplitPage
@@ -322,5 +561,22 @@ describe("SplitPage", () => {
322
561
  // showItemList=true triggers onItemDeselect -> onSelectionChange(undefined)
323
562
  expect(onSelectionChange).toHaveBeenCalled();
324
563
  });
564
+
565
+ it("renders SegmentedControl with >2 children and tabs on mobile", async () => {
566
+ const {fireEvent} = await import("@testing-library/react-native");
567
+ const {getAllByLabelText, root} = renderWithTheme(
568
+ <SplitPage {...defaultProps} tabs={["Tab A", "Tab B", "Tab C"]}>
569
+ <View testID="child-a" />
570
+ <View testID="child-b" />
571
+ <View testID="child-c" />
572
+ </SplitPage>
573
+ );
574
+ // First select an item to show children content
575
+ const boxes = getAllByLabelText("Select");
576
+ await act(async () => {
577
+ fireEvent.press(boxes[0]);
578
+ });
579
+ expect(root).toBeTruthy();
580
+ });
325
581
  });
326
582
  });
@@ -331,4 +331,48 @@ describe("formatAddress", () => {
331
331
  expect(result).toContain("Dallas County");
332
332
  expect(result).toContain("(113)");
333
333
  });
334
+
335
+ it("handles address with county name but no county code", () => {
336
+ const address = {
337
+ address1: "100 County Rd",
338
+ city: "Rural Town",
339
+ countyName: "Dallas County",
340
+ state: "TX",
341
+ zipcode: "75001",
342
+ };
343
+ const result = formatAddress(address);
344
+ expect(result).toContain("Dallas County");
345
+ expect(result).not.toContain("(");
346
+ });
347
+ });
348
+
349
+ describe("TapToEdit - additional function coverage", () => {
350
+ it("shows Clear button for date type and invokes setValue and onSave", async () => {
351
+ const setValue = mock(() => {});
352
+ const onSave = mock(() => Promise.resolve());
353
+ const {getByLabelText, getByText} = renderWithTheme(
354
+ <TapToEdit onSave={onSave} setValue={setValue} title="Date" type="date" value="2024-01-01" />
355
+ );
356
+ await act(async () => {
357
+ fireEvent.press(getByLabelText("Edit"));
358
+ });
359
+ expect(getByText("Clear")).toBeTruthy();
360
+ await act(async () => {
361
+ fireEvent.press(getByText("Clear"));
362
+ await new Promise((resolve) => setTimeout(resolve, 600));
363
+ });
364
+ expect(setValue).toHaveBeenCalledWith("");
365
+ expect(onSave).toHaveBeenCalledWith("");
366
+ });
367
+
368
+ it("assigns inputRef for text type in editing mode", async () => {
369
+ const setValue = mock(() => {});
370
+ const {getByLabelText, queryByText} = renderWithTheme(
371
+ <TapToEdit setValue={setValue} title="Name" type="text" value="Alice" />
372
+ );
373
+ await act(async () => {
374
+ fireEvent.press(getByLabelText("Edit"));
375
+ });
376
+ expect(queryByText("Save")).toBeTruthy();
377
+ });
334
378
  });
package/src/TapToEdit.tsx CHANGED
@@ -26,7 +26,7 @@ const TapToEditTitle: FC<{
26
26
  );
27
27
  };
28
28
 
29
- export function formatAddress(address: AddressInterface, asString = false): string {
29
+ export const formatAddress = (address: AddressInterface, asString = false): string => {
30
30
  let city = "";
31
31
  if (address?.city) {
32
32
  city = address?.state || address.zipcode ? `${address.city}, ` : `${address.city}`;
@@ -49,7 +49,6 @@ export function formatAddress(address: AddressInterface, asString = false): stri
49
49
  const addressLineFour = `${countyName}${address?.countyCode ? ` (${countyCode})` : ""}`;
50
50
 
51
51
  if (!asString) {
52
- // Only add new lines if lines before and after are not empty to avoid awkward whitespace
53
52
  return `${addressLineOne}${
54
53
  addressLineOne && (addressLineTwo || addressLineThree) ? `\n` : ""
55
54
  }${addressLineTwo}${addressLineTwo && addressLineThree ? `\n` : ""}${addressLineThree}${
@@ -62,7 +61,7 @@ export function formatAddress(address: AddressInterface, asString = false): stri
62
61
  addressLineThree && addressLineFour ? `, ` : ""
63
62
  }${addressLineFour}`;
64
63
  }
65
- }
64
+ };
66
65
 
67
66
  export const TapToEdit: FC<TapToEditProps> = ({
68
67
  value,