@chem-po/react-native 0.0.28 → 0.0.30
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/button/Toggle.js +19 -16
- package/lib/commonjs/components/button/Toggle.js.map +1 -1
- package/lib/commonjs/components/form/input/Editable.js +62 -93
- package/lib/commonjs/components/form/input/Editable.js.map +1 -1
- package/lib/commonjs/components/form/input/StandaloneInput.js +5 -1
- package/lib/commonjs/components/form/input/StandaloneInput.js.map +1 -1
- package/lib/commonjs/components/form/input/datetime/index.js +7 -2
- package/lib/commonjs/components/form/input/datetime/index.js.map +1 -1
- package/lib/commonjs/components/form/input/hooks/useInputStyles.js +2 -1
- package/lib/commonjs/components/form/input/hooks/useInputStyles.js.map +1 -1
- package/lib/commonjs/components/form/input/multipleSelect/index.js +25 -11
- package/lib/commonjs/components/form/input/multipleSelect/index.js.map +1 -1
- package/lib/commonjs/components/form/input/number/index.js +8 -4
- package/lib/commonjs/components/form/input/number/index.js.map +1 -1
- package/lib/commonjs/components/form/input/select/index.js +13 -3
- package/lib/commonjs/components/form/input/select/index.js.map +1 -1
- package/lib/commonjs/components/form/input/text/AutoResizeTextarea.js +54 -0
- package/lib/commonjs/components/form/input/text/AutoResizeTextarea.js.map +1 -0
- package/lib/commonjs/components/form/input/text/index.js +24 -12
- package/lib/commonjs/components/form/input/text/index.js.map +1 -1
- package/lib/commonjs/components/form/input/text/textarea.js +13 -33
- package/lib/commonjs/components/form/input/text/textarea.js.map +1 -1
- package/lib/commonjs/components/form/input/text/useWebAutoResize.js +64 -0
- package/lib/commonjs/components/form/input/text/useWebAutoResize.js.map +1 -0
- package/lib/commonjs/components/form/view/file.js +21 -12
- package/lib/commonjs/components/form/view/file.js.map +1 -1
- package/lib/commonjs/components/form/view/index.js +29 -18
- package/lib/commonjs/components/form/view/index.js.map +1 -1
- package/lib/commonjs/components/form/view/multipleSelect.js +17 -13
- package/lib/commonjs/components/form/view/multipleSelect.js.map +1 -1
- package/lib/commonjs/components/form/view/select.js +14 -7
- package/lib/commonjs/components/form/view/select.js.map +1 -1
- package/lib/commonjs/components/form/view/styles.js +0 -3
- package/lib/commonjs/components/form/view/styles.js.map +1 -1
- package/lib/commonjs/components/layout/CollapseHorizontal.js +72 -0
- package/lib/commonjs/components/layout/CollapseHorizontal.js.map +1 -0
- package/lib/commonjs/contexts/root.js +94 -1
- package/lib/commonjs/contexts/root.js.map +1 -1
- package/lib/commonjs/index.js +11 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types/forms.js +6 -0
- package/lib/commonjs/types/forms.js.map +1 -0
- package/lib/commonjs/types/index.js +17 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/module/components/button/Toggle.js +21 -18
- package/lib/module/components/button/Toggle.js.map +1 -1
- package/lib/module/components/form/input/Editable.js +62 -93
- package/lib/module/components/form/input/Editable.js.map +1 -1
- package/lib/module/components/form/input/StandaloneInput.js +5 -1
- package/lib/module/components/form/input/StandaloneInput.js.map +1 -1
- package/lib/module/components/form/input/datetime/index.js +7 -2
- package/lib/module/components/form/input/datetime/index.js.map +1 -1
- package/lib/module/components/form/input/hooks/useInputStyles.js +2 -1
- package/lib/module/components/form/input/hooks/useInputStyles.js.map +1 -1
- package/lib/module/components/form/input/multipleSelect/index.js +25 -11
- package/lib/module/components/form/input/multipleSelect/index.js.map +1 -1
- package/lib/module/components/form/input/number/index.js +8 -4
- package/lib/module/components/form/input/number/index.js.map +1 -1
- package/lib/module/components/form/input/select/index.js +14 -4
- package/lib/module/components/form/input/select/index.js.map +1 -1
- package/lib/module/components/form/input/text/AutoResizeTextarea.js +48 -0
- package/lib/module/components/form/input/text/AutoResizeTextarea.js.map +1 -0
- package/lib/module/components/form/input/text/index.js +24 -12
- package/lib/module/components/form/input/text/index.js.map +1 -1
- package/lib/module/components/form/input/text/textarea.js +15 -35
- package/lib/module/components/form/input/text/textarea.js.map +1 -1
- package/lib/module/components/form/input/text/useWebAutoResize.js +58 -0
- package/lib/module/components/form/input/text/useWebAutoResize.js.map +1 -0
- package/lib/module/components/form/view/file.js +15 -6
- package/lib/module/components/form/view/file.js.map +1 -1
- package/lib/module/components/form/view/index.js +19 -8
- package/lib/module/components/form/view/index.js.map +1 -1
- package/lib/module/components/form/view/multipleSelect.js +18 -14
- package/lib/module/components/form/view/multipleSelect.js.map +1 -1
- package/lib/module/components/form/view/select.js +14 -7
- package/lib/module/components/form/view/select.js.map +1 -1
- package/lib/module/components/form/view/styles.js +0 -3
- package/lib/module/components/form/view/styles.js.map +1 -1
- package/lib/module/components/layout/CollapseHorizontal.js +64 -0
- package/lib/module/components/layout/CollapseHorizontal.js.map +1 -0
- package/lib/module/contexts/root.js +95 -2
- package/lib/module/contexts/root.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/forms.js +2 -0
- package/lib/module/types/forms.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/typescript/components/button/Toggle.d.ts +5 -2
- package/lib/typescript/components/button/Toggle.d.ts.map +1 -1
- package/lib/typescript/components/form/input/Editable.d.ts +2 -2
- package/lib/typescript/components/form/input/Editable.d.ts.map +1 -1
- package/lib/typescript/components/form/input/StandaloneInput.d.ts +5 -12
- package/lib/typescript/components/form/input/StandaloneInput.d.ts.map +1 -1
- package/lib/typescript/components/form/input/datetime/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/number/index.d.ts.map +1 -1
- package/lib/typescript/components/form/input/select/index.d.ts.map +1 -1
- package/lib/typescript/components/form/input/text/AutoResizeTextarea.d.ts +4 -0
- package/lib/typescript/components/form/input/text/AutoResizeTextarea.d.ts.map +1 -0
- package/lib/typescript/components/form/input/text/index.d.ts.map +1 -1
- package/lib/typescript/components/form/input/text/textarea.d.ts +2 -2
- package/lib/typescript/components/form/input/text/textarea.d.ts.map +1 -1
- package/lib/typescript/components/form/input/text/useWebAutoResize.d.ts +8 -0
- package/lib/typescript/components/form/input/text/useWebAutoResize.d.ts.map +1 -0
- package/lib/typescript/components/form/types.d.ts +2 -2
- package/lib/typescript/components/form/types.d.ts.map +1 -1
- 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.map +1 -1
- package/lib/typescript/components/form/view/select.d.ts +2 -1
- package/lib/typescript/components/form/view/select.d.ts.map +1 -1
- package/lib/typescript/components/form/view/styles.d.ts +0 -3
- package/lib/typescript/components/form/view/styles.d.ts.map +1 -1
- package/lib/typescript/components/layout/CollapseHorizontal.d.ts +9 -0
- package/lib/typescript/components/layout/CollapseHorizontal.d.ts.map +1 -0
- package/lib/typescript/contexts/root.d.ts +4 -1
- package/lib/typescript/contexts/root.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/forms.d.ts +5 -0
- package/lib/typescript/types/forms.d.ts.map +1 -0
- package/lib/typescript/types/index.d.ts +2 -0
- package/lib/typescript/types/index.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/components/button/Toggle.tsx +21 -17
- package/src/components/form/input/Editable.tsx +57 -113
- package/src/components/form/input/StandaloneInput.tsx +26 -13
- package/src/components/form/input/datetime/index.tsx +7 -2
- package/src/components/form/input/hooks/useInputStyles.ts +1 -1
- package/src/components/form/input/multipleSelect/index.tsx +34 -20
- package/src/components/form/input/number/index.tsx +20 -4
- package/src/components/form/input/select/index.tsx +15 -3
- package/src/components/form/input/text/AutoResizeTextarea.tsx +45 -0
- package/src/components/form/input/text/index.tsx +35 -17
- package/src/components/form/input/text/textarea.tsx +10 -36
- package/src/components/form/input/text/useWebAutoResize.tsx +71 -0
- package/src/components/form/types.ts +6 -2
- package/src/components/form/view/file.tsx +9 -5
- package/src/components/form/view/index.tsx +26 -7
- package/src/components/form/view/multipleSelect.tsx +11 -9
- package/src/components/form/view/select.tsx +7 -2
- package/src/components/form/view/styles.ts +0 -3
- package/src/components/layout/CollapseHorizontal.tsx +82 -0
- package/src/contexts/root.tsx +101 -3
- package/src/index.ts +1 -0
- package/src/types/forms.ts +14 -0
- package/src/types/index.ts +1 -0
|
@@ -8,49 +8,67 @@ import { useInputStyles } from '../hooks/useInputStyles'
|
|
|
8
8
|
import { TextAreaComponent } from './textarea'
|
|
9
9
|
|
|
10
10
|
export const TextComponent = forwardRef<InputRef, FieldProps<TextField>>(
|
|
11
|
-
({ input, inEditable, meta, field, style, formSize }, ref) => {
|
|
11
|
+
({ input, inEditable, meta, field, style, formSize, inputStyle }, ref) => {
|
|
12
12
|
const { placeholder, type } = field
|
|
13
13
|
const [isHidden, setIsHidden] = useState(type === 'password')
|
|
14
14
|
const { value, onChange, ...inputProps } = input
|
|
15
15
|
const inputRef = useRef<TextInput>(null)
|
|
16
|
-
const { container: inputStyles } = useInputStyles(
|
|
16
|
+
const { container: conatinerStyles, text: inputStyles } = useInputStyles(
|
|
17
|
+
inEditable,
|
|
18
|
+
field.size,
|
|
19
|
+
formSize,
|
|
20
|
+
)
|
|
17
21
|
|
|
18
22
|
useImperativeHandle(ref, () => ({
|
|
19
23
|
focus: () => {
|
|
20
24
|
inputRef.current?.focus()
|
|
21
25
|
},
|
|
22
26
|
blur: () => {
|
|
23
|
-
inputRef.current?.
|
|
27
|
+
inputRef.current?.clear()
|
|
24
28
|
},
|
|
25
29
|
}))
|
|
26
30
|
|
|
27
31
|
const placeholderColor = usePlaceholderColor()
|
|
28
32
|
const color = useTextColor()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<TextInput
|
|
33
|
+
|
|
34
|
+
if (type === 'textarea') {
|
|
35
|
+
return (
|
|
36
|
+
<TextAreaComponent
|
|
34
37
|
ref={inputRef}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
{
|
|
38
|
+
formSize={formSize}
|
|
39
|
+
inputStyle={inputStyle}
|
|
40
|
+
inEditable={inEditable}
|
|
41
|
+
field={field}
|
|
42
|
+
style={style}
|
|
43
|
+
input={input}
|
|
44
|
+
meta={meta}
|
|
42
45
|
/>
|
|
43
46
|
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const body = (
|
|
50
|
+
<TextInput
|
|
51
|
+
ref={inputRef}
|
|
52
|
+
style={[inputStyles, { color }, inputStyle]}
|
|
53
|
+
secureTextEntry={isHidden}
|
|
54
|
+
selectTextOnFocus={inEditable}
|
|
55
|
+
placeholderTextColor={placeholderColor}
|
|
56
|
+
placeholder={placeholder}
|
|
57
|
+
value={value ?? ''}
|
|
58
|
+
onChangeText={onChange}
|
|
59
|
+
{...inputProps}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
44
62
|
|
|
45
63
|
return type === 'password' ? (
|
|
46
|
-
<View style={styles.passwordContainer}>
|
|
64
|
+
<View style={[conatinerStyles, styles.passwordContainer, style]}>
|
|
47
65
|
{body}
|
|
48
66
|
<TouchableOpacity style={styles.eyeIcon} onPress={() => setIsHidden(!isHidden)}>
|
|
49
67
|
<Ionicons name={isHidden ? 'eye' : 'eye-off'} size={20} color="#666" />
|
|
50
68
|
</TouchableOpacity>
|
|
51
69
|
</View>
|
|
52
70
|
) : (
|
|
53
|
-
body
|
|
71
|
+
<View style={[conatinerStyles, style]}>{body}</View>
|
|
54
72
|
)
|
|
55
73
|
},
|
|
56
74
|
)
|
|
@@ -1,38 +1,25 @@
|
|
|
1
|
-
import { InputRef } from '@chem-po/core'
|
|
2
1
|
import { TextField, usePlaceholderColor, useTextColor } from '@chem-po/react'
|
|
3
|
-
import React, { forwardRef
|
|
4
|
-
import {
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import { TextInput, View } from 'react-native'
|
|
5
4
|
import { FieldProps } from '../../types'
|
|
6
5
|
import { useInputStyles } from '../hooks/useInputStyles'
|
|
6
|
+
import { AutoResizeTextarea } from './AutoResizeTextarea'
|
|
7
7
|
|
|
8
|
-
export const TextAreaComponent = forwardRef<
|
|
9
|
-
({ input, field, inEditable, formSize }, ref) => {
|
|
10
|
-
const
|
|
11
|
-
const { container: inputStyles } = useInputStyles(inEditable, field.size, formSize)
|
|
8
|
+
export const TextAreaComponent = forwardRef<TextInput, FieldProps<TextField>>(
|
|
9
|
+
({ input, field, inEditable, formSize, inputStyle, style }, ref) => {
|
|
10
|
+
const { text, container } = useInputStyles(inEditable, field.size, formSize)
|
|
12
11
|
const { value, onChange, ...inputProps } = input
|
|
13
|
-
|
|
14
|
-
useImperativeHandle(ref, () => ({
|
|
15
|
-
focus: () => {
|
|
16
|
-
inputRef.current?.focus()
|
|
17
|
-
},
|
|
18
|
-
blur: () => {
|
|
19
|
-
inputRef.current?.blur()
|
|
20
|
-
},
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
12
|
const placeholderColor = usePlaceholderColor()
|
|
24
13
|
const color = useTextColor()
|
|
25
14
|
|
|
26
15
|
return (
|
|
27
|
-
<View style={
|
|
28
|
-
<
|
|
29
|
-
ref={
|
|
30
|
-
style={[
|
|
16
|
+
<View style={[container, style]}>
|
|
17
|
+
<AutoResizeTextarea
|
|
18
|
+
ref={ref}
|
|
19
|
+
style={[{ color, ...text }, inputStyle]}
|
|
31
20
|
placeholder={field.placeholder}
|
|
32
21
|
placeholderTextColor={placeholderColor}
|
|
33
22
|
multiline
|
|
34
|
-
maxLength={200}
|
|
35
|
-
textAlignVertical="top"
|
|
36
23
|
value={value ?? ''}
|
|
37
24
|
onChangeText={onChange}
|
|
38
25
|
{...inputProps}
|
|
@@ -43,16 +30,3 @@ export const TextAreaComponent = forwardRef<InputRef, FieldProps<TextField>>(
|
|
|
43
30
|
)
|
|
44
31
|
|
|
45
32
|
TextAreaComponent.displayName = 'TextAreaComponent'
|
|
46
|
-
|
|
47
|
-
const styles = StyleSheet.create({
|
|
48
|
-
textarea: {
|
|
49
|
-
width: '100%',
|
|
50
|
-
minHeight: 80,
|
|
51
|
-
backgroundColor: 'transparent',
|
|
52
|
-
textAlignVertical: 'top',
|
|
53
|
-
},
|
|
54
|
-
inEditable: {
|
|
55
|
-
paddingHorizontal: 0,
|
|
56
|
-
paddingVertical: 0,
|
|
57
|
-
},
|
|
58
|
-
})
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
2
|
+
import { Platform, StyleProp, StyleSheet, TextStyle } from 'react-native'
|
|
3
|
+
|
|
4
|
+
// creates a span element with the text and style and returns the height
|
|
5
|
+
const getWebTextHeight = (text: string, spanRef: React.RefObject<HTMLSpanElement | null>) => {
|
|
6
|
+
if (!spanRef.current) return null
|
|
7
|
+
const span = spanRef.current
|
|
8
|
+
span.innerText = `${text}\n`
|
|
9
|
+
document.body.appendChild(span)
|
|
10
|
+
const height = span.offsetHeight
|
|
11
|
+
document.body.removeChild(span)
|
|
12
|
+
return height
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const updateSpanStyle = (span: HTMLSpanElement, style: TextStyle | undefined) => {
|
|
16
|
+
span.style.whiteSpace = 'pre-wrap'
|
|
17
|
+
if (style?.fontFamily) {
|
|
18
|
+
span.style.fontFamily = style.fontFamily
|
|
19
|
+
}
|
|
20
|
+
if (style?.fontSize) {
|
|
21
|
+
span.style.fontSize = style.fontSize.toString() + 'px'
|
|
22
|
+
}
|
|
23
|
+
if (style?.fontWeight) {
|
|
24
|
+
span.style.fontWeight = style.fontWeight.toString()
|
|
25
|
+
}
|
|
26
|
+
if (style?.lineHeight) {
|
|
27
|
+
span.style.lineHeight = style.lineHeight.toString()
|
|
28
|
+
}
|
|
29
|
+
if (style?.letterSpacing) {
|
|
30
|
+
span.style.letterSpacing = style.letterSpacing.toString()
|
|
31
|
+
}
|
|
32
|
+
if (style?.textAlign) {
|
|
33
|
+
span.style.textAlign = style.textAlign
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const useWebAutoResize = (
|
|
38
|
+
onChangeText: ((e: string) => void) | undefined,
|
|
39
|
+
style: StyleProp<TextStyle> | undefined,
|
|
40
|
+
) => {
|
|
41
|
+
const flattenedStyle = useMemo(() => StyleSheet.flatten(style), [style])
|
|
42
|
+
const [height, setHeight] = useState((flattenedStyle.fontSize ?? 18) + 4)
|
|
43
|
+
const spanRef = useRef<HTMLSpanElement>(
|
|
44
|
+
Platform.OS === 'web' ? document.createElement('span') : null,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (Platform.OS === 'web' && spanRef.current) {
|
|
49
|
+
updateSpanStyle(spanRef.current, flattenedStyle)
|
|
50
|
+
}
|
|
51
|
+
}, [flattenedStyle])
|
|
52
|
+
const handleChange = useMemo(
|
|
53
|
+
() =>
|
|
54
|
+
Platform.OS === 'web'
|
|
55
|
+
? (e: string) => {
|
|
56
|
+
if (spanRef.current) {
|
|
57
|
+
const height = getWebTextHeight(e, spanRef)
|
|
58
|
+
setHeight((height ?? 18) + 4)
|
|
59
|
+
if (onChangeText) onChangeText(e)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
: onChangeText,
|
|
63
|
+
[onChangeText],
|
|
64
|
+
)
|
|
65
|
+
return {
|
|
66
|
+
getWebTextHeight,
|
|
67
|
+
handleChange,
|
|
68
|
+
height,
|
|
69
|
+
setHeight,
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { BaseFieldProps, Field } from '@chem-po/react'
|
|
2
|
-
import { StyleProp } from 'react-native'
|
|
2
|
+
import { StyleProp, TextStyle, ViewStyle } from 'react-native'
|
|
3
3
|
|
|
4
|
-
export type FieldProps<
|
|
4
|
+
export type FieldProps<
|
|
5
|
+
T extends Field,
|
|
6
|
+
ContainerStyle extends ViewStyle = ViewStyle,
|
|
7
|
+
InputStyle extends TextStyle = TextStyle,
|
|
8
|
+
> = BaseFieldProps<StyleProp<ContainerStyle>, StyleProp<InputStyle>, T>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { ImageViewOptions, InputSize } from '@chem-po/core'
|
|
2
|
-
import { FileField } from '@chem-po/react'
|
|
2
|
+
import { FileField, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import React, { useMemo } from 'react'
|
|
4
4
|
import { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
5
|
+
import { Txt } from '../../text/Txt'
|
|
5
6
|
import { FileView } from '../input/file'
|
|
7
|
+
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
6
8
|
|
|
7
9
|
const styles = StyleSheet.create({
|
|
8
10
|
container: {
|
|
@@ -16,9 +18,6 @@ const styles = StyleSheet.create({
|
|
|
16
18
|
opacity: 0.7,
|
|
17
19
|
fontWeight: '600',
|
|
18
20
|
},
|
|
19
|
-
emptyText: {
|
|
20
|
-
opacity: 0.7,
|
|
21
|
-
},
|
|
22
21
|
fileContainer: {
|
|
23
22
|
padding: 4,
|
|
24
23
|
},
|
|
@@ -59,6 +58,9 @@ export const FileFieldView = ({
|
|
|
59
58
|
[imageOptions, size, sizeProp],
|
|
60
59
|
)
|
|
61
60
|
|
|
61
|
+
const { text, container } = useInputStyles(false, field.size, sizeProp)
|
|
62
|
+
const placeholderColor = usePlaceholderColor()
|
|
63
|
+
|
|
62
64
|
return (
|
|
63
65
|
<View style={[value ? styles.container : styles.rowContainer, style]}>
|
|
64
66
|
{!noLabel && <Text style={styles.label}>{placeholder}</Text>}
|
|
@@ -67,7 +69,9 @@ export const FileFieldView = ({
|
|
|
67
69
|
<FileView imageOptions={options} value={value} />
|
|
68
70
|
</View>
|
|
69
71
|
) : (
|
|
70
|
-
<
|
|
72
|
+
<View style={container}>
|
|
73
|
+
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
74
|
+
</View>
|
|
71
75
|
)}
|
|
72
76
|
</View>
|
|
73
77
|
)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { displayField, InputSize } from '@chem-po/core'
|
|
2
|
-
import { Field, FormatField } from '@chem-po/react'
|
|
2
|
+
import { Field, FormatField, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import React, { useMemo } from 'react'
|
|
4
4
|
import { StyleSheet, View, ViewStyle } from 'react-native'
|
|
5
5
|
import { Txt } from '../../text'
|
|
@@ -22,30 +22,33 @@ const DefaultFieldView = ({
|
|
|
22
22
|
noLabel,
|
|
23
23
|
style,
|
|
24
24
|
size: sizeProp,
|
|
25
|
+
inEditable,
|
|
25
26
|
}: {
|
|
26
27
|
field: Field
|
|
27
28
|
value: any
|
|
28
29
|
noLabel?: boolean
|
|
29
30
|
style?: ViewStyle
|
|
30
31
|
size?: InputSize
|
|
32
|
+
inEditable?: boolean
|
|
31
33
|
}) => {
|
|
32
34
|
const { placeholder } = field
|
|
33
35
|
|
|
34
|
-
const { text } = useInputStyles(
|
|
36
|
+
const { text, container: containerStyles } = useInputStyles(inEditable, field.size, sizeProp)
|
|
35
37
|
const formatted = useMemo(() => {
|
|
36
38
|
const format = displayField[field._type] as FormatField<Field>
|
|
37
39
|
if (!format) return value
|
|
38
40
|
return format(field, value)
|
|
39
41
|
}, [value, field])
|
|
40
42
|
|
|
43
|
+
const placeholderColor = usePlaceholderColor()
|
|
41
44
|
const hasValue = useMemo(() => {
|
|
42
45
|
return value !== null && value !== undefined && value !== ''
|
|
43
46
|
}, [value])
|
|
44
47
|
|
|
45
48
|
return (
|
|
46
|
-
<View style={[styles.container, style]}>
|
|
49
|
+
<View style={[styles.container, containerStyles, { backgroundColor: 'transparent' }, style]}>
|
|
47
50
|
{!noLabel && <Txt style={[inputViewStyles.label, text]}>{placeholder}</Txt>}
|
|
48
|
-
<Txt style={[hasValue ?
|
|
51
|
+
<Txt style={[text, { color: hasValue ? undefined : placeholderColor }]}>
|
|
49
52
|
{hasValue ? formatted : 'None'}
|
|
50
53
|
</Txt>
|
|
51
54
|
</View>
|
|
@@ -58,17 +61,26 @@ export const FieldView = ({
|
|
|
58
61
|
noLabel,
|
|
59
62
|
style,
|
|
60
63
|
size,
|
|
64
|
+
inEditable,
|
|
61
65
|
}: {
|
|
62
66
|
field: Field
|
|
63
|
-
value
|
|
67
|
+
value?: any
|
|
64
68
|
noLabel?: boolean
|
|
65
69
|
style?: ViewStyle
|
|
66
70
|
size?: InputSize
|
|
71
|
+
inEditable?: boolean
|
|
67
72
|
}) => {
|
|
68
73
|
switch (field._type) {
|
|
69
74
|
case 'select':
|
|
70
75
|
return (
|
|
71
|
-
<SelectFieldView
|
|
76
|
+
<SelectFieldView
|
|
77
|
+
style={style}
|
|
78
|
+
field={field}
|
|
79
|
+
value={value}
|
|
80
|
+
noLabel={noLabel}
|
|
81
|
+
size={size}
|
|
82
|
+
inEditable={inEditable}
|
|
83
|
+
/>
|
|
72
84
|
)
|
|
73
85
|
case 'multipleSelect':
|
|
74
86
|
return (
|
|
@@ -86,7 +98,14 @@ export const FieldView = ({
|
|
|
86
98
|
)
|
|
87
99
|
default:
|
|
88
100
|
return (
|
|
89
|
-
<DefaultFieldView
|
|
101
|
+
<DefaultFieldView
|
|
102
|
+
style={style}
|
|
103
|
+
field={field}
|
|
104
|
+
value={value}
|
|
105
|
+
noLabel={noLabel}
|
|
106
|
+
size={size}
|
|
107
|
+
inEditable={inEditable}
|
|
108
|
+
/>
|
|
90
109
|
)
|
|
91
110
|
}
|
|
92
111
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { InputSize } from '@chem-po/core'
|
|
2
|
-
import { MultipleSelectField, useColorMode } from '@chem-po/react'
|
|
2
|
+
import { MultipleSelectField, useColorMode, usePlaceholderColor } from '@chem-po/react'
|
|
3
3
|
import { useMemo } from 'react'
|
|
4
4
|
import React, { StyleSheet, Text, View, ViewStyle } from 'react-native'
|
|
5
|
+
import { Txt } from '../../text/Txt'
|
|
5
6
|
import { useInputStyles } from '../input/hooks/useInputStyles'
|
|
6
7
|
import { SelectedOptionContainer } from '../input/multipleSelect'
|
|
7
8
|
import { DefaultRenderOption } from './select'
|
|
@@ -12,6 +13,7 @@ const styles = StyleSheet.create({
|
|
|
12
13
|
flexWrap: 'wrap',
|
|
13
14
|
alignItems: 'center',
|
|
14
15
|
maxWidth: '100%',
|
|
16
|
+
backgroundColor: 'transparent',
|
|
15
17
|
},
|
|
16
18
|
label: {
|
|
17
19
|
paddingRight: 8,
|
|
@@ -27,9 +29,6 @@ const styles = StyleSheet.create({
|
|
|
27
29
|
marginTop: 2,
|
|
28
30
|
marginHorizontal: 2,
|
|
29
31
|
},
|
|
30
|
-
emptyText: {
|
|
31
|
-
opacity: 0.6,
|
|
32
|
-
},
|
|
33
32
|
})
|
|
34
33
|
|
|
35
34
|
export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
@@ -48,13 +47,14 @@ export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
|
48
47
|
const { placeholder, renderOption: customRender, options } = field
|
|
49
48
|
const selectedOptions = options.filter(o => value?.includes(o.value))
|
|
50
49
|
const colorMode = useColorMode()
|
|
51
|
-
const { size,
|
|
50
|
+
const { size, text, container } = useInputStyles(true, field.size, sizeProp)
|
|
51
|
+
const placeholderColor = usePlaceholderColor()
|
|
52
52
|
const selectedOptionStyle = useMemo<ViewStyle>(() => {
|
|
53
53
|
return {
|
|
54
|
-
paddingHorizontal:
|
|
55
|
-
paddingVertical:
|
|
54
|
+
paddingHorizontal: container.paddingHorizontal,
|
|
55
|
+
paddingVertical: container.paddingVertical,
|
|
56
56
|
}
|
|
57
|
-
}, [
|
|
57
|
+
}, [container])
|
|
58
58
|
const RenderOption = useMemo(() => customRender ?? DefaultRenderOption, [customRender])
|
|
59
59
|
return (
|
|
60
60
|
<View style={[styles.container, style]}>
|
|
@@ -74,7 +74,9 @@ export const MultipleSelectFieldView = <F extends MultipleSelectField>({
|
|
|
74
74
|
))}
|
|
75
75
|
</View>
|
|
76
76
|
) : (
|
|
77
|
-
<
|
|
77
|
+
<View style={container}>
|
|
78
|
+
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
79
|
+
</View>
|
|
78
80
|
)}
|
|
79
81
|
</View>
|
|
80
82
|
)
|
|
@@ -10,6 +10,7 @@ const styles = StyleSheet.create({
|
|
|
10
10
|
container: {
|
|
11
11
|
flexDirection: 'row',
|
|
12
12
|
alignItems: 'center',
|
|
13
|
+
backgroundColor: 'transparent',
|
|
13
14
|
},
|
|
14
15
|
label: {
|
|
15
16
|
paddingRight: 10,
|
|
@@ -32,17 +33,19 @@ export const SelectFieldView = ({
|
|
|
32
33
|
noLabel,
|
|
33
34
|
style,
|
|
34
35
|
size: sizeProp,
|
|
36
|
+
inEditable,
|
|
35
37
|
}: {
|
|
36
38
|
field: SelectField
|
|
37
39
|
value: any
|
|
38
40
|
noLabel?: boolean
|
|
39
41
|
style?: ViewStyle
|
|
40
42
|
size?: InputSize
|
|
43
|
+
inEditable?: boolean
|
|
41
44
|
}) => {
|
|
42
45
|
const { placeholder, renderOption: customRender } = field
|
|
43
46
|
const colorMode = useColorMode()
|
|
44
47
|
const placeholderColor = usePlaceholderColor()
|
|
45
|
-
const { size, text } = useInputStyles(
|
|
48
|
+
const { size, text, container } = useInputStyles(inEditable, field.size, sizeProp)
|
|
46
49
|
const selectedOption = field.options.find(o => o.value === value)
|
|
47
50
|
const RenderOption = customRender ?? DefaultRenderOption
|
|
48
51
|
return (
|
|
@@ -59,7 +62,9 @@ export const SelectFieldView = ({
|
|
|
59
62
|
size={size}
|
|
60
63
|
/>
|
|
61
64
|
) : (
|
|
62
|
-
<
|
|
65
|
+
<View style={container}>
|
|
66
|
+
<Txt style={[text, { color: placeholderColor }]}>None</Txt>
|
|
67
|
+
</View>
|
|
63
68
|
)}
|
|
64
69
|
</View>
|
|
65
70
|
)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { useCallback } from 'react'
|
|
2
|
+
import { LayoutChangeEvent, StyleProp, View, ViewStyle } from 'react-native'
|
|
3
|
+
import Animated, {
|
|
4
|
+
useAnimatedStyle,
|
|
5
|
+
useSharedValue,
|
|
6
|
+
withSequence,
|
|
7
|
+
withTiming,
|
|
8
|
+
} from 'react-native-reanimated'
|
|
9
|
+
|
|
10
|
+
export const CollapseHorizontal = ({
|
|
11
|
+
children,
|
|
12
|
+
in: isIn,
|
|
13
|
+
duration = 200,
|
|
14
|
+
style,
|
|
15
|
+
}: {
|
|
16
|
+
children: React.ReactNode
|
|
17
|
+
in: boolean
|
|
18
|
+
duration?: number
|
|
19
|
+
style?: StyleProp<ViewStyle>
|
|
20
|
+
}) => {
|
|
21
|
+
const contentWidth = useSharedValue(0)
|
|
22
|
+
const width = useSharedValue(0)
|
|
23
|
+
const opacity = useSharedValue(0)
|
|
24
|
+
|
|
25
|
+
const handleLayout = useCallback(
|
|
26
|
+
(event: LayoutChangeEvent) => {
|
|
27
|
+
contentWidth.value = event.nativeEvent.layout.width
|
|
28
|
+
// Initialize width if component is initially visible
|
|
29
|
+
if (isIn && width.value === 0) {
|
|
30
|
+
width.value = contentWidth.value
|
|
31
|
+
opacity.value = 1
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
[isIn, contentWidth, width, opacity],
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
React.useEffect(() => {
|
|
38
|
+
if (isIn) {
|
|
39
|
+
// Fade in: width first, then opacity
|
|
40
|
+
width.value = withTiming(contentWidth.value, {
|
|
41
|
+
duration,
|
|
42
|
+
})
|
|
43
|
+
opacity.value = withSequence(
|
|
44
|
+
withTiming(0, { duration: 0 }), // Reset opacity
|
|
45
|
+
withTiming(1, {
|
|
46
|
+
duration,
|
|
47
|
+
}),
|
|
48
|
+
)
|
|
49
|
+
} else {
|
|
50
|
+
// Fade out: opacity first, then width
|
|
51
|
+
opacity.value = withTiming(0, {
|
|
52
|
+
duration,
|
|
53
|
+
})
|
|
54
|
+
width.value = withSequence(
|
|
55
|
+
withTiming(width.value, { duration: 0 }), // Ensure we start from current width
|
|
56
|
+
withTiming(0, {
|
|
57
|
+
duration,
|
|
58
|
+
}),
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}, [isIn, contentWidth.value, duration, width, opacity])
|
|
62
|
+
|
|
63
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
64
|
+
width: width.value,
|
|
65
|
+
opacity: opacity.value,
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Animated.View
|
|
70
|
+
style={[
|
|
71
|
+
{
|
|
72
|
+
overflow: 'hidden',
|
|
73
|
+
pointerEvents: isIn ? 'auto' : 'none',
|
|
74
|
+
},
|
|
75
|
+
animatedStyle,
|
|
76
|
+
]}>
|
|
77
|
+
<View style={[{ position: 'absolute' }, style]} onLayout={handleLayout}>
|
|
78
|
+
{children}
|
|
79
|
+
</View>
|
|
80
|
+
</Animated.View>
|
|
81
|
+
)
|
|
82
|
+
}
|
package/src/contexts/root.tsx
CHANGED
|
@@ -1,24 +1,121 @@
|
|
|
1
1
|
import { BackendAdapterInterface, ColorMode, Theme } from '@chem-po/core'
|
|
2
|
-
import { ChempoProps, ChempoProvider } from '@chem-po/react'
|
|
2
|
+
import { ChempoProps, ChempoProvider, useTheme } from '@chem-po/react'
|
|
3
3
|
import React, { PropsWithChildren, useMemo } from 'react'
|
|
4
4
|
import { NotifierWrapper } from 'react-native-notifier'
|
|
5
|
+
import { configureFonts, PaperProvider, Props as PaperProviderProps } from 'react-native-paper'
|
|
5
6
|
import { en, registerTranslation } from 'react-native-paper-dates'
|
|
7
|
+
import { MD3Type, MD3TypescaleKey } from 'react-native-paper/lib/typescript/types'
|
|
6
8
|
import { nativeToast } from '../constants/toast'
|
|
7
9
|
import { useThemeState } from '../hooks/useThemeState'
|
|
8
10
|
import { initializeScreen } from '../store/useScreen'
|
|
9
11
|
|
|
10
12
|
registerTranslation('en', en)
|
|
11
13
|
|
|
14
|
+
export type FontConfig = Partial<Record<MD3TypescaleKey, Partial<MD3Type>>>
|
|
12
15
|
export interface ChempoNativeProviderProps<BackendAdapter extends BackendAdapterInterface>
|
|
13
16
|
extends PropsWithChildren<Pick<ChempoProps<BackendAdapter>, 'backendAdapter' | 'assets'>> {
|
|
14
17
|
theme?: Theme
|
|
18
|
+
fonts?: FontConfig
|
|
15
19
|
initialColorMode?: ColorMode
|
|
16
20
|
}
|
|
21
|
+
const createPaperTheme = (
|
|
22
|
+
theme: Theme,
|
|
23
|
+
fonts: FontConfig | undefined,
|
|
24
|
+
colorMode: ColorMode,
|
|
25
|
+
): PaperProviderProps['theme'] => {
|
|
26
|
+
const { colors } = theme
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
dark: colorMode === 'dark',
|
|
30
|
+
colors: {
|
|
31
|
+
primary: colors.accent[300],
|
|
32
|
+
onPrimary: colors.text[900],
|
|
33
|
+
primaryContainer: colors.accent[800],
|
|
34
|
+
onPrimaryContainer: colors.text[150],
|
|
35
|
+
|
|
36
|
+
secondary: colors.background[150],
|
|
37
|
+
onSecondary: colors.text[100],
|
|
38
|
+
secondaryContainer: colors.accent[950],
|
|
39
|
+
onSecondaryContainer: colors.text[150],
|
|
40
|
+
|
|
41
|
+
tertiary: colors.accent[600],
|
|
42
|
+
onTertiary: colors.text[50],
|
|
43
|
+
tertiaryContainer: colors.accent[300],
|
|
44
|
+
onTertiaryContainer: colors.text[700],
|
|
45
|
+
|
|
46
|
+
error: colors.error[500],
|
|
47
|
+
onError: colors.text[50],
|
|
48
|
+
errorContainer: colors.error[100],
|
|
49
|
+
onErrorContainer: colors.error[900],
|
|
50
|
+
|
|
51
|
+
background: colors.background[50],
|
|
52
|
+
onBackground: colors.text[100],
|
|
53
|
+
surface: colors.background[100],
|
|
54
|
+
onSurface: colors.text[100],
|
|
55
|
+
surfaceVariant: colors.background[200],
|
|
56
|
+
onSurfaceVariant: colors.text[300],
|
|
57
|
+
outline: colors.text[500],
|
|
58
|
+
outlineVariant: colors.accent[300],
|
|
59
|
+
|
|
60
|
+
surfaceDisabled: colors.background[200],
|
|
61
|
+
onSurfaceDisabled: colors.text[400],
|
|
62
|
+
backdrop: '#000000aa', // 60% opacity
|
|
63
|
+
|
|
64
|
+
inverseSurface: colors.background[900],
|
|
65
|
+
inverseOnSurface: colors.text[50],
|
|
66
|
+
inversePrimary: colors.accent[200],
|
|
67
|
+
shadow: '#00000099',
|
|
68
|
+
scrim: '#00000099', // Semi-transparent dark overlay
|
|
69
|
+
|
|
70
|
+
elevation: {
|
|
71
|
+
level0: 'transparent',
|
|
72
|
+
level1: colors.background[100],
|
|
73
|
+
level2: colors.background[200],
|
|
74
|
+
level3: colors.background[300],
|
|
75
|
+
level4: colors.background[400],
|
|
76
|
+
level5: colors.background[500],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
roundness: 4,
|
|
80
|
+
animation: {
|
|
81
|
+
scale: 1.0,
|
|
82
|
+
},
|
|
83
|
+
fonts: configureFonts({
|
|
84
|
+
config: {
|
|
85
|
+
...fonts,
|
|
86
|
+
bodyLarge: {
|
|
87
|
+
fontSize: 18,
|
|
88
|
+
...fonts?.bodyLarge,
|
|
89
|
+
},
|
|
90
|
+
bodyMedium: {
|
|
91
|
+
fontSize: 17,
|
|
92
|
+
...fonts?.bodyMedium,
|
|
93
|
+
},
|
|
94
|
+
bodySmall: {
|
|
95
|
+
fontSize: 16,
|
|
96
|
+
...fonts?.bodySmall,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const ChempoPaperProvider = ({ children, fonts }: PropsWithChildren<{ fonts?: FontConfig }>) => {
|
|
104
|
+
const { theme, colorMode } = useTheme()
|
|
105
|
+
|
|
106
|
+
const paperTheme = useMemo(
|
|
107
|
+
() => createPaperTheme(theme, fonts, colorMode),
|
|
108
|
+
[theme, fonts, colorMode],
|
|
109
|
+
)
|
|
110
|
+
return <PaperProvider theme={paperTheme}>{children}</PaperProvider>
|
|
111
|
+
}
|
|
17
112
|
export const ChempoNativeProvider = <
|
|
18
113
|
BackendAdapter extends BackendAdapterInterface<any, any, any, any, any, any>,
|
|
19
114
|
>({
|
|
20
115
|
theme: themeProp,
|
|
21
116
|
initialColorMode,
|
|
117
|
+
children,
|
|
118
|
+
fonts,
|
|
22
119
|
...props
|
|
23
120
|
}: ChempoNativeProviderProps<BackendAdapter>) => {
|
|
24
121
|
const useThemeProps = useMemo(
|
|
@@ -32,8 +129,9 @@ export const ChempoNativeProvider = <
|
|
|
32
129
|
toast={nativeToast}
|
|
33
130
|
theme={theme}
|
|
34
131
|
initializeScreen={initializeScreen}
|
|
35
|
-
{...props}
|
|
36
|
-
|
|
132
|
+
{...props}>
|
|
133
|
+
<ChempoPaperProvider fonts={fonts}>{children}</ChempoPaperProvider>
|
|
134
|
+
</ChempoProvider>
|
|
37
135
|
</NotifierWrapper>
|
|
38
136
|
)
|
|
39
137
|
}
|