ferns-ui 2.0.0-beta.2 → 2.0.0-beta.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.
Files changed (140) hide show
  1. package/dist/Accordion.js +7 -2
  2. package/dist/Accordion.js.map +1 -1
  3. package/dist/ActionSheet.js +14 -11
  4. package/dist/ActionSheet.js.map +1 -1
  5. package/dist/AddressField.js +1 -1
  6. package/dist/AddressField.js.map +1 -1
  7. package/dist/Badge.js +1 -1
  8. package/dist/Badge.js.map +1 -1
  9. package/dist/Banner.js +1 -1
  10. package/dist/Banner.js.map +1 -1
  11. package/dist/Box.js +3 -3
  12. package/dist/Box.js.map +1 -1
  13. package/dist/Button.js +0 -1
  14. package/dist/Button.js.map +1 -1
  15. package/dist/CheckBox.js.map +1 -1
  16. package/dist/Common.d.ts +13 -9
  17. package/dist/Common.js.map +1 -1
  18. package/dist/DataTable.js +1 -2
  19. package/dist/DataTable.js.map +1 -1
  20. package/dist/DateTimeField.js +22 -22
  21. package/dist/DateTimeField.js.map +1 -1
  22. package/dist/EmailField.js +17 -37
  23. package/dist/EmailField.js.map +1 -1
  24. package/dist/FernsProvider.js +1 -1
  25. package/dist/FernsProvider.js.map +1 -1
  26. package/dist/Heading.js +3 -1
  27. package/dist/Heading.js.map +1 -1
  28. package/dist/Hyperlink.js +1 -1
  29. package/dist/Hyperlink.js.map +1 -1
  30. package/dist/IconButton.js +1 -1
  31. package/dist/IconButton.js.map +1 -1
  32. package/dist/Image.js.map +1 -1
  33. package/dist/MarkdownView.d.ts +5 -0
  34. package/dist/MarkdownView.js +44 -0
  35. package/dist/MarkdownView.js.map +1 -0
  36. package/dist/MobileAddressAutoComplete.js +1 -1
  37. package/dist/MobileAddressAutoComplete.js.map +1 -1
  38. package/dist/Modal.d.ts +1 -1
  39. package/dist/Modal.js +35 -15
  40. package/dist/Modal.js.map +1 -1
  41. package/dist/NumberField.js +10 -4
  42. package/dist/NumberField.js.map +1 -1
  43. package/dist/NumberPickerActionSheet.d.ts +1 -3
  44. package/dist/NumberPickerActionSheet.js +0 -3
  45. package/dist/NumberPickerActionSheet.js.map +1 -1
  46. package/dist/Page.js +1 -1
  47. package/dist/Page.js.map +1 -1
  48. package/dist/Pagination.js +2 -2
  49. package/dist/Pagination.js.map +1 -1
  50. package/dist/Permissions.d.ts +1 -1
  51. package/dist/Permissions.js +2 -2
  52. package/dist/Permissions.js.map +1 -1
  53. package/dist/PickerSelect.js +1 -1
  54. package/dist/PickerSelect.js.map +1 -1
  55. package/dist/SectionDivider.js +1 -1
  56. package/dist/SectionDivider.js.map +1 -1
  57. package/dist/SegmentedControl.js.map +1 -1
  58. package/dist/Signature.native.js +2 -2
  59. package/dist/Signature.native.js.map +1 -1
  60. package/dist/SignatureField.js +2 -2
  61. package/dist/SignatureField.js.map +1 -1
  62. package/dist/Slider.js +3 -3
  63. package/dist/Slider.js.map +1 -1
  64. package/dist/SplitPage.js +7 -7
  65. package/dist/SplitPage.js.map +1 -1
  66. package/dist/SplitPage.native.js +4 -6
  67. package/dist/SplitPage.native.js.map +1 -1
  68. package/dist/TapToEdit.js +3 -3
  69. package/dist/TapToEdit.js.map +1 -1
  70. package/dist/Text.js +1 -1
  71. package/dist/Text.js.map +1 -1
  72. package/dist/TextFieldNumberActionSheet.d.ts +2 -4
  73. package/dist/TextFieldNumberActionSheet.js +1 -4
  74. package/dist/TextFieldNumberActionSheet.js.map +1 -1
  75. package/dist/Tooltip.js +37 -19
  76. package/dist/Tooltip.js.map +1 -1
  77. package/dist/Unifier.d.ts +0 -1
  78. package/dist/Unifier.js.map +1 -1
  79. package/dist/Utilities.d.ts +1 -1
  80. package/dist/Utilities.js +2 -3
  81. package/dist/Utilities.js.map +1 -1
  82. package/dist/WebAddressAutocomplete.js +2 -1
  83. package/dist/WebAddressAutocomplete.js.map +1 -1
  84. package/dist/index.d.ts +10 -10
  85. package/dist/index.js +10 -9
  86. package/dist/index.js.map +1 -1
  87. package/dist/table/Table.js +14 -15
  88. package/dist/table/Table.js.map +1 -1
  89. package/dist/table/TableHeaderCell.js +2 -2
  90. package/dist/table/TableHeaderCell.js.map +1 -1
  91. package/dist/useStoredState.js +4 -2
  92. package/dist/useStoredState.js.map +1 -1
  93. package/package.json +5 -64
  94. package/src/Accordion.tsx +7 -1
  95. package/src/ActionSheet.tsx +26 -22
  96. package/src/AddressField.tsx +1 -1
  97. package/src/Badge.tsx +1 -1
  98. package/src/Banner.tsx +1 -1
  99. package/src/Box.test.tsx +71 -70
  100. package/src/Box.tsx +21 -9
  101. package/src/Button.tsx +0 -1
  102. package/src/CheckBox.tsx +7 -1
  103. package/src/Common.ts +14 -21
  104. package/src/DataTable.tsx +1 -2
  105. package/src/DateTimeField.tsx +22 -22
  106. package/src/EmailField.tsx +22 -42
  107. package/src/FernsProvider.tsx +1 -4
  108. package/src/Heading.tsx +3 -1
  109. package/src/Hyperlink.tsx +1 -1
  110. package/src/IconButton.tsx +2 -2
  111. package/src/Image.tsx +1 -0
  112. package/src/MarkdownView.tsx +67 -0
  113. package/src/MobileAddressAutoComplete.tsx +1 -1
  114. package/src/Modal.tsx +58 -21
  115. package/src/NumberField.tsx +10 -4
  116. package/src/NumberPickerActionSheet.tsx +1 -5
  117. package/src/Page.tsx +1 -1
  118. package/src/Pagination.tsx +2 -11
  119. package/src/Permissions.ts +2 -2
  120. package/src/PickerSelect.tsx +1 -1
  121. package/src/SectionDivider.tsx +1 -1
  122. package/src/SegmentedControl.tsx +3 -1
  123. package/src/Signature.native.tsx +2 -2
  124. package/src/SignatureField.tsx +2 -2
  125. package/src/Slider.tsx +10 -17
  126. package/src/SplitPage.native.tsx +2 -4
  127. package/src/SplitPage.tsx +4 -4
  128. package/src/TapToEdit.tsx +3 -7
  129. package/src/Text.tsx +1 -1
  130. package/src/TextArea.test.tsx +27 -43
  131. package/src/TextField.test.tsx +3 -4
  132. package/src/TextFieldNumberActionSheet.tsx +3 -7
  133. package/src/Tooltip.tsx +41 -19
  134. package/src/Unifier.ts +1 -3
  135. package/src/Utilities.tsx +3 -4
  136. package/src/WebAddressAutocomplete.tsx +1 -1
  137. package/src/index.tsx +11 -10
  138. package/src/table/Table.tsx +34 -36
  139. package/src/table/TableHeaderCell.tsx +2 -2
  140. package/src/useStoredState.ts +13 -11
package/src/Box.test.tsx CHANGED
@@ -38,7 +38,7 @@ describe("Box", () => {
38
38
  const view = root.findByType("View");
39
39
  expect(view.props.style).toMatchObject({
40
40
  flexDirection: "column",
41
- display: "flex"
41
+ display: "flex",
42
42
  });
43
43
  });
44
44
 
@@ -53,7 +53,7 @@ describe("Box", () => {
53
53
  expect(view.props.style).toMatchObject({
54
54
  flexGrow: 1,
55
55
  flexShrink: 1,
56
- display: "flex"
56
+ display: "flex",
57
57
  });
58
58
  });
59
59
 
@@ -62,7 +62,7 @@ describe("Box", () => {
62
62
  const view = root.findByType("View");
63
63
  expect(view.props.style).toMatchObject({
64
64
  flexShrink: 1,
65
- display: "flex"
65
+ display: "flex",
66
66
  });
67
67
  });
68
68
 
@@ -71,7 +71,7 @@ describe("Box", () => {
71
71
  const view = root.findByType("View");
72
72
  expect(view.props.style).toMatchObject({
73
73
  flex: 0,
74
- display: "flex"
74
+ display: "flex",
75
75
  });
76
76
  });
77
77
 
@@ -79,7 +79,7 @@ describe("Box", () => {
79
79
  const {root} = renderWithTheme(<Box justifyContent="center" />);
80
80
  const view = root.findByType("View");
81
81
  expect(view.props.style).toMatchObject({
82
- justifyContent: "center"
82
+ justifyContent: "center",
83
83
  });
84
84
  });
85
85
 
@@ -87,7 +87,7 @@ describe("Box", () => {
87
87
  const {root} = renderWithTheme(<Box alignItems="center" />);
88
88
  const view = root.findByType("View");
89
89
  expect(view.props.style).toMatchObject({
90
- alignItems: "center"
90
+ alignItems: "center",
91
91
  });
92
92
  });
93
93
 
@@ -95,7 +95,7 @@ describe("Box", () => {
95
95
  const {root} = renderWithTheme(<Box alignContent="center" />);
96
96
  const view = root.findByType("View");
97
97
  expect(view.props.style).toMatchObject({
98
- alignContent: "center"
98
+ alignContent: "center",
99
99
  });
100
100
  });
101
101
 
@@ -103,7 +103,7 @@ describe("Box", () => {
103
103
  const {root} = renderWithTheme(<Box alignSelf="center" />);
104
104
  const view = root.findByType("View");
105
105
  expect(view.props.style).toMatchObject({
106
- alignSelf: "center"
106
+ alignSelf: "center",
107
107
  });
108
108
  });
109
109
 
@@ -112,7 +112,7 @@ describe("Box", () => {
112
112
  const view = root.findByType("View");
113
113
  expect(view.props.style).toMatchObject({
114
114
  flexWrap: "wrap",
115
- alignItems: "flex-start"
115
+ alignItems: "flex-start",
116
116
  });
117
117
  });
118
118
 
@@ -120,7 +120,7 @@ describe("Box", () => {
120
120
  const {root} = renderWithTheme(<Box gap={4} />);
121
121
  const view = root.findByType("View");
122
122
  expect(view.props.style).toMatchObject({
123
- gap: 16
123
+ gap: 16,
124
124
  });
125
125
  });
126
126
  });
@@ -130,7 +130,7 @@ describe("Box", () => {
130
130
  const {root} = renderWithTheme(<Box padding={4} />);
131
131
  const view = root.findByType("View");
132
132
  expect(view.props.style).toMatchObject({
133
- padding: 16
133
+ padding: 16,
134
134
  });
135
135
  });
136
136
 
@@ -139,7 +139,7 @@ describe("Box", () => {
139
139
  const view = root.findByType("View");
140
140
  expect(view.props.style).toMatchObject({
141
141
  paddingLeft: 8,
142
- paddingRight: 8
142
+ paddingRight: 8,
143
143
  });
144
144
  });
145
145
 
@@ -148,7 +148,7 @@ describe("Box", () => {
148
148
  const view = root.findByType("View");
149
149
  expect(view.props.style).toMatchObject({
150
150
  paddingTop: 12,
151
- paddingBottom: 12
151
+ paddingBottom: 12,
152
152
  });
153
153
  });
154
154
 
@@ -156,7 +156,7 @@ describe("Box", () => {
156
156
  const {root} = renderWithTheme(<Box margin={4} />);
157
157
  const view = root.findByType("View");
158
158
  expect(view.props.style).toMatchObject({
159
- margin: 16
159
+ margin: 16,
160
160
  });
161
161
  });
162
162
 
@@ -164,7 +164,7 @@ describe("Box", () => {
164
164
  const {root} = renderWithTheme(<Box marginTop={2} />);
165
165
  const view = root.findByType("View");
166
166
  expect(view.props.style).toMatchObject({
167
- marginTop: 8
167
+ marginTop: 8,
168
168
  });
169
169
  });
170
170
 
@@ -172,7 +172,7 @@ describe("Box", () => {
172
172
  const {root} = renderWithTheme(<Box marginBottom={2} />);
173
173
  const view = root.findByType("View");
174
174
  expect(view.props.style).toMatchObject({
175
- marginBottom: 8
175
+ marginBottom: 8,
176
176
  });
177
177
  });
178
178
 
@@ -180,7 +180,7 @@ describe("Box", () => {
180
180
  const {root} = renderWithTheme(<Box marginLeft={2} />);
181
181
  const view = root.findByType("View");
182
182
  expect(view.props.style).toMatchObject({
183
- marginLeft: 8
183
+ marginLeft: 8,
184
184
  });
185
185
  });
186
186
 
@@ -188,7 +188,7 @@ describe("Box", () => {
188
188
  const {root} = renderWithTheme(<Box marginRight={2} />);
189
189
  const view = root.findByType("View");
190
190
  expect(view.props.style).toMatchObject({
191
- marginRight: 8
191
+ marginRight: 8,
192
192
  });
193
193
  });
194
194
  });
@@ -198,7 +198,7 @@ describe("Box", () => {
198
198
  const {root} = renderWithTheme(<Box width={100} />);
199
199
  const view = root.findByType("View");
200
200
  expect(view.props.style).toMatchObject({
201
- width: 100
201
+ width: 100,
202
202
  });
203
203
  });
204
204
 
@@ -206,7 +206,7 @@ describe("Box", () => {
206
206
  const {root} = renderWithTheme(<Box height={100} />);
207
207
  const view = root.findByType("View");
208
208
  expect(view.props.style).toMatchObject({
209
- height: 100
209
+ height: 100,
210
210
  });
211
211
  });
212
212
 
@@ -214,7 +214,7 @@ describe("Box", () => {
214
214
  const {root} = renderWithTheme(<Box width="50%" />);
215
215
  const view = root.findByType("View");
216
216
  expect(view.props.style).toMatchObject({
217
- width: "50%"
217
+ width: "50%",
218
218
  });
219
219
  });
220
220
 
@@ -222,7 +222,7 @@ describe("Box", () => {
222
222
  const {root} = renderWithTheme(<Box height="50%" />);
223
223
  const view = root.findByType("View");
224
224
  expect(view.props.style).toMatchObject({
225
- height: "50%"
225
+ height: "50%",
226
226
  });
227
227
  });
228
228
  });
@@ -232,7 +232,7 @@ describe("Box", () => {
232
232
  const {root} = renderWithTheme(<Box position="absolute" />);
233
233
  const view = root.findByType("View");
234
234
  expect(view.props.style).toMatchObject({
235
- position: "absolute"
235
+ position: "absolute",
236
236
  });
237
237
  });
238
238
 
@@ -240,7 +240,7 @@ describe("Box", () => {
240
240
  const {root} = renderWithTheme(<Box top />);
241
241
  const view = root.findByType("View");
242
242
  expect(view.props.style).toMatchObject({
243
- top: 0
243
+ top: 0,
244
244
  });
245
245
  });
246
246
 
@@ -248,7 +248,7 @@ describe("Box", () => {
248
248
  const {root} = renderWithTheme(<Box bottom />);
249
249
  const view = root.findByType("View");
250
250
  expect(view.props.style).toMatchObject({
251
- bottom: 0
251
+ bottom: 0,
252
252
  });
253
253
  });
254
254
 
@@ -256,7 +256,7 @@ describe("Box", () => {
256
256
  const {root} = renderWithTheme(<Box left />);
257
257
  const view = root.findByType("View");
258
258
  expect(view.props.style).toMatchObject({
259
- left: 0
259
+ left: 0,
260
260
  });
261
261
  });
262
262
 
@@ -264,7 +264,7 @@ describe("Box", () => {
264
264
  const {root} = renderWithTheme(<Box right />);
265
265
  const view = root.findByType("View");
266
266
  expect(view.props.style).toMatchObject({
267
- right: 0
267
+ right: 0,
268
268
  });
269
269
  });
270
270
 
@@ -272,7 +272,7 @@ describe("Box", () => {
272
272
  const {root} = renderWithTheme(<Box zIndex={10} />);
273
273
  const view = root.findByType("View");
274
274
  expect(view.props.style).toMatchObject({
275
- zIndex: 10
275
+ zIndex: 10,
276
276
  });
277
277
  });
278
278
  });
@@ -356,7 +356,9 @@ describe("Box", () => {
356
356
  it("should warn when using circle without dimensions", () => {
357
357
  const consoleSpy = jest.spyOn(console, "warn").mockImplementation();
358
358
  renderWithTheme(<Box rounding="circle" />);
359
- expect(consoleSpy).toHaveBeenCalledWith("Cannot use Box rounding='circle' without height or width.");
359
+ expect(consoleSpy).toHaveBeenCalledWith(
360
+ "Cannot use Box rounding='circle' without height or width."
361
+ );
360
362
  consoleSpy.mockRestore();
361
363
  });
362
364
  });
@@ -366,7 +368,7 @@ describe("Box", () => {
366
368
  const {root} = renderWithTheme(<Box display="none" />);
367
369
  const view = root.findByType("View");
368
370
  expect(view.props.style).toMatchObject({
369
- display: "none"
371
+ display: "none",
370
372
  });
371
373
  });
372
374
 
@@ -374,7 +376,7 @@ describe("Box", () => {
374
376
  const {root} = renderWithTheme(<Box display="flex" />);
375
377
  const view = root.findByType("View");
376
378
  expect(view.props.style).toMatchObject({
377
- flex: undefined
379
+ flex: undefined,
378
380
  });
379
381
  });
380
382
 
@@ -383,7 +385,7 @@ describe("Box", () => {
383
385
  const view = root.findByType("View");
384
386
  expect(view.props.style).toMatchObject({
385
387
  flex: 0,
386
- flexDirection: "row"
388
+ flexDirection: "row",
387
389
  });
388
390
  });
389
391
  });
@@ -393,7 +395,7 @@ describe("Box", () => {
393
395
  const {root} = renderWithTheme(<Box overflow="scroll" />);
394
396
  const view = root.findByType("View");
395
397
  expect(view.props.style).toMatchObject({
396
- overflow: "scroll"
398
+ overflow: "scroll",
397
399
  });
398
400
  });
399
401
 
@@ -401,7 +403,7 @@ describe("Box", () => {
401
403
  const {root} = renderWithTheme(<Box overflow="scrollY" />);
402
404
  const view = root.findByType("View");
403
405
  expect(view.props.style).toMatchObject({
404
- overflow: "scroll"
406
+ overflow: "scroll",
405
407
  });
406
408
  });
407
409
 
@@ -409,7 +411,7 @@ describe("Box", () => {
409
411
  const {root} = renderWithTheme(<Box overflow="hidden" />);
410
412
  const view = root.findByType("View");
411
413
  expect(view.props.style).toMatchObject({
412
- overflow: "hidden"
414
+ overflow: "hidden",
413
415
  });
414
416
  });
415
417
  });
@@ -426,11 +428,15 @@ describe("Box", () => {
426
428
  it("should render as Pressable when onClick is provided", () => {
427
429
  const mockOnClick = jest.fn();
428
430
  const {root} = renderWithTheme(
429
- <Box onClick={mockOnClick} accessibilityLabel="Click me" accessibilityHint="Tap to trigger action">
431
+ <Box
432
+ onClick={mockOnClick}
433
+ accessibilityLabel="Click me"
434
+ accessibilityHint="Tap to trigger action"
435
+ >
430
436
  <Text>Clickable content</Text>
431
437
  </Box>
432
438
  );
433
-
439
+
434
440
  expect(root).toBeTruthy();
435
441
  // Just verify the component renders without error when onClick is provided
436
442
  });
@@ -438,33 +444,33 @@ describe("Box", () => {
438
444
  it("should call onClick when pressed", async () => {
439
445
  const mockOnClick = jest.fn();
440
446
  const {getByTestId} = renderWithTheme(
441
- <Box
442
- onClick={mockOnClick}
447
+ <Box
448
+ onClick={mockOnClick}
443
449
  testID="clickable-box"
444
- accessibilityLabel="Click me"
450
+ accessibilityLabel="Click me"
445
451
  accessibilityHint="Tap to trigger action"
446
452
  />
447
453
  );
448
-
454
+
449
455
  const pressable = getByTestId("clickable-box-clickable");
450
456
  await act(async () => {
451
457
  fireEvent.press(pressable);
452
458
  });
453
-
459
+
454
460
  expect(mockOnClick).toHaveBeenCalledTimes(1);
455
461
  });
456
462
 
457
463
  it("should apply accessibility props to Pressable", () => {
458
464
  const mockOnClick = jest.fn();
459
465
  const {getByTestId} = renderWithTheme(
460
- <Box
466
+ <Box
461
467
  onClick={mockOnClick}
462
468
  testID="accessible-box"
463
469
  accessibilityLabel="Click me"
464
470
  accessibilityHint="Tap to trigger action"
465
471
  />
466
472
  );
467
-
473
+
468
474
  const pressable = getByTestId("accessible-box-clickable");
469
475
  expect(pressable).toBeTruthy();
470
476
  // Basic check that accessibility props are being applied
@@ -513,26 +519,24 @@ describe("Box", () => {
513
519
  const {getByTestId} = renderWithTheme(
514
520
  <Box onHoverStart={mockOnHoverStart} testID="hover-box" />
515
521
  );
516
-
522
+
517
523
  const view = getByTestId("hover-box");
518
524
  await act(async () => {
519
525
  fireEvent(view, "pointerEnter");
520
526
  });
521
-
527
+
522
528
  expect(mockOnHoverStart).toHaveBeenCalledTimes(1);
523
529
  });
524
530
 
525
531
  it("should call onHoverEnd", async () => {
526
532
  const mockOnHoverEnd = jest.fn();
527
- const {getByTestId} = renderWithTheme(
528
- <Box onHoverEnd={mockOnHoverEnd} testID="hover-box" />
529
- );
530
-
533
+ const {getByTestId} = renderWithTheme(<Box onHoverEnd={mockOnHoverEnd} testID="hover-box" />);
534
+
531
535
  const view = getByTestId("hover-box");
532
536
  await act(async () => {
533
537
  fireEvent(view, "pointerLeave");
534
538
  });
535
-
539
+
536
540
  expect(mockOnHoverEnd).toHaveBeenCalledTimes(1);
537
541
  });
538
542
  });
@@ -541,7 +545,7 @@ describe("Box", () => {
541
545
  it("should expose scrollToEnd method", () => {
542
546
  const ref = React.createRef<any>();
543
547
  renderWithTheme(<Box ref={ref} scroll />);
544
-
548
+
545
549
  expect(ref.current).toBeTruthy();
546
550
  expect(typeof ref.current.scrollToEnd).toBe("function");
547
551
  });
@@ -549,7 +553,7 @@ describe("Box", () => {
549
553
  it("should expose scrollTo method", () => {
550
554
  const ref = React.createRef<any>();
551
555
  renderWithTheme(<Box ref={ref} scroll />);
552
-
556
+
553
557
  expect(ref.current).toBeTruthy();
554
558
  expect(typeof ref.current.scrollTo).toBe("function");
555
559
  });
@@ -558,11 +562,11 @@ describe("Box", () => {
558
562
  describe("dangerous inline styles", () => {
559
563
  it("should apply dangerouslySetInlineStyle", () => {
560
564
  const {root} = renderWithTheme(
561
- <Box dangerouslySetInlineStyle={{ __style: { backgroundColor: "red" } }} />
565
+ <Box dangerouslySetInlineStyle={{__style: {backgroundColor: "red"}}} />
562
566
  );
563
567
  const view = root.findByType("View");
564
568
  expect(view.props.style).toMatchObject({
565
- backgroundColor: "red"
569
+ backgroundColor: "red",
566
570
  });
567
571
  });
568
572
  });
@@ -571,7 +575,9 @@ describe("Box", () => {
571
575
  it("should warn when using wrap and alignItems together", () => {
572
576
  const consoleSpy = jest.spyOn(console, "warn").mockImplementation();
573
577
  renderWithTheme(<Box wrap alignItems="center" />);
574
- expect(consoleSpy).toHaveBeenCalledWith("React Native doesn't support wrap and alignItems together.");
578
+ expect(consoleSpy).toHaveBeenCalledWith(
579
+ "React Native doesn't support wrap and alignItems together."
580
+ );
575
581
  consoleSpy.mockRestore();
576
582
  });
577
583
  });
@@ -604,7 +610,7 @@ describe("Box", () => {
604
610
  expect(view.props.style).toMatchObject({
605
611
  padding: 0,
606
612
  margin: 0,
607
- gap: 0
613
+ gap: 0,
608
614
  });
609
615
  });
610
616
  });
@@ -617,11 +623,11 @@ describe("Box", () => {
617
623
 
618
624
  it("should match snapshot with layout props", () => {
619
625
  const component = renderWithTheme(
620
- <Box
621
- direction="column"
622
- flex="grow"
623
- justifyContent="center"
624
- alignItems="center"
626
+ <Box
627
+ direction="column"
628
+ flex="grow"
629
+ justifyContent="center"
630
+ alignItems="center"
625
631
  padding={4}
626
632
  margin={2}
627
633
  />
@@ -631,7 +637,7 @@ describe("Box", () => {
631
637
 
632
638
  it("should match snapshot with clickable props", () => {
633
639
  const component = renderWithTheme(
634
- <Box
640
+ <Box
635
641
  onClick={jest.fn()}
636
642
  accessibilityLabel="Click me"
637
643
  accessibilityHint="Tap to trigger action"
@@ -652,14 +658,9 @@ describe("Box", () => {
652
658
 
653
659
  it("should match snapshot with border and rounding", () => {
654
660
  const component = renderWithTheme(
655
- <Box
656
- border="default"
657
- rounding="md"
658
- color="primary"
659
- shadow
660
- />
661
+ <Box border="default" rounding="md" color="primary" shadow />
661
662
  );
662
663
  expect(component.toJSON()).toMatchSnapshot();
663
664
  });
664
665
  });
665
- });
666
+ });
package/src/Box.tsx CHANGED
@@ -58,7 +58,7 @@ const isValidPercentage = (value: string): boolean => {
58
58
  };
59
59
 
60
60
  const isValidWidthHeight = (value: number | string): boolean => {
61
- return typeof value === 'number' || !isNaN(Number(value)) || isValidPercentage(value);
61
+ return typeof value === "number" || !Number.isNaN(Number(value)) || isValidPercentage(value);
62
62
  };
63
63
 
64
64
  // eslint-disable-next-line react/display-name
@@ -153,10 +153,12 @@ export const Box = React.forwardRef((props: BoxProps, ref) => {
153
153
  gap: (value) => ({gap: getSpacing(value)}),
154
154
  height: (value) => {
155
155
  if (!isValidWidthHeight(value)) {
156
- console.warn(`Box: height prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
156
+ console.warn(
157
+ `Box: height prop must be a number or percentage string (e.g., "50%"), received: ${value}`
158
+ );
157
159
  return {};
158
160
  }
159
- if (props.border && !isNaN(Number(value))) {
161
+ if (props.border && !Number.isNaN(Number(value))) {
160
162
  return {height: Number(value) + 2 * 2};
161
163
  } else {
162
164
  return {height: value};
@@ -210,10 +212,12 @@ export const Box = React.forwardRef((props: BoxProps, ref) => {
210
212
  top: (top) => ({top: top ? 0 : undefined}),
211
213
  width: (value) => {
212
214
  if (!isValidWidthHeight(value)) {
213
- console.warn(`Box: width prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
215
+ console.warn(
216
+ `Box: width prop must be a number or percentage string (e.g., "50%"), received: ${value}`
217
+ );
214
218
  return {};
215
219
  }
216
- if (props.border && !isNaN(Number(value))) {
220
+ if (props.border && !Number.isNaN(Number(value))) {
217
221
  return {width: Number(value) + 2 * 2};
218
222
  } else {
219
223
  return {width: value};
@@ -221,28 +225,36 @@ export const Box = React.forwardRef((props: BoxProps, ref) => {
221
225
  },
222
226
  maxHeight: (value) => {
223
227
  if (!isValidWidthHeight(value)) {
224
- console.warn(`Box: maxHeight prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
228
+ console.warn(
229
+ `Box: maxHeight prop must be a number or percentage string (e.g., "50%"), received: ${value}`
230
+ );
225
231
  return {};
226
232
  }
227
233
  return {maxHeight: value};
228
234
  },
229
235
  maxWidth: (value) => {
230
236
  if (!isValidWidthHeight(value)) {
231
- console.warn(`Box: maxWidth prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
237
+ console.warn(
238
+ `Box: maxWidth prop must be a number or percentage string (e.g., "50%"), received: ${value}`
239
+ );
232
240
  return {};
233
241
  }
234
242
  return {maxWidth: value};
235
243
  },
236
244
  minHeight: (value) => {
237
245
  if (!isValidWidthHeight(value)) {
238
- console.warn(`Box: minHeight prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
246
+ console.warn(
247
+ `Box: minHeight prop must be a number or percentage string (e.g., "50%"), received: ${value}`
248
+ );
239
249
  return {};
240
250
  }
241
251
  return {minHeight: value};
242
252
  },
243
253
  minWidth: (value) => {
244
254
  if (!isValidWidthHeight(value)) {
245
- console.warn(`Box: minWidth prop must be a number or percentage string (e.g., "50%"), received: ${value}`);
255
+ console.warn(
256
+ `Box: minWidth prop must be a number or percentage string (e.g., "50%"), received: ${value}`
257
+ );
246
258
  return {};
247
259
  }
248
260
  return {minWidth: value};
package/src/Button.tsx CHANGED
@@ -116,7 +116,6 @@ const ButtonComponent: FC<ButtonProps> = ({
116
116
  testID={testID}
117
117
  onPress={debounce(
118
118
  async () => {
119
- // TODO: Allow for a click outside of the confirmation modal to close it.
120
119
  await Unifier.utils.haptic();
121
120
  setLoading(true);
122
121
 
package/src/CheckBox.tsx CHANGED
@@ -32,7 +32,13 @@ export const CheckBox: FC<CheckBoxProps> = ({selected, size = "md", bgColor = "d
32
32
  }}
33
33
  >
34
34
  {selected ? (
35
- <FontAwesome6 color={theme.surface.base} name="check" size={px[size].icon} solid selectable={undefined}/>
35
+ <FontAwesome6
36
+ color={theme.surface.base}
37
+ name="check"
38
+ size={px[size].icon}
39
+ solid
40
+ selectable={undefined}
41
+ />
36
42
  ) : null}
37
43
  </View>
38
44
  );
package/src/Common.ts CHANGED
@@ -64,6 +64,11 @@ export interface AccordionProps extends InfoModalIconProps {
64
64
  * The title of the accordion.
65
65
  */
66
66
  title: string;
67
+
68
+ /**
69
+ * * Callback fired when the accordion is toggled.
70
+ * */
71
+ onToggle?: (isCollapse: boolean) => void;
67
72
  }
68
73
 
69
74
  export interface BaseProfile {
@@ -303,18 +308,6 @@ export type TextColor = keyof TextTheme;
303
308
  export type SurfaceColor = keyof SurfaceTheme;
304
309
  export type BorderColor = keyof BorderTheme;
305
310
  export type StatusColor = keyof StatusTheme;
306
- // TODO: Remove ButtonColor. Buttons no longer have colors, only types (called style in Figma)
307
- export type ButtonColor =
308
- | "blue"
309
- | "gray"
310
- | "red"
311
- // | "transparent"
312
- | "white"
313
- | "primary"
314
- | "secondary"
315
- | "accent"
316
- | "tertiary"
317
- | string;
318
311
 
319
312
  // TODO: we may want/need to expand icon color options from just text colors.
320
313
  export type IconColor = TextColor;
@@ -432,11 +425,11 @@ export const iconSizeToNumber = (size?: IconSize) => {
432
425
 
433
426
  export type TextSize = "sm" | "md" | "lg" | "xl" | "2xl";
434
427
 
435
- export type ValueMappingItem = {
428
+ export interface ValueMappingItem {
436
429
  value: number;
437
430
  label: string;
438
431
  size?: IconSize;
439
- };
432
+ }
440
433
 
441
434
  export type IconPrefix = "far" | "fas";
442
435
 
@@ -738,7 +731,7 @@ export interface HeadingProps {
738
731
  children?: React.ReactNode;
739
732
  color?: TextColor;
740
733
  overflow?: "normal" | "breakWord"; // default "breakWord"
741
- size?: "sm" | "md" | "lg" | "xl"; // default "sm"
734
+ size?: "sm" | "md" | "lg" | "xl" | "2xl"; // default "sm"
742
735
  truncate?: boolean; // default false
743
736
  testID?: string;
744
737
  }
@@ -770,11 +763,6 @@ export interface ImageProps {
770
763
  style?: any;
771
764
  }
772
765
 
773
- export interface SearchButtonProps {
774
- color: ButtonColor;
775
- onClick: () => void;
776
- }
777
-
778
766
  export interface BackButtonInterface {
779
767
  onBack: () => void;
780
768
  }
@@ -1786,6 +1774,11 @@ export interface ModalProps {
1786
1774
  * The content of the modal.
1787
1775
  */
1788
1776
  children?: React.ReactElement;
1777
+ /**
1778
+ * If true, the modal will be closed when the background is clicked.
1779
+ * @default false
1780
+ */
1781
+ persistOnBackgroundClick?: boolean;
1789
1782
  /**
1790
1783
  * If true, the primary button will be disabled.
1791
1784
  * @default false
@@ -2139,7 +2132,7 @@ export interface TableContextType {
2139
2132
  }
2140
2133
 
2141
2134
  export interface TableContextProviderProps extends TableContextType {
2142
- children: React.ReactElement;
2135
+ children: React.ReactNode;
2143
2136
  }
2144
2137
 
2145
2138
  export interface TextProps {
package/src/DataTable.tsx CHANGED
@@ -1,7 +1,6 @@
1
1
  import {FontAwesome6} from "@expo/vector-icons";
2
2
  import React, {FC, useCallback, useMemo, useRef, useState} from "react";
3
3
  import {NativeScrollEvent, NativeSyntheticEvent, Pressable, ScrollView, View} from "react-native";
4
- // @ts-ignore
5
4
  import Markdown from "react-native-markdown-display";
6
5
 
7
6
  import {Box} from "./Box";
@@ -18,9 +17,9 @@ import {Icon} from "./Icon";
18
17
  import {InfoModalIcon} from "./InfoModalIcon";
19
18
  import {Modal} from "./Modal";
20
19
  import {Pagination} from "./Pagination";
21
- import {TableTitle} from "./table/TableTitle";
22
20
  import {Text} from "./Text";
23
21
  import {useTheme} from "./Theme";
22
+ import {TableTitle} from "./table/TableTitle";
24
23
 
25
24
  // TODO: Add permanent horizontal scroll bar so users with only a mouse can scroll left/right
26
25
  // easily.