@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
package/src/Page.test.tsx CHANGED
@@ -2,6 +2,7 @@ import {afterAll, describe, expect, it, mock} from "bun:test";
2
2
  import {act, fireEvent, waitFor} from "@testing-library/react-native";
3
3
  import React, {type ReactNode} from "react";
4
4
  import {Pressable, Text as RNText} from "react-native";
5
+ import {SafeAreaView} from "react-native-safe-area-context";
5
6
 
6
7
  // Override the IconButton mock so the inline onClick arrows fire when pressed.
7
8
  mock.module("./IconButton", () => ({
@@ -273,6 +274,33 @@ describe("Page", () => {
273
274
  expect(routerBack).toHaveBeenCalled();
274
275
  });
275
276
 
277
+ it("wraps content in SafeAreaView when safeArea is true", () => {
278
+ const {UNSAFE_root} = renderWithTheme(
279
+ <Page navigation={mockNavigation} safeArea>
280
+ <Text>Content</Text>
281
+ </Page>
282
+ );
283
+ expect(UNSAFE_root.findAllByType(SafeAreaView).length).toBeGreaterThan(0);
284
+ });
285
+
286
+ it("does not wrap content in SafeAreaView when safeArea is omitted", () => {
287
+ const {UNSAFE_root} = renderWithTheme(
288
+ <Page navigation={mockNavigation}>
289
+ <Text>Content</Text>
290
+ </Page>
291
+ );
292
+ expect(UNSAFE_root.findAllByType(SafeAreaView)).toHaveLength(0);
293
+ });
294
+
295
+ it("does not wrap content in SafeAreaView when safeArea is false", () => {
296
+ const {UNSAFE_root} = renderWithTheme(
297
+ <Page navigation={mockNavigation} safeArea={false}>
298
+ <Text>Content</Text>
299
+ </Page>
300
+ );
301
+ expect(UNSAFE_root.findAllByType(SafeAreaView)).toHaveLength(0);
302
+ });
303
+
276
304
  it("safely handles a missing rightButtonOnClick callback", async () => {
277
305
  const {getByText} = renderWithTheme(
278
306
  <Page navigation={mockNavigation} rightButton="Go" title="Page">
package/src/Page.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import {router} from "expo-router";
2
2
  import React from "react";
3
+ import {SafeAreaView} from "react-native-safe-area-context";
3
4
 
4
5
  import {Box} from "./Box";
5
6
  import {Button} from "./Button";
@@ -58,9 +59,9 @@ export class Page extends React.Component<PageProps, {}> {
58
59
  );
59
60
  }
60
61
 
61
- render() {
62
+ renderBody() {
62
63
  return (
63
- <ErrorBoundary onError={this.props.onError}>
64
+ <>
64
65
  <Box
65
66
  alignSelf="center"
66
67
  avoidKeyboard
@@ -112,6 +113,20 @@ export class Page extends React.Component<PageProps, {}> {
112
113
  {this.props.footer}
113
114
  </Box>
114
115
  )}
116
+ </>
117
+ );
118
+ }
119
+
120
+ render() {
121
+ return (
122
+ <ErrorBoundary onError={this.props.onError}>
123
+ {this.props.safeArea ? (
124
+ <SafeAreaView edges={["top", "bottom"]} style={{flex: 1}}>
125
+ {this.renderBody()}
126
+ </SafeAreaView>
127
+ ) : (
128
+ this.renderBody()
129
+ )}
115
130
  </ErrorBoundary>
116
131
  );
117
132
  }
@@ -1,3 +1,4 @@
1
+ // biome-ignore-all lint/suspicious/noExplicitAny: test mock typing
1
2
  import {describe, expect, it, mock} from "bun:test";
2
3
  import {act, fireEvent} from "@testing-library/react-native";
3
4
 
@@ -160,6 +161,248 @@ describe("PickerSelect", () => {
160
161
  expect(toJSON()).toBeTruthy();
161
162
  });
162
163
 
164
+ describe("web rendering (Platform.OS === 'web')", () => {
165
+ const PlatformModule = require("react-native").Platform;
166
+ let savedOS: any;
167
+
168
+ let hadDocument = false;
169
+ let savedDocument: any;
170
+
171
+ const ensureDocument = () => {
172
+ hadDocument = "document" in globalThis;
173
+ savedDocument = (globalThis as any).document;
174
+ if (typeof (globalThis as any).HTMLElement === "undefined") {
175
+ (globalThis as any).HTMLElement = class HTMLElement {};
176
+ }
177
+ const el = new (globalThis as any).HTMLElement();
178
+ el.blur = () => {};
179
+ (globalThis as any).document = {activeElement: el};
180
+ };
181
+
182
+ const restoreDocument = () => {
183
+ if (hadDocument) {
184
+ (globalThis as any).document = savedDocument;
185
+ } else {
186
+ delete (globalThis as any).document;
187
+ }
188
+ };
189
+
190
+ it("renders web dropdown with display label", () => {
191
+ ensureDocument();
192
+ savedOS = PlatformModule.OS;
193
+ try {
194
+ PlatformModule.OS = "web";
195
+ const {getByTestId} = renderWithTheme(<RNPickerSelect {...defaultProps} value="2" />);
196
+ expect(getByTestId("text_input")).toBeTruthy();
197
+ } finally {
198
+ PlatformModule.OS = savedOS;
199
+ restoreDocument();
200
+ }
201
+ });
202
+
203
+ it("renders web dropdown and opens on press", async () => {
204
+ ensureDocument();
205
+ savedOS = PlatformModule.OS;
206
+ try {
207
+ PlatformModule.OS = "web";
208
+ const onOpen = mock(() => {});
209
+ const {getByTestId} = renderWithTheme(
210
+ <RNPickerSelect {...defaultProps} onOpen={onOpen} value="1" />
211
+ );
212
+ await act(async () => {
213
+ fireEvent.press(getByTestId("web_picker"));
214
+ });
215
+ expect(onOpen).toHaveBeenCalled();
216
+ } finally {
217
+ PlatformModule.OS = savedOS;
218
+ restoreDocument();
219
+ }
220
+ });
221
+
222
+ it("does not open web menu when disabled", async () => {
223
+ ensureDocument();
224
+ savedOS = PlatformModule.OS;
225
+ try {
226
+ PlatformModule.OS = "web";
227
+ const onOpen = mock(() => {});
228
+ const {getByTestId} = renderWithTheme(
229
+ <RNPickerSelect {...defaultProps} disabled onOpen={onOpen} />
230
+ );
231
+ await act(async () => {
232
+ fireEvent.press(getByTestId("web_picker"));
233
+ });
234
+ expect(onOpen).not.toHaveBeenCalled();
235
+ } finally {
236
+ PlatformModule.OS = savedOS;
237
+ restoreDocument();
238
+ }
239
+ });
240
+
241
+ it("calls onClose when closing web menu", async () => {
242
+ ensureDocument();
243
+ savedOS = PlatformModule.OS;
244
+ try {
245
+ PlatformModule.OS = "web";
246
+ const onClose = mock(() => {});
247
+ const onOpen = mock(() => {});
248
+ const {getByTestId} = renderWithTheme(
249
+ <RNPickerSelect {...defaultProps} onClose={onClose} onOpen={onOpen} value="1" />
250
+ );
251
+ await act(async () => {
252
+ fireEvent.press(getByTestId("web_picker"));
253
+ });
254
+ expect(onOpen).toHaveBeenCalled();
255
+ await act(async () => {
256
+ fireEvent.press(getByTestId("web_dropdown_backdrop"));
257
+ });
258
+ expect(onClose).toHaveBeenCalled();
259
+ } finally {
260
+ PlatformModule.OS = savedOS;
261
+ restoreDocument();
262
+ }
263
+ });
264
+
265
+ it("renders disabled web dropdown with correct styling", () => {
266
+ ensureDocument();
267
+ savedOS = PlatformModule.OS;
268
+ try {
269
+ PlatformModule.OS = "web";
270
+ const {getByTestId} = renderWithTheme(<RNPickerSelect {...defaultProps} disabled />);
271
+ expect(getByTestId("web_picker")).toBeTruthy();
272
+ } finally {
273
+ PlatformModule.OS = savedOS;
274
+ restoreDocument();
275
+ }
276
+ });
277
+
278
+ it("renders web dropdown with inputLabel when available", () => {
279
+ ensureDocument();
280
+ savedOS = PlatformModule.OS;
281
+ try {
282
+ PlatformModule.OS = "web";
283
+ const items = [
284
+ {inputLabel: "Opt 1 short", label: "Option 1 long", value: "1"},
285
+ {label: "Option 2", value: "2"},
286
+ ];
287
+ const {getByTestId} = renderWithTheme(
288
+ <RNPickerSelect {...defaultProps} items={items} value="1" />
289
+ );
290
+ expect(getByTestId("text_input")).toBeTruthy();
291
+ } finally {
292
+ PlatformModule.OS = savedOS;
293
+ restoreDocument();
294
+ }
295
+ });
296
+
297
+ it("renders web dropdown with no placeholder (empty object)", () => {
298
+ ensureDocument();
299
+ savedOS = PlatformModule.OS;
300
+ try {
301
+ PlatformModule.OS = "web";
302
+ const {getByTestId} = renderWithTheme(
303
+ <RNPickerSelect {...defaultProps} placeholder={{}} value="1" />
304
+ );
305
+ expect(getByTestId("web_picker")).toBeTruthy();
306
+ } finally {
307
+ PlatformModule.OS = savedOS;
308
+ restoreDocument();
309
+ }
310
+ });
311
+ });
312
+
313
+ describe("android rendering", () => {
314
+ const PlatformModule = require("react-native").Platform;
315
+ let savedOS: any;
316
+
317
+ it("renders android headless when useNativeAndroidPickerStyle is false", () => {
318
+ savedOS = PlatformModule.OS;
319
+ try {
320
+ PlatformModule.OS = "android";
321
+ const {getByTestId} = renderWithTheme(
322
+ <RNPickerSelect {...defaultProps} useNativeAndroidPickerStyle={false} value="1" />
323
+ );
324
+ expect(getByTestId("android_touchable_wrapper")).toBeTruthy();
325
+ } finally {
326
+ PlatformModule.OS = savedOS;
327
+ }
328
+ });
329
+
330
+ it("renders android headless with fixAndroidTouchableBug", () => {
331
+ savedOS = PlatformModule.OS;
332
+ try {
333
+ PlatformModule.OS = "android";
334
+ const {getByTestId} = renderWithTheme(
335
+ <RNPickerSelect
336
+ {...defaultProps}
337
+ fixAndroidTouchableBug
338
+ useNativeAndroidPickerStyle={false}
339
+ value="1"
340
+ />
341
+ );
342
+ expect(getByTestId("android_touchable_wrapper")).toBeTruthy();
343
+ } finally {
344
+ PlatformModule.OS = savedOS;
345
+ }
346
+ });
347
+
348
+ it("renders android headless with children", () => {
349
+ savedOS = PlatformModule.OS;
350
+ try {
351
+ PlatformModule.OS = "android";
352
+ const {getByTestId} = renderWithTheme(
353
+ <RNPickerSelect {...defaultProps} value="1">
354
+ <>Custom child</>
355
+ </RNPickerSelect>
356
+ );
357
+ expect(getByTestId("android_touchable_wrapper")).toBeTruthy();
358
+ } finally {
359
+ PlatformModule.OS = savedOS;
360
+ }
361
+ });
362
+
363
+ it("renders native android picker style", () => {
364
+ savedOS = PlatformModule.OS;
365
+ try {
366
+ PlatformModule.OS = "android";
367
+ const {getByTestId} = renderWithTheme(<RNPickerSelect {...defaultProps} value="1" />);
368
+ expect(getByTestId("android_picker")).toBeTruthy();
369
+ } finally {
370
+ PlatformModule.OS = savedOS;
371
+ }
372
+ });
373
+
374
+ it("renders native android picker disabled", () => {
375
+ savedOS = PlatformModule.OS;
376
+ try {
377
+ PlatformModule.OS = "android";
378
+ const {getByTestId} = renderWithTheme(
379
+ <RNPickerSelect {...defaultProps} disabled value="1" />
380
+ );
381
+ expect(getByTestId("android_picker")).toBeTruthy();
382
+ } finally {
383
+ PlatformModule.OS = savedOS;
384
+ }
385
+ });
386
+
387
+ it("calls onValueChange on android native picker change", async () => {
388
+ savedOS = PlatformModule.OS;
389
+ try {
390
+ PlatformModule.OS = "android";
391
+ const mockOnValueChange = mock(() => {});
392
+ const {getByTestId} = renderWithTheme(
393
+ <RNPickerSelect {...defaultProps} onValueChange={mockOnValueChange} value="1" />
394
+ );
395
+ const picker = getByTestId("android_picker");
396
+ await act(async () => {
397
+ picker.props.onValueChange?.("2", 1);
398
+ });
399
+ expect(mockOnValueChange).toHaveBeenCalledWith("2", 1);
400
+ } finally {
401
+ PlatformModule.OS = savedOS;
402
+ }
403
+ });
404
+ });
405
+
163
406
  describe("interactions on iOS", () => {
164
407
  it("fires onOpen when the iOS wrapper is pressed and onClose when Done is pressed", async () => {
165
408
  const onOpen = mock(() => {});
@@ -114,7 +114,7 @@ export interface RNPickerSelectProps {
114
114
  InputAccessoryView?: ComponentType<{testID?: string}>;
115
115
  }
116
116
 
117
- export function RNPickerSelect({
117
+ export const RNPickerSelect = ({
118
118
  onValueChange,
119
119
  value,
120
120
  items,
@@ -136,7 +136,7 @@ export function RNPickerSelect({
136
136
  touchableWrapperProps,
137
137
 
138
138
  InputAccessoryView,
139
- }: RNPickerSelectProps) {
139
+ }: RNPickerSelectProps) => {
140
140
  const [showPicker, setShowPicker] = useState<boolean>(false);
141
141
  const [animationType, setAnimationType] = useState<ModalProps["animationType"]>(undefined);
142
142
  const [orientation, setOrientation] = useState<"portrait" | "landscape">("portrait");
@@ -683,4 +683,4 @@ export function RNPickerSelect({
683
683
  };
684
684
 
685
685
  return render();
686
- }
686
+ };