@chem-po/react-native 0.0.41 → 0.0.43
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/lib/commonjs/components/form/input/Editable.js +7 -4
- package/lib/commonjs/components/form/input/Editable.js.map +1 -1
- package/lib/commonjs/components/form/input/date/index.js +2 -2
- package/lib/commonjs/components/form/input/date/index.js.map +1 -1
- package/lib/commonjs/components/form/input/datetime/index.js +2 -2
- package/lib/commonjs/components/form/input/datetime/index.js.map +1 -1
- package/lib/commonjs/components/form/input/file/index.js +3 -2
- package/lib/commonjs/components/form/input/file/index.js.map +1 -1
- package/lib/commonjs/components/form/input/multipleSelect/index.js +8 -8
- package/lib/commonjs/components/form/input/multipleSelect/index.js.map +1 -1
- package/lib/commonjs/components/form/input/select/index.js +3 -6
- package/lib/commonjs/components/form/input/select/index.js.map +1 -1
- package/lib/commonjs/components/form/view/file.js +4 -2
- package/lib/commonjs/components/form/view/file.js.map +1 -1
- package/lib/commonjs/components/form/view/index.js +9 -3
- package/lib/commonjs/components/form/view/index.js.map +1 -1
- package/lib/commonjs/components/form/view/multipleSelect.js +7 -9
- package/lib/commonjs/components/form/view/multipleSelect.js.map +1 -1
- package/lib/commonjs/components/form/view/select.js +14 -11
- package/lib/commonjs/components/form/view/select.js.map +1 -1
- package/lib/commonjs/components/image/ImageViewModal.js +2 -1
- package/lib/commonjs/components/image/ImageViewModal.js.map +1 -1
- package/lib/commonjs/components/loading/CircularProgress.js +2 -1
- package/lib/commonjs/components/loading/CircularProgress.js.map +1 -1
- package/lib/commonjs/utils/downloadFile.js +34 -23
- package/lib/commonjs/utils/downloadFile.js.map +1 -1
- package/lib/commonjs/utils/downloadFileLegacy.js +64 -0
- package/lib/commonjs/utils/downloadFileLegacy.js.map +1 -0
- package/lib/module/components/form/input/Editable.js +7 -4
- package/lib/module/components/form/input/Editable.js.map +1 -1
- package/lib/module/components/form/input/date/index.js +2 -2
- package/lib/module/components/form/input/date/index.js.map +1 -1
- package/lib/module/components/form/input/datetime/index.js +2 -2
- package/lib/module/components/form/input/datetime/index.js.map +1 -1
- package/lib/module/components/form/input/file/index.js +3 -2
- package/lib/module/components/form/input/file/index.js.map +1 -1
- package/lib/module/components/form/input/multipleSelect/index.js +9 -9
- package/lib/module/components/form/input/multipleSelect/index.js.map +1 -1
- package/lib/module/components/form/input/select/index.js +4 -7
- package/lib/module/components/form/input/select/index.js.map +1 -1
- package/lib/module/components/form/view/file.js +4 -2
- package/lib/module/components/form/view/file.js.map +1 -1
- package/lib/module/components/form/view/index.js +9 -3
- package/lib/module/components/form/view/index.js.map +1 -1
- package/lib/module/components/form/view/multipleSelect.js +7 -9
- package/lib/module/components/form/view/multipleSelect.js.map +1 -1
- package/lib/module/components/form/view/select.js +13 -10
- package/lib/module/components/form/view/select.js.map +1 -1
- package/lib/module/components/image/ImageViewModal.js +2 -1
- package/lib/module/components/image/ImageViewModal.js.map +1 -1
- package/lib/module/components/loading/CircularProgress.js +3 -2
- package/lib/module/components/loading/CircularProgress.js.map +1 -1
- package/lib/module/utils/downloadFile.js +34 -22
- package/lib/module/utils/downloadFile.js.map +1 -1
- package/lib/module/utils/downloadFileLegacy.js +57 -0
- package/lib/module/utils/downloadFileLegacy.js.map +1 -0
- package/lib/typescript/components/form/input/Editable.d.ts +1 -1
- package/lib/typescript/components/form/input/Editable.d.ts.map +1 -1
- package/lib/typescript/components/form/input/file/index.d.ts +3 -2
- package/lib/typescript/components/form/input/file/index.d.ts.map +1 -1
- package/lib/typescript/components/form/input/multipleSelect/index.d.ts.map +1 -1
- package/lib/typescript/components/form/input/select/index.d.ts.map +1 -1
- package/lib/typescript/components/form/view/file.d.ts +3 -2
- package/lib/typescript/components/form/view/file.d.ts.map +1 -1
- package/lib/typescript/components/form/view/index.d.ts +3 -2
- package/lib/typescript/components/form/view/index.d.ts.map +1 -1
- package/lib/typescript/components/form/view/multipleSelect.d.ts +6 -3
- package/lib/typescript/components/form/view/multipleSelect.d.ts.map +1 -1
- package/lib/typescript/components/form/view/select.d.ts +10 -6
- package/lib/typescript/components/form/view/select.d.ts.map +1 -1
- package/lib/typescript/components/image/ImageViewModal.d.ts.map +1 -1
- package/lib/typescript/components/loading/CircularProgress.d.ts.map +1 -1
- package/lib/typescript/utils/downloadFile.d.ts.map +1 -1
- package/lib/typescript/utils/downloadFileLegacy.d.ts +4 -0
- package/lib/typescript/utils/downloadFileLegacy.d.ts.map +1 -0
- package/package.json +27 -27
- package/src/components/form/input/Editable.tsx +5 -4
- package/src/components/form/input/date/index.tsx +2 -2
- package/src/components/form/input/datetime/index.tsx +2 -2
- package/src/components/form/input/file/index.tsx +4 -2
- package/src/components/form/input/multipleSelect/index.tsx +5 -6
- package/src/components/form/input/select/index.tsx +7 -12
- package/src/components/form/view/file.tsx +5 -3
- package/src/components/form/view/index.tsx +17 -3
- package/src/components/form/view/multipleSelect.tsx +13 -11
- package/src/components/form/view/select.tsx +24 -16
- package/src/components/image/ImageViewModal.tsx +2 -1
- package/src/components/loading/CircularProgress.tsx +3 -2
- package/src/utils/downloadFile.ts +35 -20
- package/src/utils/downloadFileLegacy.ts +66 -0
|
@@ -6,7 +6,7 @@ import { StyleSheet, Text, View } from 'react-native'
|
|
|
6
6
|
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
|
|
7
7
|
import { Portal } from 'react-native-paper'
|
|
8
8
|
import { DatePickerModal } from 'react-native-paper-dates'
|
|
9
|
-
import {
|
|
9
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
10
10
|
import { FieldProps } from '../../types'
|
|
11
11
|
import { DateInputClearButton } from '../common/InputClearButton'
|
|
12
12
|
import { useInputColor } from '../hooks/useInputColor'
|
|
@@ -55,7 +55,7 @@ export const DateInput = forwardRef<InputRef, FieldProps<DateField>>(
|
|
|
55
55
|
const maxDateObj = maxDate === 'now' ? new Date() : maxDate ? new Date(maxDate) : undefined
|
|
56
56
|
|
|
57
57
|
const mainTap = Gesture.Tap().onStart(() => {
|
|
58
|
-
|
|
58
|
+
scheduleOnRN(onFocus)
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
return (
|
|
@@ -6,7 +6,7 @@ import { StyleSheet, Text, View } from 'react-native'
|
|
|
6
6
|
import { Gesture, GestureDetector, Pressable } from 'react-native-gesture-handler'
|
|
7
7
|
import { Portal } from 'react-native-paper'
|
|
8
8
|
import { DatePickerModal, TimePickerModal } from 'react-native-paper-dates'
|
|
9
|
-
import {
|
|
9
|
+
import { scheduleOnRN } from 'react-native-worklets'
|
|
10
10
|
import { FieldProps } from '../../types'
|
|
11
11
|
import { DateInputClearButton } from '../common/InputClearButton'
|
|
12
12
|
import { useInputColor } from '../hooks/useInputColor'
|
|
@@ -96,7 +96,7 @@ export const DateTimeInput = forwardRef<InputRef, FieldProps<DateTimeField>>(
|
|
|
96
96
|
const inputColor = useInputColor(value)
|
|
97
97
|
|
|
98
98
|
const mainTap = Gesture.Tap().onStart(() => {
|
|
99
|
-
|
|
99
|
+
scheduleOnRN(handleFocusDate)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
102
|
return (
|
|
@@ -13,7 +13,7 @@ import { Ionicons } from '@expo/vector-icons'
|
|
|
13
13
|
import * as DocumentPicker from 'expo-document-picker'
|
|
14
14
|
import * as ImagePicker from 'expo-image-picker'
|
|
15
15
|
import React, { forwardRef, useCallback, useImperativeHandle, useMemo } from 'react'
|
|
16
|
-
import { Platform, StyleProp, StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
16
|
+
import { Platform, StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
|
|
17
17
|
import { Pressable } from 'react-native-gesture-handler'
|
|
18
18
|
import { downloadFile } from '../../../../utils/downloadFile'
|
|
19
19
|
import { LoadingImage } from '../../../loading/LoadingImage'
|
|
@@ -56,6 +56,7 @@ export const FileView = ({
|
|
|
56
56
|
nonImageContainerStyle,
|
|
57
57
|
withDownload,
|
|
58
58
|
onUploadPress,
|
|
59
|
+
textStyle,
|
|
59
60
|
}: {
|
|
60
61
|
value?: FileValue | null
|
|
61
62
|
hasUpload?: boolean
|
|
@@ -64,6 +65,7 @@ export const FileView = ({
|
|
|
64
65
|
nonImageContainerStyle?: StyleProp<ViewStyle>
|
|
65
66
|
withDownload?: boolean
|
|
66
67
|
onUploadPress?: () => void
|
|
68
|
+
textStyle?: StyleProp<TextStyle>
|
|
67
69
|
}) => {
|
|
68
70
|
const { storagePath, dataUrl } = value ?? {}
|
|
69
71
|
const missingFile = !dataUrl && !storagePath
|
|
@@ -131,7 +133,7 @@ export const FileView = ({
|
|
|
131
133
|
<Ionicons name="document" size={24} color={iconColor} />
|
|
132
134
|
</View>
|
|
133
135
|
<View style={styles.filenameContainer}>
|
|
134
|
-
<Text numberOfLines={1} style={[styles.filename, { color: fileNameColor }]}>
|
|
136
|
+
<Text numberOfLines={1} style={[styles.filename, { color: fileNameColor }, textStyle]}>
|
|
135
137
|
{value.filename}
|
|
136
138
|
</Text>
|
|
137
139
|
</View>
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
useBackgroundColor,
|
|
5
5
|
useBorderColor,
|
|
6
6
|
useColorMode,
|
|
7
|
-
useColorModeValue,
|
|
8
7
|
useIconColor,
|
|
9
8
|
usePlaceholderColor,
|
|
10
9
|
useTextColor,
|
|
@@ -58,7 +57,7 @@ const BaseMultipleSelectComponent = <T extends MultipleSelectField>(
|
|
|
58
57
|
const placeholderColor = usePlaceholderColor()
|
|
59
58
|
const menuBg = useBackgroundColor(100)
|
|
60
59
|
const inputBg = useBackgroundColor(50)
|
|
61
|
-
const selectedOptionBg =
|
|
60
|
+
const selectedOptionBg = useBackgroundColor(50)
|
|
62
61
|
const borderColor = useBorderColor()
|
|
63
62
|
|
|
64
63
|
useImperativeHandle(ref, () => ({
|
|
@@ -86,7 +85,7 @@ const BaseMultipleSelectComponent = <T extends MultipleSelectField>(
|
|
|
86
85
|
return RenderOption(props)
|
|
87
86
|
}
|
|
88
87
|
return (
|
|
89
|
-
<View style={{
|
|
88
|
+
<View style={[container, { width: 'auto' }]}>
|
|
90
89
|
<Txt style={[text]}>{props.option.label}</Txt>
|
|
91
90
|
</View>
|
|
92
91
|
)
|
|
@@ -100,11 +99,11 @@ const BaseMultipleSelectComponent = <T extends MultipleSelectField>(
|
|
|
100
99
|
<View style={[styles.wrapper]}>
|
|
101
100
|
<MultiSelect
|
|
102
101
|
ref={inputRef}
|
|
103
|
-
style={[container, { borderColor,
|
|
102
|
+
style={[container, { borderColor, borderBottomWidth: 1, borderRadius: 0 }]}
|
|
104
103
|
placeholderStyle={[text, { color: value?.length ? textColor : placeholderColor }]}
|
|
105
104
|
containerStyle={{
|
|
106
105
|
backgroundColor: menuBg,
|
|
107
|
-
boxShadow: `0 0
|
|
106
|
+
boxShadow: `0 0 10px #00000066`,
|
|
108
107
|
borderWidth: 0,
|
|
109
108
|
}}
|
|
110
109
|
inputSearchStyle={[styles.inputSearch, text, { backgroundColor: inputBg, borderWidth: 0 }]}
|
|
@@ -133,7 +132,7 @@ const BaseMultipleSelectComponent = <T extends MultipleSelectField>(
|
|
|
133
132
|
renderItem={(item, selected) => (
|
|
134
133
|
<View
|
|
135
134
|
style={{
|
|
136
|
-
backgroundColor: selected ? selectedOptionBg :
|
|
135
|
+
backgroundColor: selected ? selectedOptionBg : menuBg,
|
|
137
136
|
paddingVertical: 8,
|
|
138
137
|
paddingHorizontal: 12,
|
|
139
138
|
flexDirection: 'row',
|
|
@@ -2,7 +2,6 @@ import { InputRef, RenderSelectOptionProps } from '@chem-po/core'
|
|
|
2
2
|
import {
|
|
3
3
|
SelectField,
|
|
4
4
|
useBackgroundColor,
|
|
5
|
-
useBorderColor,
|
|
6
5
|
useColorMode,
|
|
7
6
|
useIconColor,
|
|
8
7
|
usePlaceholderColor,
|
|
@@ -33,14 +32,11 @@ const BaseSelectComponent = <T extends SelectField>(
|
|
|
33
32
|
const colorMode = useColorMode()
|
|
34
33
|
|
|
35
34
|
const inputRef = useRef<IDropdownRef>(null)
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
clearButtonSize,
|
|
42
|
-
buttonContainer,
|
|
43
|
-
} = useInputStyles(inEditable, field.size, formSize)
|
|
35
|
+
const { container, iconSize, text, size, clearButtonSize, buttonContainer } = useInputStyles(
|
|
36
|
+
inEditable,
|
|
37
|
+
field.size,
|
|
38
|
+
formSize,
|
|
39
|
+
)
|
|
44
40
|
|
|
45
41
|
useImperativeHandle(ref, () => ({
|
|
46
42
|
focus: () => {
|
|
@@ -64,19 +60,18 @@ const BaseSelectComponent = <T extends SelectField>(
|
|
|
64
60
|
const placeholderColor = usePlaceholderColor()
|
|
65
61
|
const menuBg = useBackgroundColor(100)
|
|
66
62
|
const selectedOptionBg = useBackgroundColor(50)
|
|
67
|
-
const borderColor = useBorderColor()
|
|
68
63
|
|
|
69
64
|
return (
|
|
70
65
|
<View style={styles.wrapper}>
|
|
71
66
|
<Dropdown
|
|
72
67
|
ref={inputRef}
|
|
73
|
-
style={
|
|
68
|
+
style={container}
|
|
74
69
|
placeholderStyle={[text, { color: placeholderColor }]}
|
|
75
70
|
containerStyle={{
|
|
76
71
|
backgroundColor: menuBg,
|
|
77
72
|
borderWidth: 0,
|
|
78
73
|
borderColor: 'transparent',
|
|
79
|
-
boxShadow: `0 0 10px
|
|
74
|
+
boxShadow: `0 0 10px #00000066`,
|
|
80
75
|
}}
|
|
81
76
|
selectedTextStyle={text}
|
|
82
77
|
inputSearchStyle={[
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageViewOptions, InputSize } from '@chem-po/core'
|
|
2
2
|
import { FileField, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import React, { useMemo } from 'react'
|
|
4
|
-
import { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
4
|
+
import { StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
|
|
5
5
|
import { Txt } from '../../text/Txt'
|
|
6
6
|
import { FileView } from '../input/file'
|
|
7
7
|
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
@@ -42,11 +42,13 @@ export const FileFieldView = ({
|
|
|
42
42
|
noLabel,
|
|
43
43
|
style,
|
|
44
44
|
size: sizeProp,
|
|
45
|
+
textStyle,
|
|
45
46
|
}: {
|
|
46
47
|
field: FileField
|
|
47
48
|
value: any
|
|
48
49
|
noLabel?: boolean
|
|
49
50
|
style?: ViewStyle
|
|
51
|
+
textStyle?: StyleProp<TextStyle>
|
|
50
52
|
size?: InputSize
|
|
51
53
|
}) => {
|
|
52
54
|
const { imageOptions, placeholder, size } = field
|
|
@@ -66,11 +68,11 @@ export const FileFieldView = ({
|
|
|
66
68
|
{!noLabel && <Text style={styles.label}>{placeholder}</Text>}
|
|
67
69
|
{value ? (
|
|
68
70
|
<View style={styles.fileContainer}>
|
|
69
|
-
<FileView imageOptions={options} value={value} />
|
|
71
|
+
<FileView textStyle={textStyle} imageOptions={options} value={value} />
|
|
70
72
|
</View>
|
|
71
73
|
) : (
|
|
72
74
|
<View style={container}>
|
|
73
|
-
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
75
|
+
<Txt style={[text, { color: placeholderColor }, textStyle]}>None</Txt>
|
|
74
76
|
</View>
|
|
75
77
|
)}
|
|
76
78
|
</View>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { displayField, InputSize } from '@chem-po/core'
|
|
2
2
|
import { Field, FormatField, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import React, { useMemo } from 'react'
|
|
4
|
-
import { StyleSheet, View, ViewStyle } from 'react-native'
|
|
4
|
+
import { StyleProp, StyleSheet, TextStyle, View, ViewStyle } from 'react-native'
|
|
5
5
|
import { Txt } from '../../text'
|
|
6
6
|
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
7
7
|
import { FileFieldView } from './file'
|
|
@@ -23,11 +23,13 @@ const DefaultFieldView = ({
|
|
|
23
23
|
style,
|
|
24
24
|
size: sizeProp,
|
|
25
25
|
inEditable,
|
|
26
|
+
textStyle,
|
|
26
27
|
}: {
|
|
27
28
|
field: Field
|
|
28
29
|
value: any
|
|
29
30
|
noLabel?: boolean
|
|
30
31
|
style?: ViewStyle
|
|
32
|
+
textStyle?: StyleProp<TextStyle>
|
|
31
33
|
size?: InputSize
|
|
32
34
|
inEditable?: boolean
|
|
33
35
|
}) => {
|
|
@@ -48,7 +50,7 @@ const DefaultFieldView = ({
|
|
|
48
50
|
return (
|
|
49
51
|
<View style={[styles.container, containerStyles, { backgroundColor: 'transparent' }, style]}>
|
|
50
52
|
{!noLabel && <Txt style={[inputViewStyles.label, text]}>{placeholder}</Txt>}
|
|
51
|
-
<Txt style={[text, { color: hasValue ?
|
|
53
|
+
<Txt style={[text, { color: hasValue ? text.color : placeholderColor }, textStyle]}>
|
|
52
54
|
{hasValue ? formatted : 'None'}
|
|
53
55
|
</Txt>
|
|
54
56
|
</View>
|
|
@@ -60,6 +62,7 @@ export const FieldView = ({
|
|
|
60
62
|
value,
|
|
61
63
|
noLabel,
|
|
62
64
|
style,
|
|
65
|
+
textStyle,
|
|
63
66
|
size,
|
|
64
67
|
inEditable,
|
|
65
68
|
}: {
|
|
@@ -67,6 +70,7 @@ export const FieldView = ({
|
|
|
67
70
|
value?: any
|
|
68
71
|
noLabel?: boolean
|
|
69
72
|
style?: ViewStyle
|
|
73
|
+
textStyle?: StyleProp<TextStyle>
|
|
70
74
|
size?: InputSize
|
|
71
75
|
inEditable?: boolean
|
|
72
76
|
}) => {
|
|
@@ -75,6 +79,7 @@ export const FieldView = ({
|
|
|
75
79
|
return (
|
|
76
80
|
<SelectFieldView
|
|
77
81
|
style={style}
|
|
82
|
+
textStyle={textStyle}
|
|
78
83
|
field={field}
|
|
79
84
|
value={value}
|
|
80
85
|
noLabel={noLabel}
|
|
@@ -88,13 +93,21 @@ export const FieldView = ({
|
|
|
88
93
|
style={style}
|
|
89
94
|
field={field}
|
|
90
95
|
value={value}
|
|
96
|
+
textStyle={textStyle}
|
|
91
97
|
noLabel={noLabel}
|
|
92
98
|
size={size}
|
|
93
99
|
/>
|
|
94
100
|
)
|
|
95
101
|
case 'file':
|
|
96
102
|
return (
|
|
97
|
-
<FileFieldView
|
|
103
|
+
<FileFieldView
|
|
104
|
+
textStyle={textStyle}
|
|
105
|
+
style={style}
|
|
106
|
+
field={field}
|
|
107
|
+
value={value}
|
|
108
|
+
noLabel={noLabel}
|
|
109
|
+
size={size}
|
|
110
|
+
/>
|
|
98
111
|
)
|
|
99
112
|
default:
|
|
100
113
|
return (
|
|
@@ -102,6 +115,7 @@ export const FieldView = ({
|
|
|
102
115
|
style={style}
|
|
103
116
|
field={field}
|
|
104
117
|
value={value}
|
|
118
|
+
textStyle={textStyle}
|
|
105
119
|
noLabel={noLabel}
|
|
106
120
|
size={size}
|
|
107
121
|
inEditable={inEditable}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { InputSize } from '@chem-po/core'
|
|
1
|
+
import { BaseSelectOption, InputSize } from '@chem-po/core'
|
|
2
2
|
import { MultipleSelectField, useColorMode, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import { useMemo } from 'react'
|
|
4
|
-
import React, { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
4
|
+
import React, { StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
|
|
5
5
|
import { Txt } from '../../text/Txt'
|
|
6
6
|
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
7
7
|
import { SelectedOptionContainer } from '../input/multipleSelect'
|
|
@@ -31,16 +31,23 @@ const styles = StyleSheet.create({
|
|
|
31
31
|
},
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
type NativeMultipleSelectField<
|
|
35
|
+
Value extends any[] = string[],
|
|
36
|
+
Option extends BaseSelectOption<Value[number]> = BaseSelectOption<Value[number]>,
|
|
37
|
+
> = MultipleSelectField<Value, Option>
|
|
38
|
+
|
|
39
|
+
export const MultipleSelectFieldView = <F extends NativeMultipleSelectField>({
|
|
35
40
|
field,
|
|
36
41
|
value,
|
|
37
42
|
noLabel,
|
|
38
43
|
size: sizeProp,
|
|
39
44
|
style,
|
|
45
|
+
textStyle,
|
|
40
46
|
}: {
|
|
41
47
|
field: F
|
|
42
48
|
value?: F['defaultValue']
|
|
43
49
|
noLabel?: boolean
|
|
50
|
+
textStyle?: StyleProp<TextStyle>
|
|
44
51
|
size?: InputSize
|
|
45
52
|
style?: ViewStyle
|
|
46
53
|
}) => {
|
|
@@ -49,12 +56,6 @@ export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
|
49
56
|
const colorMode = useColorMode()
|
|
50
57
|
const { size, text, container } = useInputStyles(true, field.size, sizeProp)
|
|
51
58
|
const placeholderColor = usePlaceholderColor()
|
|
52
|
-
const selectedOptionStyle = useMemo<ViewStyle>(() => {
|
|
53
|
-
return {
|
|
54
|
-
paddingHorizontal: container.paddingHorizontal,
|
|
55
|
-
paddingVertical: container.paddingVertical,
|
|
56
|
-
}
|
|
57
|
-
}, [container])
|
|
58
59
|
const RenderOption = useMemo(() => customRender ?? DefaultRenderOption, [customRender])
|
|
59
60
|
return (
|
|
60
61
|
<View style={[styles.container, style]}>
|
|
@@ -62,10 +63,11 @@ export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
|
62
63
|
{value?.length ? (
|
|
63
64
|
<View style={styles.optionsContainer}>
|
|
64
65
|
{selectedOptions.map(o => (
|
|
65
|
-
<SelectedOptionContainer key={o.value} style={
|
|
66
|
+
<SelectedOptionContainer key={o.value} style={[container, { width: 'auto' }]}>
|
|
66
67
|
<RenderOption
|
|
67
68
|
option={o}
|
|
68
69
|
value={o.value}
|
|
70
|
+
textStyle={[text, textStyle]}
|
|
69
71
|
colorMode={colorMode}
|
|
70
72
|
isSelected
|
|
71
73
|
size={size}
|
|
@@ -75,7 +77,7 @@ export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
|
75
77
|
</View>
|
|
76
78
|
) : (
|
|
77
79
|
<View style={container}>
|
|
78
|
-
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
80
|
+
<Txt style={[text, { color: placeholderColor }, textStyle]}>None</Txt>
|
|
79
81
|
</View>
|
|
80
82
|
)}
|
|
81
83
|
</View>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InputSize, RenderSelectOptionProps } from '@chem-po/core'
|
|
2
2
|
import { SelectField, useColorMode, usePlaceholderColor } from '@chem-po/react'
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
3
|
+
import React, { useMemo } from 'react'
|
|
4
|
+
import { StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
|
|
5
5
|
import { Txt } from '../../text'
|
|
6
6
|
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
7
7
|
import { inputViewStyles } from './styles'
|
|
@@ -18,31 +18,35 @@ const styles = StyleSheet.create({
|
|
|
18
18
|
},
|
|
19
19
|
})
|
|
20
20
|
|
|
21
|
-
export const DefaultRenderOption =
|
|
22
|
-
Value = string,
|
|
23
|
-
Option extends BaseSelectOption<Value> = BaseSelectOption<Value>,
|
|
24
|
-
>({
|
|
21
|
+
export const DefaultRenderOption = ({
|
|
25
22
|
option,
|
|
26
|
-
|
|
23
|
+
containerStyle,
|
|
24
|
+
textStyle,
|
|
25
|
+
}: RenderSelectOptionProps & {
|
|
26
|
+
containerStyle?: StyleProp<ViewStyle>
|
|
27
|
+
textStyle?: StyleProp<TextStyle>
|
|
28
|
+
}) => {
|
|
27
29
|
return (
|
|
28
|
-
<View style={
|
|
29
|
-
<Txt style={inputViewStyles.value}>{option.label}</Txt>
|
|
30
|
+
<View style={containerStyle}>
|
|
31
|
+
<Txt style={[inputViewStyles.value, textStyle]}>{option.label}</Txt>
|
|
30
32
|
</View>
|
|
31
33
|
)
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export const SelectFieldView = ({
|
|
36
|
+
export const SelectFieldView = <F extends SelectField>({
|
|
35
37
|
field,
|
|
36
38
|
value,
|
|
37
39
|
noLabel,
|
|
38
40
|
style,
|
|
39
41
|
size: sizeProp,
|
|
40
42
|
inEditable,
|
|
43
|
+
textStyle,
|
|
41
44
|
}: {
|
|
42
|
-
field:
|
|
43
|
-
value:
|
|
45
|
+
field: F
|
|
46
|
+
value: F['defaultValue']
|
|
44
47
|
noLabel?: boolean
|
|
45
48
|
style?: ViewStyle
|
|
49
|
+
textStyle?: StyleProp<TextStyle>
|
|
46
50
|
size?: InputSize
|
|
47
51
|
inEditable?: boolean
|
|
48
52
|
}) => {
|
|
@@ -51,23 +55,27 @@ export const SelectFieldView = ({
|
|
|
51
55
|
const placeholderColor = usePlaceholderColor()
|
|
52
56
|
const { size, text, container } = useInputStyles(inEditable, field.size, sizeProp)
|
|
53
57
|
const selectedOption = field.options.find(o => o.value === value)
|
|
54
|
-
const RenderOption = customRender ?? DefaultRenderOption
|
|
58
|
+
const RenderOption = useMemo(() => customRender ?? DefaultRenderOption, [customRender])
|
|
55
59
|
return (
|
|
56
60
|
<View style={[styles.container, style]}>
|
|
57
61
|
{!noLabel && (
|
|
58
|
-
<Text style={[styles.label, text, { color: placeholderColor }]}>
|
|
62
|
+
<Text style={[styles.label, text, { color: placeholderColor }, textStyle]}>
|
|
63
|
+
{placeholder}
|
|
64
|
+
</Text>
|
|
59
65
|
)}
|
|
60
66
|
{selectedOption ? (
|
|
61
67
|
<RenderOption
|
|
62
68
|
value={selectedOption.value}
|
|
63
69
|
option={selectedOption}
|
|
70
|
+
containerStyle={container}
|
|
71
|
+
textStyle={[text, textStyle]}
|
|
64
72
|
colorMode={colorMode}
|
|
65
73
|
isSelected={true}
|
|
66
74
|
size={size}
|
|
67
75
|
/>
|
|
68
76
|
) : (
|
|
69
77
|
<View style={container}>
|
|
70
|
-
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
78
|
+
<Txt style={[text, { color: placeholderColor }, textStyle]}>None</Txt>
|
|
71
79
|
</View>
|
|
72
80
|
)}
|
|
73
81
|
</View>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useScreen, useToast } from '@chem-po/react'
|
|
2
2
|
import { Ionicons } from '@expo/vector-icons'
|
|
3
3
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
|
4
|
-
import { Image, Modal, Platform,
|
|
4
|
+
import { Image, Modal, Platform, StyleSheet, View } from 'react-native'
|
|
5
5
|
import {
|
|
6
6
|
Gesture,
|
|
7
7
|
GestureDetector,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Pressable,
|
|
10
10
|
} from 'react-native-gesture-handler'
|
|
11
11
|
import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated'
|
|
12
|
+
import { SafeAreaView } from 'react-native-safe-area-context'
|
|
12
13
|
import { downloadFile } from '../../utils/downloadFile'
|
|
13
14
|
import { LoadingLogo } from '../loading/Loading'
|
|
14
15
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useColorModeValue } from '@chem-po/react'
|
|
1
|
+
import { useBackgroundColor, useColorModeValue } from '@chem-po/react'
|
|
2
2
|
import React, { useEffect, useRef } from 'react'
|
|
3
3
|
import {
|
|
4
4
|
ActivityIndicator,
|
|
@@ -24,6 +24,7 @@ export const CircularProgress = ({
|
|
|
24
24
|
...props
|
|
25
25
|
}: CircularProgressProps) => {
|
|
26
26
|
const defaultTrackColor = useColorModeValue('#959595', '#575757')
|
|
27
|
+
const defaultColor = useBackgroundColor(750)
|
|
27
28
|
const opacity = useRef(new Animated.Value(visible ? 1 : 0)).current
|
|
28
29
|
|
|
29
30
|
useEffect(() => {
|
|
@@ -42,7 +43,7 @@ export const CircularProgress = ({
|
|
|
42
43
|
{...props}
|
|
43
44
|
/>
|
|
44
45
|
{/* Spinning circle */}
|
|
45
|
-
<ActivityIndicator animating={animating} color={color ??
|
|
46
|
+
<ActivityIndicator animating={animating} color={color ?? defaultColor} {...props} />
|
|
46
47
|
</Animated.View>
|
|
47
48
|
)
|
|
48
49
|
}
|
|
@@ -1,46 +1,61 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { Directory, File, Paths } from 'expo-file-system'
|
|
2
|
+
import { StorageAccessFramework } from 'expo-file-system/legacy'
|
|
3
3
|
import { shareAsync } from 'expo-sharing'
|
|
4
4
|
import { Platform } from 'react-native'
|
|
5
5
|
|
|
6
6
|
export const downloadFile = async (uri: string, filename: string, fileType: string) => {
|
|
7
7
|
if (Platform.OS === 'android') {
|
|
8
|
-
const permissions = await
|
|
8
|
+
const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync()
|
|
9
9
|
if (!permissions.granted) {
|
|
10
10
|
throw new Error('Permission not granted')
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
const
|
|
13
|
+
// Create cache directory for temporary file
|
|
14
|
+
const cacheDir = new Directory(Paths.cache)
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
|
|
16
|
+
// Ensure cache directory exists
|
|
17
|
+
if (!cacheDir.exists) {
|
|
18
|
+
cacheDir.create()
|
|
19
|
+
}
|
|
18
20
|
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// Download the file to cache directory using static method
|
|
22
|
+
const downloadedFile = await File.downloadFileAsync(uri, cacheDir)
|
|
23
|
+
|
|
24
|
+
// Read the downloaded file as bytes and convert to base64
|
|
25
|
+
const fileBytes = await downloadedFile.bytes()
|
|
26
|
+
|
|
27
|
+
// Convert Uint8Array to base64 safely (handles large files better than btoa)
|
|
28
|
+
const base64Content = Array.from(fileBytes, byte => String.fromCharCode(byte)).join('')
|
|
29
|
+
const encodedContent = btoa(base64Content)
|
|
23
30
|
|
|
24
31
|
// Create a file within the selected directory using SAF
|
|
25
|
-
const fileUri = await
|
|
32
|
+
const fileUri = await StorageAccessFramework.createFileAsync(
|
|
26
33
|
permissions.directoryUri,
|
|
27
34
|
filename,
|
|
28
35
|
fileType,
|
|
29
36
|
)
|
|
30
37
|
|
|
31
|
-
// Write the content to the SAF file
|
|
32
|
-
await
|
|
33
|
-
encoding:
|
|
38
|
+
// Write the content to the SAF file using legacy method (as SAF might not have new API yet)
|
|
39
|
+
await StorageAccessFramework.writeAsStringAsync(fileUri, encodedContent, {
|
|
40
|
+
encoding: 'base64',
|
|
34
41
|
})
|
|
35
42
|
|
|
36
43
|
// Clean up temporary file
|
|
37
|
-
|
|
44
|
+
downloadedFile.delete()
|
|
38
45
|
|
|
39
46
|
return { uri: fileUri }
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
|
|
49
|
+
// For iOS and other platforms
|
|
50
|
+
const documentsDir = new Directory(Paths.document)
|
|
51
|
+
|
|
52
|
+
// Ensure documents directory exists
|
|
53
|
+
if (!documentsDir.exists) {
|
|
54
|
+
documentsDir.create()
|
|
43
55
|
}
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
|
|
57
|
+
// Download file directly to documents directory
|
|
58
|
+
const downloadedFile = await File.downloadFileAsync(uri, documentsDir)
|
|
59
|
+
|
|
60
|
+
return shareAsync(downloadedFile.uri)
|
|
46
61
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cacheDirectory,
|
|
3
|
+
deleteAsync,
|
|
4
|
+
documentDirectory,
|
|
5
|
+
downloadAsync,
|
|
6
|
+
EncodingType,
|
|
7
|
+
readAsStringAsync,
|
|
8
|
+
StorageAccessFramework,
|
|
9
|
+
} from 'expo-file-system/legacy'
|
|
10
|
+
import { shareAsync } from 'expo-sharing'
|
|
11
|
+
import { Platform } from 'react-native'
|
|
12
|
+
|
|
13
|
+
export const downloadFileLegacy = async (uri: string, filename: string, fileType: string) => {
|
|
14
|
+
if (Platform.OS === 'android') {
|
|
15
|
+
const permissions = await StorageAccessFramework.requestDirectoryPermissionsAsync()
|
|
16
|
+
if (!permissions.granted) {
|
|
17
|
+
throw new Error('Permission not granted')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Download to temporary location first
|
|
21
|
+
const tempFileUri = `${cacheDirectory}${filename}`
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
// Download the file to temporary location
|
|
25
|
+
await downloadAsync(uri, tempFileUri)
|
|
26
|
+
|
|
27
|
+
// Read the temporary file as base64
|
|
28
|
+
const base64Content = await readAsStringAsync(tempFileUri, {
|
|
29
|
+
encoding: EncodingType.Base64,
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Create a file within the selected directory using SAF
|
|
33
|
+
const fileUri = await StorageAccessFramework.createFileAsync(
|
|
34
|
+
permissions.directoryUri,
|
|
35
|
+
filename,
|
|
36
|
+
fileType,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
// Write the content to the SAF file
|
|
40
|
+
await StorageAccessFramework.writeAsStringAsync(fileUri, base64Content, {
|
|
41
|
+
encoding: EncodingType.Base64,
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// Clean up temporary file
|
|
45
|
+
await deleteAsync(tempFileUri, { idempotent: true })
|
|
46
|
+
|
|
47
|
+
return { uri: fileUri }
|
|
48
|
+
} catch (error) {
|
|
49
|
+
// Clean up temporary file in case of error
|
|
50
|
+
try {
|
|
51
|
+
await deleteAsync(tempFileUri, { idempotent: true })
|
|
52
|
+
} catch {
|
|
53
|
+
// Ignore cleanup errors
|
|
54
|
+
}
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// For iOS and other platforms
|
|
60
|
+
if (!documentDirectory) {
|
|
61
|
+
throw new Error('Document directory not found')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const result = await downloadAsync(uri, documentDirectory + filename)
|
|
65
|
+
return shareAsync(result.uri)
|
|
66
|
+
}
|