@terreno/ui 0.14.0 → 0.14.1

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 (79) hide show
  1. package/dist/ActionSheet.d.ts +1 -1
  2. package/dist/ActionSheet.js +2 -2
  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/MediaQuery.d.ts +4 -4
  13. package/dist/MediaQuery.js +8 -8
  14. package/dist/MediaQuery.js.map +1 -1
  15. package/dist/Page.d.ts +1 -0
  16. package/dist/Page.js +6 -2
  17. package/dist/Page.js.map +1 -1
  18. package/dist/PickerSelect.d.ts +1 -1
  19. package/dist/PickerSelect.js +2 -2
  20. package/dist/PickerSelect.js.map +1 -1
  21. package/dist/TapToEdit.d.ts +1 -1
  22. package/dist/TapToEdit.js +2 -3
  23. package/dist/TapToEdit.js.map +1 -1
  24. package/dist/ToastNotifications.js +2 -2
  25. package/dist/ToastNotifications.js.map +1 -1
  26. package/dist/Tooltip.d.ts +24 -1
  27. package/dist/Tooltip.js +2 -2
  28. package/dist/Tooltip.js.map +1 -1
  29. package/dist/Unifier.d.ts +1 -1
  30. package/dist/Unifier.js +14 -11
  31. package/dist/Unifier.js.map +1 -1
  32. package/dist/Utilities.d.ts +8 -8
  33. package/dist/Utilities.js +12 -14
  34. package/dist/Utilities.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/signUp/PasswordRequirements.js +3 -3
  39. package/dist/signUp/PasswordRequirements.js.map +1 -1
  40. package/dist/table/TableHeaderCell.js +1 -9
  41. package/dist/table/TableHeaderCell.js.map +1 -1
  42. package/dist/table/tableContext.d.ts +1 -1
  43. package/dist/table/tableContext.js +2 -2
  44. package/dist/table/tableContext.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/ActionSheet.tsx +2 -2
  47. package/src/Banner.test.tsx +71 -0
  48. package/src/Common.ts +10 -4
  49. package/src/ConsentFormScreen.test.tsx +22 -0
  50. package/src/ConsentFormScreen.tsx +9 -3
  51. package/src/DataTable.test.tsx +217 -0
  52. package/src/DateUtilities.tsx +37 -38
  53. package/src/HeightActionSheet.test.tsx +16 -0
  54. package/src/HeightField.test.tsx +106 -1
  55. package/src/MediaQuery.ts +8 -8
  56. package/src/MobileAddressAutoComplete.test.tsx +20 -1
  57. package/src/Page.test.tsx +28 -0
  58. package/src/Page.tsx +17 -2
  59. package/src/PickerSelect.tsx +3 -3
  60. package/src/TapToEdit.test.tsx +31 -0
  61. package/src/TapToEdit.tsx +2 -3
  62. package/src/ToastNotifications.test.tsx +738 -0
  63. package/src/ToastNotifications.tsx +2 -2
  64. package/src/Tooltip.test.tsx +587 -2
  65. package/src/Tooltip.tsx +2 -2
  66. package/src/Unifier.ts +14 -11
  67. package/src/Utilities.tsx +14 -16
  68. package/src/WebAddressAutocomplete.test.tsx +138 -0
  69. package/src/WebDropdownMenu.test.tsx +23 -0
  70. package/src/index.tsx +1 -1
  71. package/src/login/LoginScreen.test.tsx +23 -1
  72. package/src/signUp/PasswordRequirements.tsx +9 -6
  73. package/src/signUp/__snapshots__/PasswordRequirements.test.tsx.snap +50 -2
  74. package/src/signUp/__snapshots__/SignUpScreen.test.tsx.snap +25 -1
  75. package/src/table/TableHeaderCell.tsx +8 -11
  76. package/src/table/TableRow.test.tsx +31 -1
  77. package/src/table/__snapshots__/TableHeaderCell.test.tsx.snap +2 -0
  78. package/src/table/tableContext.tsx +2 -2
  79. package/src/useStoredState.test.tsx +47 -0
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 function mergeInlineStyles(
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 function isTestUser(profile?: BaseProfile) {
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 function bind<T>(
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 function formattedCountyCode(state: string, countyName: string): string {
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 function isAPIError(error: unknown): error is APIError {
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 function printAPIError(error: APIError, details = true): string {
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,143 @@ 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
+ });
316
454
  });
317
455
  });
@@ -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", () => {
package/src/index.tsx CHANGED
@@ -87,7 +87,7 @@ export * from "./TextArea";
87
87
  export * from "./TextField";
88
88
  export * from "./Theme";
89
89
  export * from "./Toast";
90
- export * from "./Tooltip";
90
+ export {Tooltip} from "./Tooltip";
91
91
  export * from "./table/Table";
92
92
  export * from "./table/Table";
93
93
  export * from "./table/TableBadge";
@@ -1,5 +1,5 @@
1
1
  import {describe, expect, it, mock} from "bun:test";
2
- import {fireEvent} from "@testing-library/react-native";
2
+ import {act, fireEvent, waitFor} from "@testing-library/react-native";
3
3
  import {renderWithTheme} from "../test-utils";
4
4
  import {LoginScreen} from "./LoginScreen";
5
5
 
@@ -145,4 +145,26 @@ describe("LoginScreen", () => {
145
145
  );
146
146
  expect(toJSON()).toMatchSnapshot();
147
147
  });
148
+
149
+ it("calls onSubmit with form values when submit button is pressed", async () => {
150
+ const onSubmit = mock(() => Promise.resolve());
151
+ const {getByTestId} = renderWithTheme(
152
+ <LoginScreen fields={defaultFields} onSubmit={onSubmit} />
153
+ );
154
+
155
+ await act(async () => {
156
+ fireEvent.changeText(getByTestId("login-screen-email-input"), "user@test.com");
157
+ });
158
+ await act(async () => {
159
+ fireEvent.changeText(getByTestId("login-screen-password-input"), "secret123");
160
+ });
161
+ await act(async () => {
162
+ fireEvent.press(getByTestId("login-screen-submit-button"));
163
+ });
164
+
165
+ await waitFor(() => {
166
+ expect(onSubmit).toHaveBeenCalledTimes(1);
167
+ });
168
+ expect(onSubmit.mock.calls[0][0]).toEqual({email: "user@test.com", password: "secret123"});
169
+ });
148
170
  });
@@ -1,6 +1,6 @@
1
1
  import type {FC} from "react";
2
- import {View} from "react-native";
3
2
 
3
+ import {Box} from "../Box";
4
4
  import {Icon} from "../Icon";
5
5
  import {Text} from "../Text";
6
6
  import type {PasswordRequirement} from "./signUpTypes";
@@ -23,13 +23,16 @@ export const PasswordRequirements: FC<PasswordRequirementsProps> = ({
23
23
  testID = "password-requirements",
24
24
  }) => {
25
25
  return (
26
- <View testID={testID}>
26
+ <Box testID={testID}>
27
27
  {requirements.map((req) => {
28
28
  const isMet = password.length > 0 && req.validate(password);
29
29
  return (
30
- <View
30
+ <Box
31
+ alignItems="center"
32
+ direction="row"
33
+ gap={2}
31
34
  key={req.key}
32
- style={{alignItems: "center", flexDirection: "row", gap: 8, marginBottom: 4}}
35
+ marginBottom={1}
33
36
  testID={`${testID}-${req.key}`}
34
37
  >
35
38
  <Icon
@@ -41,9 +44,9 @@ export const PasswordRequirements: FC<PasswordRequirementsProps> = ({
41
44
  <Text color={isMet ? "success" : "secondaryLight"} size="sm">
42
45
  {req.label}
43
46
  </Text>
44
- </View>
47
+ </Box>
45
48
  );
46
49
  })}
47
- </View>
50
+ </Box>
48
51
  );
49
52
  };
@@ -34,11 +34,15 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
34
34
  },
35
35
  ],
36
36
  "props": {
37
+ "onPointerEnter": [Function: AsyncFunction],
38
+ "onPointerLeave": [Function: AsyncFunction],
37
39
  "style": {
38
40
  "alignItems": "center",
41
+ "display": "flex",
39
42
  "flexDirection": "row",
40
43
  "gap": 8,
41
44
  "marginBottom": 4,
45
+ "testID": "password-requirements-minLength",
42
46
  },
43
47
  "testID": "password-requirements-minLength",
44
48
  },
@@ -74,11 +78,15 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
74
78
  },
75
79
  ],
76
80
  "props": {
81
+ "onPointerEnter": [Function: AsyncFunction],
82
+ "onPointerLeave": [Function: AsyncFunction],
77
83
  "style": {
78
84
  "alignItems": "center",
85
+ "display": "flex",
79
86
  "flexDirection": "row",
80
87
  "gap": 8,
81
88
  "marginBottom": 4,
89
+ "testID": "password-requirements-uppercase",
82
90
  },
83
91
  "testID": "password-requirements-uppercase",
84
92
  },
@@ -114,11 +122,15 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
114
122
  },
115
123
  ],
116
124
  "props": {
125
+ "onPointerEnter": [Function: AsyncFunction],
126
+ "onPointerLeave": [Function: AsyncFunction],
117
127
  "style": {
118
128
  "alignItems": "center",
129
+ "display": "flex",
119
130
  "flexDirection": "row",
120
131
  "gap": 8,
121
132
  "marginBottom": 4,
133
+ "testID": "password-requirements-lowercase",
122
134
  },
123
135
  "testID": "password-requirements-lowercase",
124
136
  },
@@ -154,11 +166,15 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
154
166
  },
155
167
  ],
156
168
  "props": {
169
+ "onPointerEnter": [Function: AsyncFunction],
170
+ "onPointerLeave": [Function: AsyncFunction],
157
171
  "style": {
158
172
  "alignItems": "center",
173
+ "display": "flex",
159
174
  "flexDirection": "row",
160
175
  "gap": 8,
161
176
  "marginBottom": 4,
177
+ "testID": "password-requirements-number",
162
178
  },
163
179
  "testID": "password-requirements-number",
164
180
  },
@@ -194,11 +210,15 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
194
210
  },
195
211
  ],
196
212
  "props": {
213
+ "onPointerEnter": [Function: AsyncFunction],
214
+ "onPointerLeave": [Function: AsyncFunction],
197
215
  "style": {
198
216
  "alignItems": "center",
217
+ "display": "flex",
199
218
  "flexDirection": "row",
200
219
  "gap": 8,
201
220
  "marginBottom": 4,
221
+ "testID": "password-requirements-special",
202
222
  },
203
223
  "testID": "password-requirements-special",
204
224
  },
@@ -206,7 +226,11 @@ exports[`PasswordRequirements renders correctly with empty password 1`] = `
206
226
  },
207
227
  ],
208
228
  "props": {
209
- "style": undefined,
229
+ "onPointerEnter": [Function: AsyncFunction],
230
+ "onPointerLeave": [Function: AsyncFunction],
231
+ "style": {
232
+ "testID": "password-requirements",
233
+ },
210
234
  "testID": "password-requirements",
211
235
  },
212
236
  "type": "View",
@@ -247,11 +271,15 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
247
271
  },
248
272
  ],
249
273
  "props": {
274
+ "onPointerEnter": [Function: AsyncFunction],
275
+ "onPointerLeave": [Function: AsyncFunction],
250
276
  "style": {
251
277
  "alignItems": "center",
278
+ "display": "flex",
252
279
  "flexDirection": "row",
253
280
  "gap": 8,
254
281
  "marginBottom": 4,
282
+ "testID": "password-requirements-minLength",
255
283
  },
256
284
  "testID": "password-requirements-minLength",
257
285
  },
@@ -287,11 +315,15 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
287
315
  },
288
316
  ],
289
317
  "props": {
318
+ "onPointerEnter": [Function: AsyncFunction],
319
+ "onPointerLeave": [Function: AsyncFunction],
290
320
  "style": {
291
321
  "alignItems": "center",
322
+ "display": "flex",
292
323
  "flexDirection": "row",
293
324
  "gap": 8,
294
325
  "marginBottom": 4,
326
+ "testID": "password-requirements-uppercase",
295
327
  },
296
328
  "testID": "password-requirements-uppercase",
297
329
  },
@@ -327,11 +359,15 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
327
359
  },
328
360
  ],
329
361
  "props": {
362
+ "onPointerEnter": [Function: AsyncFunction],
363
+ "onPointerLeave": [Function: AsyncFunction],
330
364
  "style": {
331
365
  "alignItems": "center",
366
+ "display": "flex",
332
367
  "flexDirection": "row",
333
368
  "gap": 8,
334
369
  "marginBottom": 4,
370
+ "testID": "password-requirements-lowercase",
335
371
  },
336
372
  "testID": "password-requirements-lowercase",
337
373
  },
@@ -367,11 +403,15 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
367
403
  },
368
404
  ],
369
405
  "props": {
406
+ "onPointerEnter": [Function: AsyncFunction],
407
+ "onPointerLeave": [Function: AsyncFunction],
370
408
  "style": {
371
409
  "alignItems": "center",
410
+ "display": "flex",
372
411
  "flexDirection": "row",
373
412
  "gap": 8,
374
413
  "marginBottom": 4,
414
+ "testID": "password-requirements-number",
375
415
  },
376
416
  "testID": "password-requirements-number",
377
417
  },
@@ -407,11 +447,15 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
407
447
  },
408
448
  ],
409
449
  "props": {
450
+ "onPointerEnter": [Function: AsyncFunction],
451
+ "onPointerLeave": [Function: AsyncFunction],
410
452
  "style": {
411
453
  "alignItems": "center",
454
+ "display": "flex",
412
455
  "flexDirection": "row",
413
456
  "gap": 8,
414
457
  "marginBottom": 4,
458
+ "testID": "password-requirements-special",
415
459
  },
416
460
  "testID": "password-requirements-special",
417
461
  },
@@ -419,7 +463,11 @@ exports[`PasswordRequirements renders correctly with a strong password 1`] = `
419
463
  },
420
464
  ],
421
465
  "props": {
422
- "style": undefined,
466
+ "onPointerEnter": [Function: AsyncFunction],
467
+ "onPointerLeave": [Function: AsyncFunction],
468
+ "style": {
469
+ "testID": "password-requirements",
470
+ },
423
471
  "testID": "password-requirements",
424
472
  },
425
473
  "type": "View",
@@ -397,11 +397,15 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
397
397
  },
398
398
  ],
399
399
  "props": {
400
+ "onPointerEnter": [Function: AsyncFunction],
401
+ "onPointerLeave": [Function: AsyncFunction],
400
402
  "style": {
401
403
  "alignItems": "center",
404
+ "display": "flex",
402
405
  "flexDirection": "row",
403
406
  "gap": 8,
404
407
  "marginBottom": 4,
408
+ "testID": "signup-screen-password-requirements-minLength",
405
409
  },
406
410
  "testID": "signup-screen-password-requirements-minLength",
407
411
  },
@@ -437,11 +441,15 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
437
441
  },
438
442
  ],
439
443
  "props": {
444
+ "onPointerEnter": [Function: AsyncFunction],
445
+ "onPointerLeave": [Function: AsyncFunction],
440
446
  "style": {
441
447
  "alignItems": "center",
448
+ "display": "flex",
442
449
  "flexDirection": "row",
443
450
  "gap": 8,
444
451
  "marginBottom": 4,
452
+ "testID": "signup-screen-password-requirements-uppercase",
445
453
  },
446
454
  "testID": "signup-screen-password-requirements-uppercase",
447
455
  },
@@ -477,11 +485,15 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
477
485
  },
478
486
  ],
479
487
  "props": {
488
+ "onPointerEnter": [Function: AsyncFunction],
489
+ "onPointerLeave": [Function: AsyncFunction],
480
490
  "style": {
481
491
  "alignItems": "center",
492
+ "display": "flex",
482
493
  "flexDirection": "row",
483
494
  "gap": 8,
484
495
  "marginBottom": 4,
496
+ "testID": "signup-screen-password-requirements-lowercase",
485
497
  },
486
498
  "testID": "signup-screen-password-requirements-lowercase",
487
499
  },
@@ -517,11 +529,15 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
517
529
  },
518
530
  ],
519
531
  "props": {
532
+ "onPointerEnter": [Function: AsyncFunction],
533
+ "onPointerLeave": [Function: AsyncFunction],
520
534
  "style": {
521
535
  "alignItems": "center",
536
+ "display": "flex",
522
537
  "flexDirection": "row",
523
538
  "gap": 8,
524
539
  "marginBottom": 4,
540
+ "testID": "signup-screen-password-requirements-number",
525
541
  },
526
542
  "testID": "signup-screen-password-requirements-number",
527
543
  },
@@ -557,11 +573,15 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
557
573
  },
558
574
  ],
559
575
  "props": {
576
+ "onPointerEnter": [Function: AsyncFunction],
577
+ "onPointerLeave": [Function: AsyncFunction],
560
578
  "style": {
561
579
  "alignItems": "center",
580
+ "display": "flex",
562
581
  "flexDirection": "row",
563
582
  "gap": 8,
564
583
  "marginBottom": 4,
584
+ "testID": "signup-screen-password-requirements-special",
565
585
  },
566
586
  "testID": "signup-screen-password-requirements-special",
567
587
  },
@@ -569,7 +589,11 @@ exports[`SignUpScreen renders correctly with all props 1`] = `
569
589
  },
570
590
  ],
571
591
  "props": {
572
- "style": undefined,
592
+ "onPointerEnter": [Function: AsyncFunction],
593
+ "onPointerLeave": [Function: AsyncFunction],
594
+ "style": {
595
+ "testID": "signup-screen-password-requirements",
596
+ },
573
597
  "testID": "signup-screen-password-requirements",
574
598
  },
575
599
  "type": "View",
@@ -1,7 +1,6 @@
1
1
  // TableHeaderCell.tsx
2
2
  import {FontAwesome6} from "@expo/vector-icons";
3
3
  import {type ReactElement, useCallback} from "react";
4
- import {View} from "react-native";
5
4
 
6
5
  import {Box} from "../Box";
7
6
  import type {AlignItems, TableHeaderCellProps} from "../Common";
@@ -69,15 +68,13 @@ export const TableHeaderCell = ({
69
68
  {Boolean(sort) && (
70
69
  <Box alignSelf="end" paddingX={2}>
71
70
  {/* Make it look like an IconButton, but we can't nest buttons and the whole row is clickable. */}
72
- <View
73
- style={{
74
- alignItems: "center",
75
- backgroundColor: theme.surface.primary,
76
- borderRadius: theme.radius.rounded,
77
- height: 16,
78
- justifyContent: "center",
79
- width: 16,
80
- }}
71
+ <Box
72
+ alignItems="center"
73
+ color="primary"
74
+ height={16}
75
+ justifyContent="center"
76
+ rounding="rounded"
77
+ width={16}
81
78
  >
82
79
  <FontAwesome6
83
80
  color={theme.text.inverted}
@@ -86,7 +83,7 @@ export const TableHeaderCell = ({
86
83
  size={10}
87
84
  solid
88
85
  />
89
- </View>
86
+ </Box>
90
87
  </Box>
91
88
  )}
92
89
  </Box>