ferns-ui 1.13.0 → 1.15.0

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 (131) hide show
  1. package/dist/ActionSheet.js +14 -11
  2. package/dist/ActionSheet.js.map +1 -1
  3. package/dist/AddressField.js +1 -1
  4. package/dist/AddressField.js.map +1 -1
  5. package/dist/Badge.js +1 -1
  6. package/dist/Badge.js.map +1 -1
  7. package/dist/Banner.js +1 -1
  8. package/dist/Banner.js.map +1 -1
  9. package/dist/Box.js +3 -3
  10. package/dist/Box.js.map +1 -1
  11. package/dist/Box.test.js +36 -36
  12. package/dist/Box.test.js.map +1 -1
  13. package/dist/CheckBox.js.map +1 -1
  14. package/dist/Common.d.ts +6 -1
  15. package/dist/DataTable.js +2 -3
  16. package/dist/DataTable.js.map +1 -1
  17. package/dist/DateTimeField.js +22 -22
  18. package/dist/DateTimeField.js.map +1 -1
  19. package/dist/FernsProvider.js +1 -1
  20. package/dist/FernsProvider.js.map +1 -1
  21. package/dist/Heading.js +1 -1
  22. package/dist/Heading.js.map +1 -1
  23. package/dist/Hyperlink.js +1 -1
  24. package/dist/Hyperlink.js.map +1 -1
  25. package/dist/IconButton.js +1 -1
  26. package/dist/IconButton.js.map +1 -1
  27. package/dist/Image.js.map +1 -1
  28. package/dist/MobileAddressAutoComplete.js +1 -1
  29. package/dist/MobileAddressAutoComplete.js.map +1 -1
  30. package/dist/Modal.d.ts +1 -1
  31. package/dist/Modal.js +29 -16
  32. package/dist/Modal.js.map +1 -1
  33. package/dist/NumberField.js +10 -4
  34. package/dist/NumberField.js.map +1 -1
  35. package/dist/NumberPickerActionSheet.d.ts +1 -3
  36. package/dist/NumberPickerActionSheet.js +0 -3
  37. package/dist/NumberPickerActionSheet.js.map +1 -1
  38. package/dist/Page.js +1 -1
  39. package/dist/Page.js.map +1 -1
  40. package/dist/Pagination.js +2 -2
  41. package/dist/Pagination.js.map +1 -1
  42. package/dist/Permissions.d.ts +1 -1
  43. package/dist/Permissions.js +2 -2
  44. package/dist/Permissions.js.map +1 -1
  45. package/dist/PickerSelect.js +1 -1
  46. package/dist/PickerSelect.js.map +1 -1
  47. package/dist/SectionDivider.js +1 -1
  48. package/dist/SectionDivider.js.map +1 -1
  49. package/dist/SegmentedControl.js.map +1 -1
  50. package/dist/Signature.native.js +2 -2
  51. package/dist/Signature.native.js.map +1 -1
  52. package/dist/SignatureField.js +2 -2
  53. package/dist/SignatureField.js.map +1 -1
  54. package/dist/Slider.js +3 -3
  55. package/dist/Slider.js.map +1 -1
  56. package/dist/SplitPage.js +7 -7
  57. package/dist/SplitPage.js.map +1 -1
  58. package/dist/SplitPage.native.js +4 -6
  59. package/dist/SplitPage.native.js.map +1 -1
  60. package/dist/TapToEdit.js +3 -3
  61. package/dist/TapToEdit.js.map +1 -1
  62. package/dist/Text.js +1 -1
  63. package/dist/Text.js.map +1 -1
  64. package/dist/TextArea.test.js.map +1 -1
  65. package/dist/TextField.test.js +3 -3
  66. package/dist/TextField.test.js.map +1 -1
  67. package/dist/TextFieldNumberActionSheet.d.ts +2 -4
  68. package/dist/TextFieldNumberActionSheet.js +1 -4
  69. package/dist/TextFieldNumberActionSheet.js.map +1 -1
  70. package/dist/Tooltip.js +37 -19
  71. package/dist/Tooltip.js.map +1 -1
  72. package/dist/Unifier.d.ts +0 -1
  73. package/dist/Unifier.js.map +1 -1
  74. package/dist/Utilities.d.ts +1 -1
  75. package/dist/Utilities.js +2 -3
  76. package/dist/Utilities.js.map +1 -1
  77. package/dist/WebAddressAutocomplete.js +2 -1
  78. package/dist/WebAddressAutocomplete.js.map +1 -1
  79. package/dist/index.d.ts +10 -11
  80. package/dist/index.js +10 -10
  81. package/dist/index.js.map +1 -1
  82. package/dist/table/Table.js +14 -15
  83. package/dist/table/Table.js.map +1 -1
  84. package/dist/table/TableHeaderCell.js +2 -2
  85. package/dist/table/TableHeaderCell.js.map +1 -1
  86. package/dist/useStoredState.js +4 -2
  87. package/dist/useStoredState.js.map +1 -1
  88. package/package.json +5 -19
  89. package/src/ActionSheet.tsx +26 -22
  90. package/src/AddressField.tsx +1 -1
  91. package/src/Badge.tsx +1 -1
  92. package/src/Banner.tsx +1 -1
  93. package/src/Box.test.tsx +71 -70
  94. package/src/Box.tsx +21 -9
  95. package/src/CheckBox.tsx +7 -1
  96. package/src/Common.ts +6 -1
  97. package/src/DataTable.tsx +2 -5
  98. package/src/DateTimeField.tsx +22 -22
  99. package/src/FernsProvider.tsx +1 -4
  100. package/src/Heading.tsx +1 -1
  101. package/src/Hyperlink.tsx +1 -1
  102. package/src/IconButton.tsx +2 -2
  103. package/src/Image.tsx +1 -0
  104. package/src/MobileAddressAutoComplete.tsx +1 -1
  105. package/src/Modal.tsx +41 -20
  106. package/src/NumberField.tsx +10 -4
  107. package/src/NumberPickerActionSheet.tsx +1 -5
  108. package/src/Page.tsx +1 -1
  109. package/src/Pagination.tsx +2 -11
  110. package/src/Permissions.ts +2 -2
  111. package/src/PickerSelect.tsx +1 -1
  112. package/src/SectionDivider.tsx +1 -1
  113. package/src/SegmentedControl.tsx +3 -1
  114. package/src/Signature.native.tsx +2 -2
  115. package/src/SignatureField.tsx +2 -2
  116. package/src/Slider.tsx +10 -17
  117. package/src/SplitPage.native.tsx +2 -4
  118. package/src/SplitPage.tsx +4 -4
  119. package/src/TapToEdit.tsx +3 -7
  120. package/src/Text.tsx +1 -1
  121. package/src/TextArea.test.tsx +27 -43
  122. package/src/TextField.test.tsx +3 -4
  123. package/src/TextFieldNumberActionSheet.tsx +3 -7
  124. package/src/Tooltip.tsx +44 -22
  125. package/src/Unifier.ts +1 -3
  126. package/src/Utilities.tsx +3 -4
  127. package/src/WebAddressAutocomplete.tsx +1 -1
  128. package/src/index.tsx +11 -11
  129. package/src/table/Table.tsx +34 -36
  130. package/src/table/TableHeaderCell.tsx +2 -2
  131. package/src/useStoredState.ts +13 -11
package/src/Text.tsx CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  useFonts,
9
9
  } from "@expo-google-fonts/nunito";
10
10
  import React from "react";
11
- import {Platform, Text as NativeText, TextStyle} from "react-native";
11
+ import {Text as NativeText, Platform, TextStyle} from "react-native";
12
12
 
13
13
  import {TextProps} from "./Common";
14
14
  import {Hyperlink} from "./Hyperlink";
@@ -20,7 +20,7 @@ describe("TextArea", () => {
20
20
  const {getByDisplayValue} = renderWithTheme(
21
21
  <TextArea value="test content" onChange={mockOnChange} />
22
22
  );
23
-
23
+
24
24
  const input = getByDisplayValue("test content");
25
25
  expect(input.props.multiline).toBe(true);
26
26
  expect(input.props.value).toBe("test content");
@@ -30,7 +30,7 @@ describe("TextArea", () => {
30
30
  const {getByText} = renderWithTheme(
31
31
  <TextArea title="Description" value="" onChange={mockOnChange} />
32
32
  );
33
-
33
+
34
34
  expect(getByText("Description")).toBeTruthy();
35
35
  });
36
36
 
@@ -38,7 +38,7 @@ describe("TextArea", () => {
38
38
  const {getByPlaceholderText} = renderWithTheme(
39
39
  <TextArea placeholder="Enter description" value="" onChange={mockOnChange} />
40
40
  );
41
-
41
+
42
42
  expect(getByPlaceholderText("Enter description")).toBeTruthy();
43
43
  });
44
44
 
@@ -46,7 +46,7 @@ describe("TextArea", () => {
46
46
  const {getByText} = renderWithTheme(
47
47
  <TextArea helperText="Maximum 500 characters" value="" onChange={mockOnChange} />
48
48
  );
49
-
49
+
50
50
  expect(getByText("Maximum 500 characters")).toBeTruthy();
51
51
  });
52
52
 
@@ -54,7 +54,7 @@ describe("TextArea", () => {
54
54
  const {getByText} = renderWithTheme(
55
55
  <TextArea errorText="This field is required" value="" onChange={mockOnChange} />
56
56
  );
57
-
57
+
58
58
  expect(getByText("This field is required")).toBeTruthy();
59
59
  });
60
60
 
@@ -62,7 +62,7 @@ describe("TextArea", () => {
62
62
  const {getByDisplayValue} = renderWithTheme(
63
63
  <TextArea grow value="" onChange={mockOnChange} />
64
64
  );
65
-
65
+
66
66
  const input = getByDisplayValue("");
67
67
  expect(input.props.multiline).toBe(true);
68
68
  });
@@ -71,16 +71,14 @@ describe("TextArea", () => {
71
71
  const {getByDisplayValue} = renderWithTheme(
72
72
  <TextArea disabled value="test" onChange={mockOnChange} />
73
73
  );
74
-
74
+
75
75
  const input = getByDisplayValue("test");
76
76
  expect(input.props.readOnly).toBe(true);
77
77
  });
78
78
 
79
79
  it("should always have text type", () => {
80
- const {getByDisplayValue} = renderWithTheme(
81
- <TextArea value="" onChange={mockOnChange} />
82
- );
83
-
80
+ const {getByDisplayValue} = renderWithTheme(<TextArea value="" onChange={mockOnChange} />);
81
+
84
82
  const input = getByDisplayValue("");
85
83
  expect(input.props.keyboardType).toBe("default");
86
84
  });
@@ -89,9 +87,7 @@ describe("TextArea", () => {
89
87
  describe("user interactions", () => {
90
88
  it("should call onChange when text is entered", async () => {
91
89
  const user = userEvent.setup();
92
- const {getByDisplayValue} = renderWithTheme(
93
- <TextArea value="" onChange={mockOnChange} />
94
- );
90
+ const {getByDisplayValue} = renderWithTheme(<TextArea value="" onChange={mockOnChange} />);
95
91
 
96
92
  const input = getByDisplayValue("");
97
93
  await user.type(input, "hello world");
@@ -103,9 +99,7 @@ describe("TextArea", () => {
103
99
  it("should handle multiline text input", async () => {
104
100
  const user = userEvent.setup();
105
101
  const multilineText = "Line 1\nLine 2\nLine 3";
106
- const {getByDisplayValue} = renderWithTheme(
107
- <TextArea value="" onChange={mockOnChange} />
108
- );
102
+ const {getByDisplayValue} = renderWithTheme(<TextArea value="" onChange={mockOnChange} />);
109
103
 
110
104
  const input = getByDisplayValue("");
111
105
  await user.type(input, multilineText);
@@ -117,10 +111,8 @@ describe("TextArea", () => {
117
111
 
118
112
  describe("accessibility", () => {
119
113
  it("should have correct accessibility properties", () => {
120
- const {getByDisplayValue} = renderWithTheme(
121
- <TextArea value="" onChange={mockOnChange} />
122
- );
123
-
114
+ const {getByDisplayValue} = renderWithTheme(<TextArea value="" onChange={mockOnChange} />);
115
+
124
116
  const input = getByDisplayValue("");
125
117
  expect(input.props.accessibilityHint).toBe("Enter text here");
126
118
  expect(input.props["aria-label"]).toBe("Text input field");
@@ -130,7 +122,7 @@ describe("TextArea", () => {
130
122
  const {getByDisplayValue} = renderWithTheme(
131
123
  <TextArea disabled value="" onChange={mockOnChange} />
132
124
  );
133
-
125
+
134
126
  const input = getByDisplayValue("");
135
127
  expect(input.props.accessibilityState.disabled).toBe(true);
136
128
  });
@@ -138,19 +130,15 @@ describe("TextArea", () => {
138
130
 
139
131
  describe("edge cases", () => {
140
132
  it("should handle empty value", () => {
141
- const {getByDisplayValue} = renderWithTheme(
142
- <TextArea value="" onChange={mockOnChange} />
143
- );
144
-
133
+ const {getByDisplayValue} = renderWithTheme(<TextArea value="" onChange={mockOnChange} />);
134
+
145
135
  const input = getByDisplayValue("");
146
136
  expect(input.props.value).toBe("");
147
137
  });
148
138
 
149
139
  it("should handle undefined value", () => {
150
- const {root} = renderWithTheme(
151
- <TextArea value={undefined} onChange={mockOnChange} />
152
- );
153
-
140
+ const {root} = renderWithTheme(<TextArea value={undefined} onChange={mockOnChange} />);
141
+
154
142
  expect(root).toBeTruthy();
155
143
  });
156
144
 
@@ -159,7 +147,7 @@ describe("TextArea", () => {
159
147
  const {getByDisplayValue} = renderWithTheme(
160
148
  <TextArea value={longText} onChange={mockOnChange} />
161
149
  );
162
-
150
+
163
151
  const input = getByDisplayValue(longText);
164
152
  expect(input.props.value).toBe(longText);
165
153
  });
@@ -169,7 +157,7 @@ describe("TextArea", () => {
169
157
  const {getByDisplayValue} = renderWithTheme(
170
158
  <TextArea value={textWithBreaks} onChange={mockOnChange} />
171
159
  );
172
-
160
+
173
161
  const input = getByDisplayValue(textWithBreaks);
174
162
  expect(input.props.value).toBe(textWithBreaks);
175
163
  });
@@ -179,10 +167,10 @@ describe("TextArea", () => {
179
167
  it("should inherit all TextField props except multiline and type", () => {
180
168
  const mockOnFocus = jest.fn();
181
169
  const mockOnBlur = jest.fn();
182
-
170
+
183
171
  const {getByDisplayValue} = renderWithTheme(
184
- <TextArea
185
- value="test"
172
+ <TextArea
173
+ value="test"
186
174
  onChange={mockOnChange}
187
175
  onFocus={mockOnFocus}
188
176
  onBlur={mockOnBlur}
@@ -191,7 +179,7 @@ describe("TextArea", () => {
191
179
  rows={5}
192
180
  />
193
181
  );
194
-
182
+
195
183
  const input = getByDisplayValue("test");
196
184
  expect(input.props.numberOfLines).toBe(5);
197
185
  expect(input.props.onFocus).toBeTruthy();
@@ -200,19 +188,15 @@ describe("TextArea", () => {
200
188
 
201
189
  it("should support inputRef", () => {
202
190
  const mockInputRef = jest.fn();
203
- renderWithTheme(
204
- <TextArea inputRef={mockInputRef} value="" onChange={mockOnChange} />
205
- );
206
-
191
+ renderWithTheme(<TextArea inputRef={mockInputRef} value="" onChange={mockOnChange} />);
192
+
207
193
  expect(mockInputRef).toHaveBeenCalled();
208
194
  });
209
195
  });
210
196
 
211
197
  describe("snapshots", () => {
212
198
  it("should match snapshot with default props", () => {
213
- const component = renderWithTheme(
214
- <TextArea value="test content" onChange={mockOnChange} />
215
- );
199
+ const component = renderWithTheme(<TextArea value="test content" onChange={mockOnChange} />);
216
200
  expect(component.toJSON()).toMatchSnapshot();
217
201
  });
218
202
 
@@ -1,8 +1,7 @@
1
1
  import {act, userEvent} from "@testing-library/react-native";
2
2
  import React from "react";
3
-
4
- import {renderWithTheme} from "./test-utils";
5
3
  import {TextField} from "./TextField";
4
+ import {renderWithTheme} from "./test-utils";
6
5
 
7
6
  describe("TextField", () => {
8
7
  let mockOnChange: jest.Mock;
@@ -103,7 +102,7 @@ describe("TextField", () => {
103
102
  });
104
103
 
105
104
  it("should call onEnter when enter key is pressed", async () => {
106
- const user = userEvent.setup();
105
+ const _user = userEvent.setup();
107
106
  const {getByDisplayValue} = renderWithTheme(
108
107
  <TextField value="" onChange={mockOnChange} onEnter={mockOnEnter} />
109
108
  );
@@ -206,7 +205,7 @@ describe("TextField", () => {
206
205
  });
207
206
 
208
207
  it("should not call onFocus when disabled", async () => {
209
- const user = userEvent.setup();
208
+ const _user = userEvent.setup();
210
209
  const {getByDisplayValue} = renderWithTheme(
211
210
  <TextField disabled value="" onChange={mockOnChange} onFocus={mockOnFocus} />
212
211
  );
@@ -4,18 +4,14 @@ import React from "react";
4
4
  import {ActionSheet} from "./ActionSheet";
5
5
  import {Box} from "./Box";
6
6
  import {Button} from "./Button";
7
- import {NumberPickerActionSheetProps, TextFieldPickerActionSheetProps} from "./Common";
7
+ import {TextFieldPickerActionSheetProps} from "./Common";
8
8
 
9
- interface NumberPickerActionSheetState {}
9
+ type NumberPickerActionSheetState = {};
10
10
 
11
11
  export class NumberPickerActionSheet extends React.Component<
12
12
  TextFieldPickerActionSheetProps,
13
13
  NumberPickerActionSheetState
14
14
  > {
15
- constructor(props: NumberPickerActionSheetProps) {
16
- super(props);
17
- }
18
-
19
15
  render() {
20
16
  return (
21
17
  <ActionSheet ref={this.props.actionSheetRef} bounceOnOpen gestureEnabled>
@@ -36,7 +32,7 @@ export class NumberPickerActionSheet extends React.Component<
36
32
  mode={this.props.mode}
37
33
  testID="dateTimePicker"
38
34
  value={this.props.value ? new Date(this.props.value) : new Date()}
39
- onChange={(event: any, date?: Date) => {
35
+ onChange={(_event: any, date?: Date) => {
40
36
  if (!date) {
41
37
  return;
42
38
  }
package/src/Tooltip.tsx CHANGED
@@ -19,20 +19,20 @@ const TOOLTIP_OFFSET = 6;
19
19
  // How many pixels to leave between the tooltip and the edge of the screen
20
20
  const TOOLTIP_OVERFLOW_PADDING = 20;
21
21
 
22
- type ChildrenMeasurement = {
22
+ interface ChildrenMeasurement {
23
23
  width: number;
24
24
  height: number;
25
25
  pageX: number;
26
26
  pageY: number;
27
- };
27
+ }
28
28
 
29
29
  // empty object is a fallback for when the tooltip is not measured yet
30
- type Measurement = {
30
+ interface Measurement {
31
31
  children: ChildrenMeasurement | {};
32
32
  tooltip: LayoutRectangle | {};
33
33
  measured: boolean;
34
34
  idealPosition?: TooltipPosition;
35
- };
35
+ }
36
36
 
37
37
  const getTooltipPosition = ({
38
38
  children,
@@ -182,20 +182,33 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
182
182
  const childrenWrapperRef = useRef<View>(null);
183
183
  const touched = useRef(false);
184
184
  const isWeb = Platform.OS === "web";
185
+ const resetMeasurement = useCallback(() => {
186
+ setMeasurement({
187
+ children: {},
188
+ tooltip: {},
189
+ measured: false,
190
+ });
191
+ }, []);
192
+ const hideTooltip = useCallback(() => {
193
+ if (showTooltipTimer.current) {
194
+ clearTimeout(showTooltipTimer.current);
195
+ }
196
+ if (hideTooltipTimer.current) {
197
+ clearTimeout(hideTooltipTimer.current);
198
+ }
199
+
200
+ touched.current = false;
201
+ setVisible(false);
202
+ resetMeasurement();
203
+ }, [resetMeasurement, setVisible]);
185
204
 
186
205
  // If the tooltip is visible, and the user clicks outside of the tooltip, hide it.
187
206
  useEffect(() => {
188
207
  return () => {
189
- if (showTooltipTimer.current) {
190
- clearTimeout(showTooltipTimer.current);
191
- }
192
- if (hideTooltipTimer.current) {
193
- clearTimeout(hideTooltipTimer.current);
194
- }
195
208
  // Hide tooltip on unmount to prevent it from staying stuck on screen
196
- setVisible(false);
209
+ hideTooltip();
197
210
  };
198
- }, []);
211
+ }, [hideTooltip]);
199
212
 
200
213
  const getArrowContainerStyle = (): ViewStyle => {
201
214
  if (!includeArrow) {
@@ -258,6 +271,11 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
258
271
  );
259
272
 
260
273
  const handleTouchStart = useCallback(() => {
274
+ if (visible) {
275
+ hideTooltip();
276
+ return;
277
+ }
278
+
261
279
  if (hideTooltipTimer.current) {
262
280
  clearTimeout(hideTooltipTimer.current);
263
281
  }
@@ -266,7 +284,7 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
266
284
  touched.current = true;
267
285
  setVisible(true);
268
286
  }, 100);
269
- }, []);
287
+ }, [hideTooltip, visible]);
270
288
 
271
289
  const handleHoverIn = useCallback(() => {
272
290
  if (hideTooltipTimer.current) {
@@ -280,20 +298,23 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
280
298
  }, [hoverDelay]);
281
299
 
282
300
  const handleHoverOut = useCallback(() => {
283
- touched.current = false;
284
301
  if (showTooltipTimer.current) {
285
302
  clearTimeout(showTooltipTimer.current);
286
303
  }
304
+ if (hideTooltipTimer.current) {
305
+ clearTimeout(hideTooltipTimer.current);
306
+ }
287
307
 
288
308
  hideTooltipTimer.current = setTimeout(() => {
289
- setVisible(false);
290
- setMeasurement({
291
- children: {},
292
- tooltip: {},
293
- measured: false,
294
- });
309
+ hideTooltip();
295
310
  }, hoverEndDelay);
296
- }, [hoverEndDelay]);
311
+ }, [hideTooltip, hoverEndDelay]);
312
+
313
+ const handleClick = useCallback(() => {
314
+ if (visible) {
315
+ hideTooltip();
316
+ }
317
+ }, [hideTooltip, visible]);
297
318
 
298
319
  const mobilePressProps = {
299
320
  onPress: useCallback(() => {
@@ -348,7 +369,7 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
348
369
  borderRadius: theme.radius.default,
349
370
  }}
350
371
  testID="tooltip-container"
351
- onPress={() => setVisible(false)}
372
+ onPress={hideTooltip}
352
373
  >
353
374
  <Text color="inverted" size="sm">
354
375
  {text}
@@ -369,6 +390,7 @@ export const Tooltip: FC<TooltipProps> = ({text, children, idealPosition, includ
369
390
  handleHoverOut();
370
391
  children.props.onHoverOut?.();
371
392
  }}
393
+ onPress={isWeb ? handleClick : undefined}
372
394
  onTouchStart={handleTouchStart}
373
395
  {...(!isWeb && mobilePressProps)}
374
396
  >
package/src/Unifier.ts CHANGED
@@ -6,7 +6,7 @@ import * as Clipboard from "expo-clipboard";
6
6
  import * as Haptics from "expo-haptics";
7
7
  import {Dimensions, Keyboard, Linking, Platform, Vibration} from "react-native";
8
8
 
9
- import {FernsTheme, PermissionKind} from "./Common";
9
+ import {PermissionKind} from "./Common";
10
10
  import {requestPermissions} from "./Permissions";
11
11
 
12
12
  declare global {
@@ -61,8 +61,6 @@ export function changeColorLuminance(hex: string, luminanceChange: Luminance) {
61
61
  }
62
62
 
63
63
  class UnifierClass {
64
- private _theme?: Partial<FernsTheme>;
65
-
66
64
  private _web = false;
67
65
 
68
66
  private _dev = false;
package/src/Utilities.tsx CHANGED
@@ -18,8 +18,7 @@ export function mergeInlineStyles(inlineStyle?: any, newStyle?: any) {
18
18
 
19
19
  export function isTestUser(profile?: BaseProfile) {
20
20
  return (
21
- profile &&
22
- profile.email &&
21
+ profile?.email &&
23
22
  (profile.email.indexOf("nang.io") > -1 || profile.email.indexOf("example.com") > -1)
24
23
  );
25
24
  }
@@ -57,7 +56,7 @@ order in which you do so doesn't really matter.
57
56
  */
58
57
 
59
58
  interface InlineStyle {
60
- [key: string]: string | number | void;
59
+ [key: string]: string | number | undefined;
61
60
  }
62
61
 
63
62
  // TODO: This type should be opaque, however the Babel parser doesn't support
@@ -318,7 +317,7 @@ export function formattedCountyCode(state: string, countyName: string): string {
318
317
  }
319
318
 
320
319
  export function isAPIError(error: any): error is APIError {
321
- return error && error.data?.title;
320
+ return error?.data?.title;
322
321
  }
323
322
 
324
323
  export function printAPIError(error: APIError, details = true): string {
@@ -7,7 +7,7 @@ import {processAddressComponents} from "./Utilities";
7
7
 
8
8
  const loadGooglePlacesScript = (googleMapsApiKey: string, callbackName: any): Promise<void> => {
9
9
  return new Promise<void>((resolve, reject): undefined => {
10
- if (window.google && window.google.maps && window.google.maps.places) {
10
+ if (window.google?.maps?.places) {
11
11
  resolve();
12
12
  return;
13
13
  }
package/src/index.tsx CHANGED
@@ -34,6 +34,7 @@ export * from "./ImageBackground";
34
34
  export * from "./InfoModalIcon";
35
35
  export * from "./InfoTooltipButton";
36
36
  export * from "./Link";
37
+ export * from "./MarkdownView";
37
38
  export * from "./MediaQuery";
38
39
  export * from "./MobileAddressAutoComplete";
39
40
  export * from "./Modal";
@@ -59,11 +60,17 @@ export * from "./SignatureField";
59
60
  export * from "./Slider";
60
61
  export * from "./Spinner";
61
62
  export * from "./SplitPage";
63
+ export * from "./TapToEdit";
64
+ export * from "./Text";
65
+ export * from "./TextArea";
66
+ export * from "./TextField";
67
+ export * from "./Theme";
68
+ export * from "./Toast";
69
+ export * from "./Tooltip";
62
70
  export * from "./table/Table";
63
71
  export * from "./table/Table";
64
72
  export * from "./table/TableBadge";
65
73
  export * from "./table/TableBoolean";
66
- export * from "./table/tableContext";
67
74
  export * from "./table/TableDate";
68
75
  export * from "./table/TableHeader";
69
76
  export * from "./table/TableHeaderCell";
@@ -72,19 +79,13 @@ export * from "./table/TableNumber";
72
79
  export * from "./table/TableRow";
73
80
  export * from "./table/TableText";
74
81
  export * from "./table/TableTitle";
75
- export * from "./TapToEdit";
76
- export * from "./Text";
77
- export * from "./TextArea";
78
- export * from "./TextField";
79
- export * from "./Theme";
80
- export * from "./Toast";
81
- export * from "./Tooltip";
82
- export * from "./MarkdownView";
82
+ export * from "./table/tableContext";
83
83
  export * from "./UnifiedAddressAutoComplete";
84
84
  export * from "./Unifier";
85
- export * from "./useStoredState";
86
85
  export * from "./Utilities";
86
+ export * from "./useStoredState";
87
87
  export * from "./WebAddressAutocomplete";
88
+
88
89
  // export * from "./Layout";
89
90
  // export * from "./Drawer";
90
91
  // export * from "./Chart";
@@ -1371,4 +1372,3 @@ export interface Options {
1371
1372
  */
1372
1373
  blurOnUnmount?: boolean;
1373
1374
  }
1374
- export {};
@@ -68,44 +68,42 @@ export const Table = ({
68
68
  sortColumn={sortColumn}
69
69
  stickyHeader={stickyHeader}
70
70
  >
71
- <>
72
- <Box
73
- flex="grow"
74
- maxWidth="100%"
75
- style={{
76
- position: "relative",
77
- }}
78
- width={width}
79
- >
80
- <ScrollView horizontal style={{width, maxWidth: "100%"}}>
81
- {/* TODO: Replace table scrollview with flat list */}
82
- <ScrollView
83
- // nestedScrollEnabled
84
- stickyHeaderIndices={stickyHeader ? [0] : undefined}
85
- style={{width, maxWidth: "100%", flex: 1, maxHeight}}
86
- >
87
- {Children.map(
88
- children,
89
- (child, index) =>
90
- Boolean(child) &&
91
- React.cloneElement(child as ReactElement, {
92
- color: index % 2 === 1 && alternateRowBackground ? "neutralLight" : "base",
93
- })
94
- )}
95
- </ScrollView>
71
+ <Box
72
+ flex="grow"
73
+ maxWidth="100%"
74
+ style={{
75
+ position: "relative",
76
+ }}
77
+ width={width}
78
+ >
79
+ <ScrollView horizontal style={{width, maxWidth: "100%"}}>
80
+ {/* TODO: Replace table scrollview with flat list */}
81
+ <ScrollView
82
+ // nestedScrollEnabled
83
+ stickyHeaderIndices={stickyHeader ? [0] : undefined}
84
+ style={{width, maxWidth: "100%", flex: 1, maxHeight}}
85
+ >
86
+ {Children.map(
87
+ children,
88
+ (child, index) =>
89
+ Boolean(child) &&
90
+ React.cloneElement(child as ReactElement, {
91
+ color: index % 2 === 1 && alternateRowBackground ? "neutralLight" : "base",
92
+ })
93
+ )}
96
94
  </ScrollView>
95
+ </ScrollView>
96
+ </Box>
97
+ {Boolean(shouldPaginate && totalPages !== undefined) && (
98
+ <Box alignItems="center" borderTop="default" direction="row" height={60} paddingX={8}>
99
+ <Pagination
100
+ page={propsPage ?? page}
101
+ setPage={propsSetPage ?? setPage}
102
+ totalPages={totalPages!}
103
+ />
104
+ {Boolean(extraControls) && extraControls}
97
105
  </Box>
98
- {Boolean(shouldPaginate && totalPages !== undefined) && (
99
- <Box alignItems="center" borderTop="default" direction="row" height={60} paddingX={8}>
100
- <Pagination
101
- page={propsPage ?? page}
102
- setPage={propsSetPage ?? setPage}
103
- totalPages={totalPages!}
104
- />
105
- {Boolean(extraControls) && extraControls}
106
- </Box>
107
- )}
108
- </>
106
+ )}
109
107
  </TableContextProvider>
110
108
  );
111
109
  };
@@ -6,8 +6,8 @@ import {View} from "react-native";
6
6
  import {Box} from "../Box";
7
7
  import {AlignItems, TableHeaderCellProps} from "../Common";
8
8
  import {useTheme} from "../Theme";
9
- import {useTableContext} from "./tableContext";
10
9
  import {TableTitle} from "./TableTitle";
10
+ import {useTableContext} from "./tableContext";
11
11
 
12
12
  /**
13
13
  * Use TableHeaderCell to define a header cell in Table.
@@ -48,7 +48,7 @@ export const TableHeaderCell = ({
48
48
  if (setSortColumn) {
49
49
  setSortColumn(newSort ? {column: index, direction: newSort} : undefined);
50
50
  }
51
- onSortChange && onSortChange(newSort);
51
+ onSortChange?.(newSort);
52
52
  }, [index, onSortChange, setSortColumn, sort]);
53
53
 
54
54
  if (sortable && !onSortChange) {
@@ -22,17 +22,19 @@ export const useStoredState = <T>(
22
22
 
23
23
  // Fetch data when the component mounts
24
24
  useEffect(() => {
25
- void fetchData().then((value) => {
26
- if (isMounted.current) {
27
- setState(value);
28
- setIsLoading(false);
29
- }
30
- }).catch((error) => {
31
- console.error("Error fetching data:", error);
32
- if (isMounted.current) {
33
- setIsLoading(false);
34
- }
35
- });
25
+ void fetchData()
26
+ .then((value) => {
27
+ if (isMounted.current) {
28
+ setState(value);
29
+ setIsLoading(false);
30
+ }
31
+ })
32
+ .catch((error) => {
33
+ console.error("Error fetching data:", error);
34
+ if (isMounted.current) {
35
+ setIsLoading(false);
36
+ }
37
+ });
36
38
 
37
39
  return () => {
38
40
  isMounted.current = false;