ferns-ui 1.15.0 → 2.0.0-beta.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.
- package/dist/ActionSheet.js +11 -14
- package/dist/ActionSheet.js.map +1 -1
- package/dist/AddressField.js +1 -1
- package/dist/AddressField.js.map +1 -1
- package/dist/Badge.js +1 -1
- package/dist/Badge.js.map +1 -1
- package/dist/Banner.js +1 -1
- package/dist/Banner.js.map +1 -1
- package/dist/Box.js +3 -3
- package/dist/Box.js.map +1 -1
- package/dist/Button.js +1 -0
- package/dist/Button.js.map +1 -1
- package/dist/CheckBox.js.map +1 -1
- package/dist/Common.d.ts +7 -7
- package/dist/Common.js.map +1 -1
- package/dist/DataTable.js +2 -1
- package/dist/DataTable.js.map +1 -1
- package/dist/DateTimeField.js +22 -22
- package/dist/DateTimeField.js.map +1 -1
- package/dist/ErrorBoundary.d.ts +1 -1
- package/dist/FernsProvider.js +1 -1
- package/dist/FernsProvider.js.map +1 -1
- package/dist/Heading.js +1 -3
- package/dist/Heading.js.map +1 -1
- package/dist/Hyperlink.js +1 -1
- package/dist/Hyperlink.js.map +1 -1
- package/dist/IconButton.js +1 -1
- package/dist/IconButton.js.map +1 -1
- package/dist/Image.js.map +1 -1
- package/dist/MobileAddressAutoComplete.js +1 -1
- package/dist/MobileAddressAutoComplete.js.map +1 -1
- package/dist/Modal.d.ts +1 -1
- package/dist/Modal.js +15 -35
- package/dist/Modal.js.map +1 -1
- package/dist/ModalSheet.d.ts +1 -1
- package/dist/ModalSheet.js +1 -1
- package/dist/ModalSheet.js.map +1 -1
- package/dist/NumberField.js +4 -10
- package/dist/NumberField.js.map +1 -1
- package/dist/NumberPickerActionSheet.d.ts +3 -1
- package/dist/NumberPickerActionSheet.js +3 -0
- package/dist/NumberPickerActionSheet.js.map +1 -1
- package/dist/Page.js +1 -1
- package/dist/Page.js.map +1 -1
- package/dist/Pagination.js +2 -2
- package/dist/Pagination.js.map +1 -1
- package/dist/Permissions.d.ts +1 -1
- package/dist/Permissions.js +2 -2
- package/dist/Permissions.js.map +1 -1
- package/dist/PickerSelect.js +1 -1
- package/dist/PickerSelect.js.map +1 -1
- package/dist/SectionDivider.js +1 -1
- package/dist/SectionDivider.js.map +1 -1
- package/dist/SegmentedControl.js.map +1 -1
- package/dist/Signature.native.js +2 -2
- package/dist/Signature.native.js.map +1 -1
- package/dist/SignatureField.js +2 -2
- package/dist/SignatureField.js.map +1 -1
- package/dist/Slider.js +3 -3
- package/dist/Slider.js.map +1 -1
- package/dist/SplitPage.js +7 -7
- package/dist/SplitPage.js.map +1 -1
- package/dist/SplitPage.native.js +6 -4
- package/dist/SplitPage.native.js.map +1 -1
- package/dist/TapToEdit.js +3 -3
- package/dist/TapToEdit.js.map +1 -1
- package/dist/Text.js +1 -1
- package/dist/Text.js.map +1 -1
- package/dist/TextFieldNumberActionSheet.d.ts +4 -2
- package/dist/TextFieldNumberActionSheet.js +4 -1
- package/dist/TextFieldNumberActionSheet.js.map +1 -1
- package/dist/Tooltip.js +21 -39
- package/dist/Tooltip.js.map +1 -1
- package/dist/Unifier.d.ts +1 -0
- package/dist/Unifier.js.map +1 -1
- package/dist/Utilities.d.ts +1 -1
- package/dist/Utilities.js +3 -2
- package/dist/Utilities.js.map +1 -1
- package/dist/WebAddressAutocomplete.js +1 -2
- package/dist/WebAddressAutocomplete.js.map +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -10
- package/dist/index.js.map +1 -1
- package/dist/jestSetup.d.ts +0 -0
- package/dist/jestSetup.js +21 -0
- package/dist/jestSetup.js.map +1 -0
- package/dist/setupTests.js +22 -0
- package/dist/setupTests.js.map +1 -1
- package/dist/table/Table.js +15 -14
- package/dist/table/Table.js.map +1 -1
- package/dist/table/TableHeaderCell.js +2 -2
- package/dist/table/TableHeaderCell.js.map +1 -1
- package/dist/test-utils.d.ts +4 -1
- package/dist/useStoredState.js +2 -4
- package/dist/useStoredState.js.map +1 -1
- package/package.json +106 -43
- package/src/ActionSheet.tsx +22 -26
- package/src/AddressField.tsx +1 -1
- package/src/Avatar.test.tsx +0 -2
- package/src/Badge.tsx +1 -1
- package/src/Banner.tsx +1 -1
- package/src/Box.test.tsx +70 -71
- package/src/Box.tsx +9 -21
- package/src/Button.tsx +1 -0
- package/src/CheckBox.tsx +1 -7
- package/src/Common.ts +19 -7
- package/src/DataTable.tsx +4 -3
- package/src/DateTimeField.tsx +22 -22
- package/src/FernsProvider.tsx +4 -1
- package/src/Heading.tsx +1 -3
- package/src/Hyperlink.tsx +2 -2
- package/src/IconButton.tsx +2 -2
- package/src/Image.tsx +0 -1
- package/src/MobileAddressAutoComplete.tsx +1 -1
- package/src/Modal.tsx +21 -58
- package/src/ModalSheet.tsx +1 -1
- package/src/NumberField.tsx +4 -10
- package/src/NumberPickerActionSheet.tsx +5 -1
- package/src/Page.tsx +1 -1
- package/src/Pagination.tsx +11 -2
- package/src/Permissions.ts +2 -2
- package/src/PickerSelect.tsx +1 -1
- package/src/SectionDivider.tsx +1 -1
- package/src/SegmentedControl.tsx +1 -3
- package/src/Signature.native.tsx +2 -2
- package/src/SignatureField.tsx +2 -2
- package/src/Slider.tsx +17 -10
- package/src/SplitPage.native.tsx +4 -2
- package/src/SplitPage.tsx +4 -4
- package/src/TapToEdit.tsx +7 -3
- package/src/Text.tsx +1 -1
- package/src/TextArea.test.tsx +43 -27
- package/src/TextField.test.tsx +4 -3
- package/src/TextFieldNumberActionSheet.tsx +7 -3
- package/src/Tooltip.tsx +29 -45
- package/src/Unifier.ts +3 -1
- package/src/Utilities.tsx +4 -3
- package/src/WebAddressAutocomplete.tsx +1 -1
- package/src/index.tsx +10 -11
- package/src/jestSetup.ts +16 -0
- package/src/setupTests.ts +24 -0
- package/src/table/Table.tsx +38 -36
- package/src/table/TableHeaderCell.tsx +2 -2
- package/src/useStoredState.ts +11 -13
- package/dist/Accordion.test.d.ts +0 -1
- package/dist/Accordion.test.js +0 -71
- package/dist/Accordion.test.js.map +0 -1
- package/dist/AddressField.test.d.ts +0 -1
- package/dist/AddressField.test.js +0 -65
- package/dist/AddressField.test.js.map +0 -1
- package/dist/Avatar.test.d.ts +0 -1
- package/dist/Avatar.test.js +0 -131
- package/dist/Avatar.test.js.map +0 -1
- package/dist/Badge.test.d.ts +0 -1
- package/dist/Badge.test.js +0 -76
- package/dist/Badge.test.js.map +0 -1
- package/dist/Box.test.d.ts +0 -1
- package/dist/Box.test.js +0 -528
- package/dist/Box.test.js.map +0 -1
- package/dist/DateTimeField.test.d.ts +0 -1
- package/dist/DateTimeField.test.js +0 -258
- package/dist/DateTimeField.test.js.map +0 -1
- package/dist/DateUtilities.test.d.ts +0 -1
- package/dist/DateUtilities.test.js +0 -279
- package/dist/DateUtilities.test.js.map +0 -1
- package/dist/MarkdownView.d.ts +0 -5
- package/dist/MarkdownView.js +0 -44
- package/dist/MarkdownView.js.map +0 -1
- package/dist/TextArea.test.d.ts +0 -1
- package/dist/TextArea.test.js +0 -146
- package/dist/TextArea.test.js.map +0 -1
- package/dist/TextField.test.d.ts +0 -1
- package/dist/TextField.test.js +0 -251
- package/dist/TextField.test.js.map +0 -1
- package/dist/useStoredState.test.d.ts +0 -1
- package/dist/useStoredState.test.js +0 -93
- package/dist/useStoredState.test.js.map +0 -1
- package/src/MarkdownView.tsx +0 -67
package/src/DateTimeField.tsx
CHANGED
|
@@ -262,20 +262,20 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
262
262
|
if (type === "date" || type === "datetime") {
|
|
263
263
|
if (fieldIndex === 0) {
|
|
264
264
|
// Month
|
|
265
|
-
const monthNum = parseInt(fieldValue
|
|
266
|
-
if (
|
|
265
|
+
const monthNum = parseInt(fieldValue);
|
|
266
|
+
if (isNaN(monthNum) || monthNum < 1 || monthNum > 12) {
|
|
267
267
|
return "Month must be between 1 and 12";
|
|
268
268
|
}
|
|
269
269
|
} else if (fieldIndex === 1) {
|
|
270
270
|
// Day
|
|
271
|
-
const dayNum = parseInt(fieldValue
|
|
272
|
-
if (
|
|
271
|
+
const dayNum = parseInt(fieldValue);
|
|
272
|
+
if (isNaN(dayNum) || dayNum < 1 || dayNum > 31) {
|
|
273
273
|
return "Day must be between 1 and 31";
|
|
274
274
|
}
|
|
275
275
|
} else if (fieldIndex === 2) {
|
|
276
276
|
// Year
|
|
277
|
-
const yearNum = parseInt(fieldValue
|
|
278
|
-
if (
|
|
277
|
+
const yearNum = parseInt(fieldValue);
|
|
278
|
+
if (isNaN(yearNum) || yearNum < 1900 || yearNum > 2100) {
|
|
279
279
|
return "Year must be between 1900 and 2100";
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -284,14 +284,14 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
284
284
|
if (type === "time" || type === "datetime") {
|
|
285
285
|
if (fieldIndex === (type === "time" ? 0 : 3)) {
|
|
286
286
|
// Hour
|
|
287
|
-
const hourNum = parseInt(fieldValue
|
|
288
|
-
if (
|
|
287
|
+
const hourNum = parseInt(fieldValue);
|
|
288
|
+
if (isNaN(hourNum) || hourNum < 1 || hourNum > 12) {
|
|
289
289
|
return "Hour must be between 1 and 12";
|
|
290
290
|
}
|
|
291
291
|
} else if (fieldIndex === (type === "time" ? 1 : 4)) {
|
|
292
292
|
// Minute
|
|
293
|
-
const minuteNum = parseInt(fieldValue
|
|
294
|
-
if (
|
|
293
|
+
const minuteNum = parseInt(fieldValue);
|
|
294
|
+
if (isNaN(minuteNum) || minuteNum < 0 || minuteNum > 59) {
|
|
295
295
|
return "Minute must be between 0 and 59";
|
|
296
296
|
}
|
|
297
297
|
}
|
|
@@ -323,7 +323,7 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
323
323
|
if (!monthVal || !dayVal || !yearVal || !hour || !minuteVal) {
|
|
324
324
|
return undefined;
|
|
325
325
|
}
|
|
326
|
-
let hourNum = parseInt(hourVal
|
|
326
|
+
let hourNum = parseInt(hourVal);
|
|
327
327
|
if (ampPmVal === "pm" && hourNum !== 12) {
|
|
328
328
|
hourNum += 12;
|
|
329
329
|
} else if (ampPmVal === "am" && hourNum === 12) {
|
|
@@ -331,11 +331,11 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
331
331
|
}
|
|
332
332
|
date = DateTime.fromObject(
|
|
333
333
|
{
|
|
334
|
-
year: parseInt(yearVal
|
|
335
|
-
month: parseInt(monthVal
|
|
336
|
-
day: parseInt(dayVal
|
|
334
|
+
year: parseInt(yearVal),
|
|
335
|
+
month: parseInt(monthVal),
|
|
336
|
+
day: parseInt(dayVal),
|
|
337
337
|
hour: hourNum,
|
|
338
|
-
minute: parseInt(minuteVal
|
|
338
|
+
minute: parseInt(minuteVal),
|
|
339
339
|
second: 0,
|
|
340
340
|
millisecond: 0,
|
|
341
341
|
},
|
|
@@ -349,9 +349,9 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
349
349
|
}
|
|
350
350
|
date = DateTime.fromObject(
|
|
351
351
|
{
|
|
352
|
-
year: parseInt(yearVal
|
|
353
|
-
month: parseInt(monthVal
|
|
354
|
-
day: parseInt(dayVal
|
|
352
|
+
year: parseInt(yearVal),
|
|
353
|
+
month: parseInt(monthVal),
|
|
354
|
+
day: parseInt(dayVal),
|
|
355
355
|
hour: 0,
|
|
356
356
|
minute: 0,
|
|
357
357
|
second: 0,
|
|
@@ -365,7 +365,7 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
365
365
|
if (!hour || !minuteVal) {
|
|
366
366
|
return undefined;
|
|
367
367
|
}
|
|
368
|
-
let hourNum = parseInt(hour
|
|
368
|
+
let hourNum = parseInt(hour);
|
|
369
369
|
if (ampPmVal === "pm" && hourNum !== 12) {
|
|
370
370
|
hourNum += 12;
|
|
371
371
|
} else if (ampPmVal === "am" && hourNum === 12) {
|
|
@@ -374,7 +374,7 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
374
374
|
date = DateTime.fromObject(
|
|
375
375
|
{
|
|
376
376
|
hour: hourNum,
|
|
377
|
-
minute: parseInt(minuteVal
|
|
377
|
+
minute: parseInt(minuteVal),
|
|
378
378
|
second: 0,
|
|
379
379
|
millisecond: 0,
|
|
380
380
|
},
|
|
@@ -404,7 +404,7 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
404
404
|
// so it's always a valid time and easier to edit.
|
|
405
405
|
// This lets users freely edit or clear the minute field without breaking the time format.
|
|
406
406
|
const finalValue = numericValue === "" ? "00" : numericValue.slice(-2);
|
|
407
|
-
const minuteNum = parseInt(finalValue
|
|
407
|
+
const minuteNum = parseInt(finalValue);
|
|
408
408
|
|
|
409
409
|
// Update the minute state so the UI reflects the latest input,
|
|
410
410
|
// even if it's temporarily invalid
|
|
@@ -412,7 +412,7 @@ export const DateTimeField: FC<DateTimeFieldProps> = ({
|
|
|
412
412
|
setMinute(finalValue);
|
|
413
413
|
|
|
414
414
|
// Only update ref and result if it's a valid minute value
|
|
415
|
-
if (!
|
|
415
|
+
if (!isNaN(minuteNum) && minuteNum >= 0 && minuteNum <= 59) {
|
|
416
416
|
pendingValueRef.current = {minute: finalValue};
|
|
417
417
|
setFieldErrors((prev) => ({...prev, [index]: undefined}));
|
|
418
418
|
|
package/src/FernsProvider.tsx
CHANGED
|
@@ -9,7 +9,10 @@ import {Toast} from "./Toast";
|
|
|
9
9
|
export const FernsProvider: FC<{
|
|
10
10
|
children: React.ReactNode;
|
|
11
11
|
openAPISpecUrl?: string;
|
|
12
|
-
}> = ({
|
|
12
|
+
}> = ({
|
|
13
|
+
children,
|
|
14
|
+
openAPISpecUrl,
|
|
15
|
+
}) => {
|
|
13
16
|
return (
|
|
14
17
|
<ThemeProvider>
|
|
15
18
|
<ToastProvider
|
package/src/Heading.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
useFonts,
|
|
5
5
|
} from "@expo-google-fonts/titillium-web";
|
|
6
6
|
import React from "react";
|
|
7
|
-
import {Text as NativeText,
|
|
7
|
+
import {Platform, StyleProp, Text as NativeText, TextStyle} from "react-native";
|
|
8
8
|
|
|
9
9
|
import {HeadingProps} from "./Common";
|
|
10
10
|
import {useTheme} from "./Theme";
|
|
@@ -14,7 +14,6 @@ const fontSizeAndWeightWeb = {
|
|
|
14
14
|
md: {size: 18, weight: "bold"},
|
|
15
15
|
lg: {size: 24, weight: "bold"},
|
|
16
16
|
xl: {size: 32, weight: "bold"},
|
|
17
|
-
"2xl": {size: 48, weight: "bold"},
|
|
18
17
|
};
|
|
19
18
|
|
|
20
19
|
const fontSizeAndWeighMobile = {
|
|
@@ -22,7 +21,6 @@ const fontSizeAndWeighMobile = {
|
|
|
22
21
|
md: {size: 16, weight: "bold"},
|
|
23
22
|
lg: {size: 20, weight: "bold"},
|
|
24
23
|
xl: {size: 28, weight: "bold"},
|
|
25
|
-
"2xl": {size: 32, weight: "bold"},
|
|
26
24
|
};
|
|
27
25
|
|
|
28
26
|
const fontSizes = Platform.OS === "web" ? fontSizeAndWeightWeb : fontSizeAndWeighMobile;
|
package/src/Hyperlink.tsx
CHANGED
|
@@ -111,7 +111,7 @@ class HyperlinkComponent extends React.Component<HyperlinkProps> {
|
|
|
111
111
|
component.props.children.substring(_lastIndex, component.props.children.length)
|
|
112
112
|
);
|
|
113
113
|
return React.cloneElement(component, componentProps, elements);
|
|
114
|
-
} catch (
|
|
114
|
+
} catch (error) {
|
|
115
115
|
return component;
|
|
116
116
|
}
|
|
117
117
|
};
|
|
@@ -156,7 +156,7 @@ class HyperlinkComponent extends React.Component<HyperlinkProps> {
|
|
|
156
156
|
<View {...viewProps} style={this.props.style}>
|
|
157
157
|
{!this.props.onPress && !this.props.onLongPress && !this.props.linkStyle
|
|
158
158
|
? this.props.children
|
|
159
|
-
: this.parse(this).props.children}
|
|
159
|
+
: (this.parse(this).props as {children?: React.ReactNode}).children}
|
|
160
160
|
</View>
|
|
161
161
|
);
|
|
162
162
|
}
|
package/src/IconButton.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import FontAwesome6 from "@expo/vector-icons/FontAwesome6";
|
|
2
2
|
import debounce from "lodash/debounce";
|
|
3
3
|
import React, {FC, useState} from "react";
|
|
4
|
-
import {ActivityIndicator, Text as NativeText,
|
|
4
|
+
import {ActivityIndicator, Pressable, Text as NativeText, View} from "react-native";
|
|
5
5
|
|
|
6
6
|
import {IconButtonProps} from "./Common";
|
|
7
7
|
import {isMobileDevice} from "./MediaQuery";
|
|
@@ -98,7 +98,7 @@ const IconButtonComponent: FC<IconButtonProps> = ({
|
|
|
98
98
|
return (
|
|
99
99
|
<Pressable
|
|
100
100
|
accessibilityHint={
|
|
101
|
-
|
|
101
|
+
accessibilityHint ?? withConfirmation
|
|
102
102
|
? `Opens a confirmation dialog to confirm ${accessLabel}`
|
|
103
103
|
: `Press to perform ${accessLabel} action`
|
|
104
104
|
}
|
package/src/Image.tsx
CHANGED
|
@@ -108,7 +108,7 @@ export const MobileAddressAutocomplete = ({
|
|
|
108
108
|
handleAddressChange(event.nativeEvent.text);
|
|
109
109
|
},
|
|
110
110
|
}}
|
|
111
|
-
onPress={(
|
|
111
|
+
onPress={(data, details = null) => {
|
|
112
112
|
const addressComponents = details?.address_components;
|
|
113
113
|
const formattedAddressObject = processAddressComponents(addressComponents, {
|
|
114
114
|
includeCounty,
|
package/src/Modal.tsx
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React, {FC, useEffect, useRef} from "react";
|
|
2
|
-
import {Dimensions, DimensionValue,
|
|
2
|
+
import {Dimensions, DimensionValue, Modal as RNModal, Pressable, View} from "react-native";
|
|
3
3
|
import ActionSheet, {ActionSheetRef} from "react-native-actions-sheet";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
PanGestureHandler,
|
|
6
|
+
PanGestureHandlerStateChangeEvent,
|
|
7
|
+
State,
|
|
8
|
+
} from "react-native-gesture-handler";
|
|
6
9
|
|
|
7
10
|
import {Button} from "./Button";
|
|
8
|
-
import
|
|
11
|
+
import {ModalProps} from "./Common";
|
|
9
12
|
import {Heading} from "./Heading";
|
|
10
13
|
import {Icon} from "./Icon";
|
|
11
14
|
import {isMobileDevice} from "./MediaQuery";
|
|
@@ -126,13 +129,7 @@ const ModalContent: FC<{
|
|
|
126
129
|
</View>
|
|
127
130
|
)}
|
|
128
131
|
{children && (
|
|
129
|
-
<View
|
|
130
|
-
style={{
|
|
131
|
-
marginTop: text ? 0 : 12,
|
|
132
|
-
width: "100%",
|
|
133
|
-
flex: isMobile ? undefined : 1,
|
|
134
|
-
}}
|
|
135
|
-
>
|
|
132
|
+
<View style={{marginTop: text ? 0 : 12, width: "100%", flex: isMobile ? undefined : 1}}>
|
|
136
133
|
{children}
|
|
137
134
|
</View>
|
|
138
135
|
)}
|
|
@@ -166,7 +163,6 @@ const ModalContent: FC<{
|
|
|
166
163
|
|
|
167
164
|
export const Modal: FC<ModalProps> = ({
|
|
168
165
|
children,
|
|
169
|
-
persistOnBackgroundClick = false,
|
|
170
166
|
primaryButtonDisabled = false,
|
|
171
167
|
primaryButtonText,
|
|
172
168
|
secondaryButtonText,
|
|
@@ -188,28 +184,23 @@ export const Modal: FC<ModalProps> = ({
|
|
|
188
184
|
}
|
|
189
185
|
};
|
|
190
186
|
|
|
191
|
-
const handlePrimaryButtonClick = (
|
|
192
|
-
value?: Parameters<NonNullable<ModalProps["primaryButtonOnClick"]>>[0]
|
|
193
|
-
) => {
|
|
187
|
+
const handlePrimaryButtonClick = (value?: Parameters<NonNullable<ModalProps["primaryButtonOnClick"]>>[0]) => {
|
|
194
188
|
if (visible && primaryButtonOnClick) {
|
|
195
189
|
return primaryButtonOnClick(value);
|
|
196
190
|
}
|
|
197
191
|
};
|
|
198
192
|
|
|
199
|
-
const handleSecondaryButtonClick = (
|
|
200
|
-
value?: Parameters<NonNullable<ModalProps["secondaryButtonOnClick"]>>[0]
|
|
201
|
-
) => {
|
|
193
|
+
const handleSecondaryButtonClick = (value?: Parameters<NonNullable<ModalProps["secondaryButtonOnClick"]>>[0]) => {
|
|
202
194
|
if (visible && secondaryButtonOnClick) {
|
|
203
195
|
return secondaryButtonOnClick(value);
|
|
204
196
|
}
|
|
205
197
|
};
|
|
206
198
|
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
runOnJS(handleDismiss)();
|
|
199
|
+
const onHandlerStateChange = ({nativeEvent}: PanGestureHandlerStateChangeEvent) => {
|
|
200
|
+
if (nativeEvent.state === State.END && nativeEvent.translationY > 100) {
|
|
201
|
+
handleDismiss();
|
|
211
202
|
}
|
|
212
|
-
}
|
|
203
|
+
};
|
|
213
204
|
|
|
214
205
|
// Open the action sheet ref when the visible prop changes.
|
|
215
206
|
useEffect(() => {
|
|
@@ -222,7 +213,6 @@ export const Modal: FC<ModalProps> = ({
|
|
|
222
213
|
const sizePx = getModalSize(size);
|
|
223
214
|
|
|
224
215
|
const modalContentProps = {
|
|
225
|
-
persistOnBackgroundClick,
|
|
226
216
|
title,
|
|
227
217
|
subtitle,
|
|
228
218
|
text,
|
|
@@ -239,22 +229,13 @@ export const Modal: FC<ModalProps> = ({
|
|
|
239
229
|
|
|
240
230
|
if (isMobile) {
|
|
241
231
|
return (
|
|
242
|
-
<ActionSheet
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// Disable ActionSheet's built-in gestures to avoid conflicts with scrolling
|
|
246
|
-
gestureEnabled={false}
|
|
247
|
-
onClose={handleDismiss}
|
|
248
|
-
>
|
|
249
|
-
<View>
|
|
250
|
-
{/* Attach our own swipe-to-dismiss gesture to the top handle */}
|
|
251
|
-
<GestureDetector gesture={dragToClose}>
|
|
232
|
+
<ActionSheet ref={actionSheetRef} onClose={handleDismiss}>
|
|
233
|
+
<PanGestureHandler onHandlerStateChange={onHandlerStateChange}>
|
|
234
|
+
<View>
|
|
252
235
|
<View
|
|
253
236
|
accessibilityHint="Pull down to close the modal"
|
|
254
237
|
aria-label="Pull down bar"
|
|
255
238
|
aria-role="adjustable"
|
|
256
|
-
// add hitSlop to make the bar easier to hit since it's small
|
|
257
|
-
hitSlop={{top: 20, bottom: 20, left: 50, right: 50}}
|
|
258
239
|
style={{
|
|
259
240
|
justifyContent: "center",
|
|
260
241
|
alignItems: "center",
|
|
@@ -267,33 +248,15 @@ export const Modal: FC<ModalProps> = ({
|
|
|
267
248
|
marginTop: 10,
|
|
268
249
|
}}
|
|
269
250
|
/>
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
</View>
|
|
251
|
+
<ModalContent {...modalContentProps}>{children}</ModalContent>
|
|
252
|
+
</View>
|
|
253
|
+
</PanGestureHandler>
|
|
274
254
|
</ActionSheet>
|
|
275
255
|
);
|
|
276
256
|
} else {
|
|
277
257
|
return (
|
|
278
258
|
<RNModal animationType="slide" transparent visible={visible} onRequestClose={handleDismiss}>
|
|
279
|
-
<
|
|
280
|
-
style={{
|
|
281
|
-
flex: 1,
|
|
282
|
-
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
283
|
-
justifyContent: "center",
|
|
284
|
-
alignItems: "center",
|
|
285
|
-
}}
|
|
286
|
-
onPress={persistOnBackgroundClick ? undefined : handleDismiss}
|
|
287
|
-
>
|
|
288
|
-
<Pressable
|
|
289
|
-
style={{cursor: "auto"}}
|
|
290
|
-
onPress={(e) => {
|
|
291
|
-
persistOnBackgroundClick ? null : e.stopPropagation();
|
|
292
|
-
}}
|
|
293
|
-
>
|
|
294
|
-
<ModalContent {...modalContentProps}>{children}</ModalContent>
|
|
295
|
-
</Pressable>
|
|
296
|
-
</Pressable>
|
|
259
|
+
<ModalContent {...modalContentProps}>{children}</ModalContent>
|
|
297
260
|
</RNModal>
|
|
298
261
|
);
|
|
299
262
|
}
|
package/src/ModalSheet.tsx
CHANGED
|
@@ -5,7 +5,7 @@ import {Modalize} from "react-native-modalize";
|
|
|
5
5
|
import {Portal} from "react-native-portalize";
|
|
6
6
|
|
|
7
7
|
export const useCombinedRefs = (...refs: any) => {
|
|
8
|
-
const targetRef = useRef();
|
|
8
|
+
const targetRef = useRef<any>(null);
|
|
9
9
|
|
|
10
10
|
// Iterate through the refs array, and set the ref.current value to the targetRef
|
|
11
11
|
useEffect(() => {
|
package/src/NumberField.tsx
CHANGED
|
@@ -24,8 +24,8 @@ export const NumberField: FC<NumberFieldProps> = ({
|
|
|
24
24
|
if (!v) {
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
const num = type === "number" ? parseInt(v
|
|
28
|
-
if (
|
|
27
|
+
const num = type === "number" ? parseInt(v) : parseFloat(v);
|
|
28
|
+
if (isNaN(num) || (type === "number" && v.match(/[^0-9]/) !== null)) {
|
|
29
29
|
return "Value must be an integer";
|
|
30
30
|
} else if (
|
|
31
31
|
(type === "decimal" && v.match(/[^0-9.]+/) !== null) ||
|
|
@@ -47,19 +47,13 @@ export const NumberField: FC<NumberFieldProps> = ({
|
|
|
47
47
|
// Only return the value if it is a valid number
|
|
48
48
|
const localOnChange = useCallback(
|
|
49
49
|
(v: string) => {
|
|
50
|
-
|
|
51
|
-
// if type is decimal and dot is the first character add 0 before it
|
|
52
|
-
setValue("0.");
|
|
53
|
-
rest.onChange("0.");
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
50
|
+
setValue(v);
|
|
56
51
|
const err = getError(v);
|
|
57
52
|
if (!err) {
|
|
58
|
-
setValue(v);
|
|
59
53
|
rest.onChange(v);
|
|
60
54
|
}
|
|
61
55
|
},
|
|
62
|
-
[getError, rest
|
|
56
|
+
[getError, rest]
|
|
63
57
|
);
|
|
64
58
|
|
|
65
59
|
return <TextField {...rest} errorText={error} value={value} onChange={localOnChange} />;
|
|
@@ -9,12 +9,16 @@ import {NumberPickerActionSheetProps} from "./Common";
|
|
|
9
9
|
|
|
10
10
|
const PICKER_HEIGHT = 104;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
interface NumberPickerActionSheetState {}
|
|
13
13
|
|
|
14
14
|
export class NumberPickerActionSheet extends React.Component<
|
|
15
15
|
NumberPickerActionSheetProps,
|
|
16
16
|
NumberPickerActionSheetState
|
|
17
17
|
> {
|
|
18
|
+
constructor(props: NumberPickerActionSheetProps) {
|
|
19
|
+
super(props);
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
render() {
|
|
19
23
|
return (
|
|
20
24
|
<ActionSheet ref={this.props.actionSheetRef} bounceOnOpen gestureEnabled>
|
package/src/Page.tsx
CHANGED
|
@@ -47,7 +47,7 @@ export class Page extends React.Component<PageProps, {}> {
|
|
|
47
47
|
<Button
|
|
48
48
|
text={this.props.rightButton}
|
|
49
49
|
variant="muted"
|
|
50
|
-
onClick={() => this.props.rightButtonOnClick
|
|
50
|
+
onClick={() => this.props.rightButtonOnClick && this.props.rightButtonOnClick()}
|
|
51
51
|
/>
|
|
52
52
|
</Box>
|
|
53
53
|
)}
|
package/src/Pagination.tsx
CHANGED
|
@@ -11,7 +11,12 @@ const PaginationButton: FC<{
|
|
|
11
11
|
onClick: () => void;
|
|
12
12
|
totalPages?: number;
|
|
13
13
|
page?: number;
|
|
14
|
-
}> = ({
|
|
14
|
+
}> = ({
|
|
15
|
+
type,
|
|
16
|
+
onClick,
|
|
17
|
+
totalPages = 1,
|
|
18
|
+
page = 1,
|
|
19
|
+
}) => {
|
|
15
20
|
let icon: IconName;
|
|
16
21
|
let disabled = false;
|
|
17
22
|
|
|
@@ -51,7 +56,11 @@ const PaginationNumber: FC<{
|
|
|
51
56
|
number: number | "more";
|
|
52
57
|
current: boolean;
|
|
53
58
|
onClick: () => void;
|
|
54
|
-
}> = ({
|
|
59
|
+
}> = ({
|
|
60
|
+
number,
|
|
61
|
+
current,
|
|
62
|
+
onClick,
|
|
63
|
+
}) => {
|
|
55
64
|
// Shortcut to make rendering the number buttons easier.
|
|
56
65
|
if (number === "more") {
|
|
57
66
|
return <PaginationButton type="more" onClick={() => {}} />;
|
package/src/Permissions.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// import Permissions from "react-native-permissions";
|
|
5
5
|
import {PermissionKind, PermissionStatus} from "./Common";
|
|
6
6
|
|
|
7
|
-
export async function requestPermissions(
|
|
8
|
-
return new Promise((
|
|
7
|
+
export async function requestPermissions(kind: PermissionKind): Promise<PermissionStatus> {
|
|
8
|
+
return new Promise(async (resolve, reject) => {
|
|
9
9
|
return "denied";
|
|
10
10
|
});
|
|
11
11
|
// const userPropertyKey = `PermissionsFor${capitalize(kind)}`;
|
package/src/PickerSelect.tsx
CHANGED
|
@@ -201,7 +201,7 @@ export function RNPickerSelect({
|
|
|
201
201
|
Keyboard.dismiss();
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
setAnimationType(modalProps?.animationType ? modalProps?.animationType : "slide");
|
|
204
|
+
setAnimationType(modalProps && modalProps?.animationType ? modalProps?.animationType : "slide");
|
|
205
205
|
|
|
206
206
|
triggerOpenCloseCallbacks();
|
|
207
207
|
|
package/src/SectionDivider.tsx
CHANGED
package/src/SegmentedControl.tsx
CHANGED
|
@@ -24,9 +24,7 @@ export const SegmentedControl: FC<SegmentedControlProps> = ({
|
|
|
24
24
|
}, []);
|
|
25
25
|
|
|
26
26
|
const handleNext = useCallback(() => {
|
|
27
|
-
setStartIndex((prev) =>
|
|
28
|
-
Math.min(items.length - (maxItems ?? items.length), prev + (maxItems ?? 4))
|
|
29
|
-
);
|
|
27
|
+
setStartIndex((prev) => Math.min(items.length - (maxItems ?? items.length), prev + (maxItems ?? 4)));
|
|
30
28
|
}, [items.length, maxItems]);
|
|
31
29
|
|
|
32
30
|
const visibleItems = maxItems ? items.slice(startIndex, startIndex + maxItems) : items;
|
package/src/Signature.native.tsx
CHANGED
|
@@ -21,14 +21,14 @@ export const Signature: FC<Props> = ({onChange, onStart, onEnd}: Props) => {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
const onBegin = () => {
|
|
24
|
-
onStart
|
|
24
|
+
onStart && onStart();
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
// Called after end of stroke. Kind of goofy if you ask me,
|
|
28
28
|
// but you need this in order to trigger the 'onOK' callback that gives us the actual image.
|
|
29
29
|
const handleEnd = () => {
|
|
30
30
|
ref.current?.readSignature();
|
|
31
|
-
onEnd
|
|
31
|
+
onEnd && onEnd();
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
return (
|
package/src/SignatureField.tsx
CHANGED
package/src/Slider.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import SliderComponent from "@react-native-community/slider";
|
|
2
2
|
import React, {FC} from "react";
|
|
3
|
+
import {View} from "react-native";
|
|
3
4
|
|
|
4
5
|
import {Box} from "./Box";
|
|
5
6
|
import {IconName, SliderProps, ValueMappingItem} from "./Common";
|
|
@@ -15,11 +16,11 @@ const getCurrentMapping = (map: ValueMappingItem[], value: number) => {
|
|
|
15
16
|
if (!map || map.length === 0) {
|
|
16
17
|
return null;
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
// Find the option with the closest value
|
|
20
21
|
let closestOption = map[0];
|
|
21
22
|
let closestDistance = Math.abs(value - closestOption.value);
|
|
22
|
-
|
|
23
|
+
|
|
23
24
|
for (const option of map) {
|
|
24
25
|
const distance = Math.abs(value - option.value);
|
|
25
26
|
if (distance < closestDistance) {
|
|
@@ -27,7 +28,7 @@ const getCurrentMapping = (map: ValueMappingItem[], value: number) => {
|
|
|
27
28
|
closestOption = option;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
return closestOption;
|
|
32
33
|
};
|
|
33
34
|
|
|
@@ -48,9 +49,9 @@ const getCenterContent = (
|
|
|
48
49
|
</Text>
|
|
49
50
|
);
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
+
|
|
52
53
|
const currentOption = getCurrentMapping(valueMapping, value);
|
|
53
|
-
|
|
54
|
+
|
|
54
55
|
if (useIcons) {
|
|
55
56
|
return (
|
|
56
57
|
<Icon
|
|
@@ -60,7 +61,7 @@ const getCenterContent = (
|
|
|
60
61
|
/>
|
|
61
62
|
);
|
|
62
63
|
}
|
|
63
|
-
|
|
64
|
+
|
|
64
65
|
return (
|
|
65
66
|
<Text align="center" color={disabled ? "secondaryLight" : "primary"} size="2xl">
|
|
66
67
|
{currentOption?.label}
|
|
@@ -71,7 +72,7 @@ const getCenterContent = (
|
|
|
71
72
|
const getSliderContent = (
|
|
72
73
|
slider: React.ReactElement,
|
|
73
74
|
inlineLabels: boolean,
|
|
74
|
-
labels?: SliderProps[
|
|
75
|
+
labels?: SliderProps['labels']
|
|
75
76
|
): React.ReactElement => {
|
|
76
77
|
if (inlineLabels && labels?.min && labels?.max) {
|
|
77
78
|
return (
|
|
@@ -153,9 +154,9 @@ export const Slider: FC<SliderProps> = ({
|
|
|
153
154
|
thumbStyle: {
|
|
154
155
|
width: 48,
|
|
155
156
|
height: 48,
|
|
156
|
-
backgroundColor:
|
|
157
|
+
backgroundColor: 'white',
|
|
157
158
|
borderRadius: 24,
|
|
158
|
-
shadowColor:
|
|
159
|
+
shadowColor: '#000',
|
|
159
160
|
shadowOffset: {
|
|
160
161
|
width: 0,
|
|
161
162
|
height: 2,
|
|
@@ -188,7 +189,11 @@ export const Slider: FC<SliderProps> = ({
|
|
|
188
189
|
<Box>
|
|
189
190
|
{Boolean(title) && <FieldTitle text={title!} />}
|
|
190
191
|
<Box direction="column" gap={showSelection ? 2 : 0}>
|
|
191
|
-
{showSelection &&
|
|
192
|
+
{showSelection && (
|
|
193
|
+
<Box alignItems="center">
|
|
194
|
+
{centerContent}
|
|
195
|
+
</Box>
|
|
196
|
+
)}
|
|
192
197
|
{sliderContent}
|
|
193
198
|
</Box>
|
|
194
199
|
{Boolean(helperText && !errorText) && <FieldHelperText text={helperText!} />}
|
|
@@ -196,3 +201,5 @@ export const Slider: FC<SliderProps> = ({
|
|
|
196
201
|
</Box>
|
|
197
202
|
);
|
|
198
203
|
};
|
|
204
|
+
|
|
205
|
+
|
package/src/SplitPage.native.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import {SplitPageProps} from "./Common";
|
|
|
9
9
|
import {FlatList} from "./FlatList";
|
|
10
10
|
import {IconButton} from "./IconButton";
|
|
11
11
|
import {Spinner} from "./Spinner";
|
|
12
|
+
import {useTheme} from "./Theme";
|
|
12
13
|
import {Unifier} from "./Unifier";
|
|
13
14
|
|
|
14
15
|
export const SplitPage = ({
|
|
@@ -25,6 +26,7 @@ export const SplitPage = ({
|
|
|
25
26
|
bottomNavBarHeight,
|
|
26
27
|
showItemList,
|
|
27
28
|
}: SplitPageProps) => {
|
|
29
|
+
const {theme} = useTheme();
|
|
28
30
|
const [selectedId, setSelectedId] = useState<number | undefined>(undefined);
|
|
29
31
|
|
|
30
32
|
// flattenChildren is necessary to pull children from a React Fragment. Without this,
|
|
@@ -90,7 +92,7 @@ export const SplitPage = ({
|
|
|
90
92
|
paddingBottom: bottomNavBarHeight,
|
|
91
93
|
}}
|
|
92
94
|
>
|
|
93
|
-
{renderListViewHeader
|
|
95
|
+
{renderListViewHeader && renderListViewHeader()}
|
|
94
96
|
<FlatList
|
|
95
97
|
data={listViewData}
|
|
96
98
|
extraData={listViewExtraData}
|
|
@@ -115,7 +117,7 @@ export const SplitPage = ({
|
|
|
115
117
|
onClick={() => onItemDeselect()}
|
|
116
118
|
/>
|
|
117
119
|
</Box>
|
|
118
|
-
{renderContent
|
|
120
|
+
{renderContent && renderContent(selectedId)}
|
|
119
121
|
</Box>
|
|
120
122
|
);
|
|
121
123
|
};
|