@chem-po/react-native 0.0.48 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/lib/commonjs/components/button/ActionButton.js +5 -3
  2. package/lib/commonjs/components/button/ActionButton.js.map +1 -1
  3. package/lib/commonjs/components/button/DeleteButton.js +7 -2
  4. package/lib/commonjs/components/button/DeleteButton.js.map +1 -1
  5. package/lib/commonjs/components/form/Form.js +9 -4
  6. package/lib/commonjs/components/form/Form.js.map +1 -1
  7. package/lib/commonjs/components/form/input/Editable.js +15 -6
  8. package/lib/commonjs/components/form/input/Editable.js.map +1 -1
  9. package/lib/commonjs/components/form/input/boolean/index.js +3 -2
  10. package/lib/commonjs/components/form/input/boolean/index.js.map +1 -1
  11. package/lib/commonjs/components/form/input/file/index.js +3 -1
  12. package/lib/commonjs/components/form/input/file/index.js.map +1 -1
  13. package/lib/commonjs/components/loading/LoadingOverlay.js +6 -1
  14. package/lib/commonjs/components/loading/LoadingOverlay.js.map +1 -1
  15. package/lib/commonjs/components/text/AnimatedText.js +5 -3
  16. package/lib/commonjs/components/text/AnimatedText.js.map +1 -1
  17. package/lib/commonjs/contexts/root.js +3 -0
  18. package/lib/commonjs/contexts/root.js.map +1 -1
  19. package/lib/commonjs/hooks/useRefreshFontScale.js +33 -0
  20. package/lib/commonjs/hooks/useRefreshFontScale.js.map +1 -0
  21. package/lib/commonjs/store/index.js +11 -0
  22. package/lib/commonjs/store/index.js.map +1 -1
  23. package/lib/commonjs/store/useFontScale.js +14 -0
  24. package/lib/commonjs/store/useFontScale.js.map +1 -0
  25. package/lib/module/components/button/ActionButton.js +5 -3
  26. package/lib/module/components/button/ActionButton.js.map +1 -1
  27. package/lib/module/components/button/DeleteButton.js +7 -2
  28. package/lib/module/components/button/DeleteButton.js.map +1 -1
  29. package/lib/module/components/form/Form.js +9 -4
  30. package/lib/module/components/form/Form.js.map +1 -1
  31. package/lib/module/components/form/input/Editable.js +15 -6
  32. package/lib/module/components/form/input/Editable.js.map +1 -1
  33. package/lib/module/components/form/input/boolean/index.js +4 -3
  34. package/lib/module/components/form/input/boolean/index.js.map +1 -1
  35. package/lib/module/components/form/input/file/index.js +3 -1
  36. package/lib/module/components/form/input/file/index.js.map +1 -1
  37. package/lib/module/components/loading/LoadingOverlay.js +6 -1
  38. package/lib/module/components/loading/LoadingOverlay.js.map +1 -1
  39. package/lib/module/components/text/AnimatedText.js +5 -3
  40. package/lib/module/components/text/AnimatedText.js.map +1 -1
  41. package/lib/module/contexts/root.js +3 -0
  42. package/lib/module/contexts/root.js.map +1 -1
  43. package/lib/module/hooks/useRefreshFontScale.js +28 -0
  44. package/lib/module/hooks/useRefreshFontScale.js.map +1 -0
  45. package/lib/module/store/index.js +1 -0
  46. package/lib/module/store/index.js.map +1 -1
  47. package/lib/module/store/useFontScale.js +9 -0
  48. package/lib/module/store/useFontScale.js.map +1 -0
  49. package/lib/typescript/components/button/ActionButton.d.ts.map +1 -1
  50. package/lib/typescript/components/button/DeleteButton.d.ts.map +1 -1
  51. package/lib/typescript/components/form/Form.d.ts.map +1 -1
  52. package/lib/typescript/components/form/input/Editable.d.ts.map +1 -1
  53. package/lib/typescript/components/form/input/boolean/index.d.ts.map +1 -1
  54. package/lib/typescript/components/form/input/file/index.d.ts.map +1 -1
  55. package/lib/typescript/components/loading/LoadingOverlay.d.ts.map +1 -1
  56. package/lib/typescript/components/text/AnimatedText.d.ts.map +1 -1
  57. package/lib/typescript/contexts/root.d.ts +2 -1
  58. package/lib/typescript/contexts/root.d.ts.map +1 -1
  59. package/lib/typescript/hooks/useRefreshFontScale.d.ts +7 -0
  60. package/lib/typescript/hooks/useRefreshFontScale.d.ts.map +1 -0
  61. package/lib/typescript/store/index.d.ts +1 -0
  62. package/lib/typescript/store/index.d.ts.map +1 -1
  63. package/lib/typescript/store/useFontScale.d.ts +4 -0
  64. package/lib/typescript/store/useFontScale.d.ts.map +1 -0
  65. package/package.json +5 -5
  66. package/src/components/button/ActionButton.tsx +5 -3
  67. package/src/components/button/DeleteButton.tsx +6 -4
  68. package/src/components/form/Form.tsx +6 -3
  69. package/src/components/form/input/Editable.tsx +23 -6
  70. package/src/components/form/input/boolean/index.tsx +4 -3
  71. package/src/components/form/input/file/index.tsx +3 -1
  72. package/src/components/loading/LoadingOverlay.tsx +3 -2
  73. package/src/components/text/AnimatedText.tsx +5 -3
  74. package/src/contexts/root.tsx +4 -0
  75. package/src/hooks/useRefreshFontScale.ts +26 -0
  76. package/src/store/index.ts +1 -0
  77. package/src/store/useFontScale.ts +8 -0
@@ -4,6 +4,7 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'reac
4
4
  import { ActivityIndicator, StyleSheet, View } from 'react-native'
5
5
  import { Pressable } from 'react-native-gesture-handler'
6
6
  import { Modal, Portal } from 'react-native-paper'
7
+ import { useFontScale } from '../../store/useFontScale'
7
8
  import { Txt } from '../text/Txt'
8
9
  import { ActionButton, ActionButtonProps } from './ActionButton'
9
10
  import { ButtonText } from './ButtonText'
@@ -32,10 +33,11 @@ export const DeleteConfirmAlert = ({
32
33
  itemName: string
33
34
  }) => {
34
35
  const backgroundColor = useBackgroundColor(100)
36
+ const fontScale = useFontScale(s => s.fontScale)
35
37
  return (
36
38
  <Portal>
37
39
  <Modal style={styles.modal} visible={confirmActive} onDismiss={onCancel}>
38
- <View style={[styles.alertContainer, { backgroundColor }]}>
40
+ <View style={[styles.alertContainer, { backgroundColor, maxWidth: 300 * fontScale }]}>
39
41
  <Txt style={styles.alertTitle}>
40
42
  {actionName} {itemName}?
41
43
  </Txt>
@@ -49,7 +51,7 @@ export const DeleteConfirmAlert = ({
49
51
  onPress={onConfirm}
50
52
  disabled={actionLoading}>
51
53
  {actionLoading ? (
52
- <ActivityIndicator color="#fff" />
54
+ <ActivityIndicator size={20 * fontScale} color="#fff" />
53
55
  ) : (
54
56
  <Txt style={[styles.buttonText, styles.confirmButtonText]}>
55
57
  {actionName.toUpperCase()}
@@ -95,7 +97,7 @@ export const DeleteButton: React.FC<DeleteButtonProps> = ({
95
97
  const isMounted = useRef(true)
96
98
  const defaultColor = useColorModeValue('#dd4444', '#ff4444')
97
99
  const color = colorProp ?? defaultColor
98
-
100
+ const fontScale = useFontScale(s => s.fontScale)
99
101
  useEffect(() => {
100
102
  isMounted.current = true
101
103
 
@@ -145,7 +147,7 @@ export const DeleteButton: React.FC<DeleteButtonProps> = ({
145
147
  <View style={styles.contentContainer}>
146
148
  <Ionicons
147
149
  name="trash"
148
- size={iconSize}
150
+ size={iconSize * fontScale}
149
151
  color={variant === 'solid' ? 'white' : color}
150
152
  {...iconProps}
151
153
  style={[variant === 'solid' ? styles.shadow : {}, iconProps?.style]}
@@ -22,6 +22,7 @@ import React, { FC, useMemo, useState } from 'react'
22
22
  import { useFieldArray, useFormContext } from 'react-hook-form'
23
23
  import { StyleSheet, Text, View } from 'react-native'
24
24
  import { Pressable } from 'react-native-gesture-handler'
25
+ import { useFontScale } from '../../store/useFontScale'
25
26
  import { Expandable } from '../box/Expandable'
26
27
  import { DeleteButton } from '../button/DeleteButton'
27
28
  import { Condition } from './Condition'
@@ -85,8 +86,8 @@ const styles = StyleSheet.create({
85
86
  },
86
87
  formElementContainer: {
87
88
  width: '100%',
88
- paddingVertical: 5,
89
- gap: 5,
89
+ // paddingVertical: 5,
90
+ // gap: 5,
90
91
  },
91
92
  dataViewHeader: {
92
93
  flexDirection: 'row',
@@ -190,6 +191,7 @@ export const FormElement = ({
190
191
  name: string
191
192
  size: InputSize
192
193
  }) => {
194
+ const fontScale = useFontScale(s => s.fontScale)
193
195
  const fields = useMemo<Array<{ name: string; field: IFormElement }>>(() => {
194
196
  if (isField(field) || isListField(field)) return [{ name: 'value', field }]
195
197
 
@@ -200,7 +202,8 @@ export const FormElement = ({
200
202
  }, [field, name])
201
203
 
202
204
  return (
203
- <View style={styles.formElementContainer}>
205
+ <View
206
+ style={[styles.formElementContainer, { gap: fontScale * 5, paddingVertical: fontScale * 5 }]}>
204
207
  {fields.map(f => {
205
208
  if (isListField(f.field)) {
206
209
  const b = <ListFieldInput key={f.name} name={f.name} field={f.field} size={size} />
@@ -12,6 +12,7 @@ import { Ionicons } from '@expo/vector-icons'
12
12
  import React, { ForwardedRef, useCallback, useEffect } from 'react'
13
13
  import { StyleSheet, TextStyle, View, ViewStyle } from 'react-native'
14
14
  import { Pressable } from 'react-native-gesture-handler'
15
+ import { useFontScale } from '../../../store/useFontScale'
15
16
  import { CustomInputProps } from '../../../types/forms'
16
17
  import { LoadingOverlay } from '../../loading/LoadingOverlay'
17
18
  import { UploadProgress } from '../UploadProgress'
@@ -55,6 +56,7 @@ export const Editable = <T extends Field>({
55
56
  onEditClose,
56
57
  ref,
57
58
  })
59
+ const fontScale = useFontScale(s => s.fontScale)
58
60
 
59
61
  useEffect(() => {
60
62
  if (isEditing) {
@@ -120,19 +122,34 @@ export const Editable = <T extends Field>({
120
122
  onPress={() => {
121
123
  handleEditClose()
122
124
  }}
123
- style={[styles.submitButton, { borderColor: iconColor, borderWidth: 1 }]}
125
+ style={[
126
+ styles.submitButton,
127
+ {
128
+ borderColor: iconColor,
129
+ borderWidth: 1,
130
+ width: 28 * fontScale,
131
+ height: 28 * fontScale,
132
+ },
133
+ ]}
124
134
  onPressIn={() => setEditHovered(true)}
125
135
  onPressOut={() => setEditHovered(false)}>
126
- <Ionicons name="close-outline" size={20} color={iconColor} />
136
+ <Ionicons name="close-outline" size={20 * fontScale} color={iconColor} />
127
137
  </Pressable>
128
138
  <Pressable
129
139
  onPress={() => {
130
140
  submit()
131
141
  }}
132
- style={[styles.submitButton, { backgroundColor: submitBackgroundColor }]}
142
+ style={[
143
+ styles.submitButton,
144
+ {
145
+ backgroundColor: submitBackgroundColor,
146
+ width: 28 * fontScale,
147
+ height: 28 * fontScale,
148
+ },
149
+ ]}
133
150
  onPressIn={() => setEditHovered(true)}
134
151
  onPressOut={() => setEditHovered(false)}>
135
- <Ionicons color="white" name="checkmark-outline" size={20} />
152
+ <Ionicons color="white" name="checkmark-outline" size={20 * fontScale} />
136
153
  </Pressable>
137
154
  </>
138
155
  ) : (
@@ -140,10 +157,10 @@ export const Editable = <T extends Field>({
140
157
  onPress={() => {
141
158
  handleEditOpen()
142
159
  }}
143
- style={styles.submitButton}
160
+ style={[styles.submitButton, { width: 28 * fontScale, height: 28 * fontScale }]}
144
161
  onPressIn={() => setEditHovered(true)}
145
162
  onPressOut={() => setEditHovered(false)}>
146
- <Ionicons name="create-outline" size={20} color={iconColor} />
163
+ <Ionicons name="create-outline" size={20 * fontScale} color={iconColor} />
147
164
  </Pressable>
148
165
  )}
149
166
  </View>
@@ -1,7 +1,8 @@
1
1
  import { InputRef } from '@chem-po/core'
2
2
  import { BooleanField, useBooleanFieldText } from '@chem-po/react'
3
3
  import React, { ForwardedRef, forwardRef, useImperativeHandle } from 'react'
4
- import { Switch, Text, View } from 'react-native'
4
+ import { Switch, View } from 'react-native'
5
+ import { Txt } from '../../../text/Txt'
5
6
  import { FieldProps } from '../../types'
6
7
 
7
8
  const BaseCheckboxComponent = (
@@ -16,7 +17,7 @@ const BaseCheckboxComponent = (
16
17
  return (
17
18
  <View style={{ flexDirection: 'row', alignItems: 'center' }}>
18
19
  <Switch value={value} onValueChange={onChange} {...input} />
19
- <Text style={{ marginLeft: 8, fontWeight: '600', opacity: value ? 0.9 : 0.6 }}>{text}</Text>
20
+ <Txt style={{ marginLeft: 8, fontWeight: '600', opacity: value ? 0.9 : 0.6 }}>{text}</Txt>
20
21
  </View>
21
22
  )
22
23
  }
@@ -37,7 +38,7 @@ const BaseSwitchComponent = (
37
38
  return (
38
39
  <View style={{ flexDirection: 'row', alignItems: 'center' }}>
39
40
  <Switch value={value} onValueChange={onChange} {...input} />
40
- <Text style={{ marginLeft: 8, fontWeight: '600', opacity: value ? 0.9 : 0.6 }}>{text}</Text>
41
+ <Txt style={{ marginLeft: 8, fontWeight: '600', opacity: value ? 0.9 : 0.6 }}>{text}</Txt>
41
42
  </View>
42
43
  )
43
44
  }
@@ -15,6 +15,7 @@ import * as ImagePicker from 'expo-image-picker'
15
15
  import React, { forwardRef, useCallback, useImperativeHandle, useMemo } from 'react'
16
16
  import { Platform, StyleProp, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native'
17
17
  import { Pressable } from 'react-native-gesture-handler'
18
+ import { useFontScale } from '../../../../store/useFontScale'
18
19
  import { downloadFile } from '../../../../utils/downloadFile'
19
20
  import { LoadingImage } from '../../../loading/LoadingImage'
20
21
  import { FieldProps } from '../../types'
@@ -38,12 +39,13 @@ const NoFileView = ({ hasUpload, onPress }: { hasUpload?: boolean; onPress?: ()
38
39
  const textColor = useTextColor()
39
40
  const iconColor = useIconColor()
40
41
  const borderColor = useBorderColor()
42
+ const fontScale = useFontScale(s => s.fontScale)
41
43
  return (
42
44
  <Pressable style={[styles.noFileContainer, { borderColor }]} onPress={onPress}>
43
45
  <Text style={[styles.noFileText, { color: textColor }]}>
44
46
  {hasUpload ? 'Tap to upload file' : 'No file uploaded'}
45
47
  </Text>
46
- <Ionicons name="cloud-upload" size={24} color={iconColor} />
48
+ <Ionicons name="cloud-upload" size={24 * fontScale} color={iconColor} />
47
49
  </Pressable>
48
50
  )
49
51
  }
@@ -1,8 +1,8 @@
1
1
  import React, { useMemo } from 'react'
2
2
  import { Animated, StyleProp, StyleSheet, ViewStyle } from 'react-native'
3
3
  import { FadeInOptions, useFadeIn } from '../../hooks/useFadeIn'
4
+ import { useFontScale } from '../../store/useFontScale'
4
5
  import { CircularProgress, CircularProgressProps } from './CircularProgress'
5
-
6
6
  const loadingFadeInProps: FadeInOptions = {
7
7
  activeOpacity: 0.8,
8
8
  duration: 100,
@@ -22,10 +22,11 @@ export const LoadingOverlay = ({
22
22
  const opts = useMemo(() => ({ ...loadingFadeInProps, ...fadeOptions }), [fadeOptions])
23
23
  const opacity = useFadeIn(loading, opts)
24
24
 
25
+ const fontScale = useFontScale(s => s.fontScale)
25
26
  return (
26
27
  <Animated.View
27
28
  style={[styles.overlay, style, { opacity, pointerEvents: loading ? 'auto' : 'none' }]}>
28
- <CircularProgress {...indicatorProps} />
29
+ <CircularProgress size={indicatorProps?.size ?? 20 * fontScale} {...indicatorProps} />
29
30
  </Animated.View>
30
31
  )
31
32
  }
@@ -1,5 +1,6 @@
1
1
  import React, { PropsWithChildren, useEffect, useMemo, useRef } from 'react'
2
2
  import { Animated, StyleProp, TextStyle } from 'react-native'
3
+ import { useFontScale } from '../../store/useFontScale'
3
4
 
4
5
  export interface AnimatedTextProps {
5
6
  show: boolean
@@ -10,6 +11,7 @@ export interface AnimatedTextProps {
10
11
  }
11
12
  const useAnimatedText = (show: boolean, color: string, height: number, marginBottom: number) => {
12
13
  const placeholderAnim = useRef(new Animated.Value(0)).current
14
+ const fontScale = useFontScale(s => s.fontScale)
13
15
 
14
16
  useEffect(() => {
15
17
  Animated.timing(placeholderAnim, {
@@ -33,14 +35,14 @@ const useAnimatedText = (show: boolean, color: string, height: number, marginBot
33
35
  ],
34
36
  height: placeholderAnim.interpolate({
35
37
  inputRange: [0, 1],
36
- outputRange: [0, height],
38
+ outputRange: [0, height * fontScale],
37
39
  }),
38
40
  marginBottom: placeholderAnim.interpolate({
39
41
  inputRange: [0, 1],
40
- outputRange: [0, marginBottom],
42
+ outputRange: [0, marginBottom * fontScale],
41
43
  }),
42
44
  }),
43
- [color, height, marginBottom, placeholderAnim],
45
+ [color, height, marginBottom, placeholderAnim, fontScale],
44
46
  )
45
47
  }
46
48
 
@@ -13,6 +13,7 @@ import { en, registerTranslation } from 'react-native-paper-dates'
13
13
  import { MD3Type, MD3Typescale, ThemeProp } from 'react-native-paper/lib/typescript/types'
14
14
  import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'
15
15
  import { nativeToast } from '../constants/toast'
16
+ import { useRefreshFontScale } from '../hooks/useRefreshFontScale'
16
17
  import { UseThemeProps, useThemeState } from '../hooks/useThemeState'
17
18
  import { initializeScreen } from '../store/useScreen'
18
19
  import { ChempoFontsProvider } from './fonts'
@@ -30,6 +31,7 @@ export interface ChempoNativeProviderProps<
30
31
  colorModeProp?: string
31
32
  middlewareProvider?: MiddlewareProvider
32
33
  insetNotifier?: boolean
34
+ disableFontScaling?: boolean
33
35
  }
34
36
  const createPaperTheme = (
35
37
  themeConfig: Theme,
@@ -149,6 +151,7 @@ export const ChempoNativeProvider = <BackendAdapter extends BackendAdapterInterf
149
151
  colorModeProp,
150
152
  middlewareProvider: Middleware,
151
153
  insetNotifier,
154
+ disableFontScaling,
152
155
  ...props
153
156
  }: ChempoNativeProviderProps<BackendAdapter>) => {
154
157
  const useThemeProps = useMemo<UseThemeProps>(
@@ -156,6 +159,7 @@ export const ChempoNativeProvider = <BackendAdapter extends BackendAdapterInterf
156
159
  [themeProp, initialColorMode, colorModeProp],
157
160
  )
158
161
  const theme = useThemeState(useThemeProps)
162
+ useRefreshFontScale(disableFontScaling)
159
163
 
160
164
  const { theme: paperTheme, fonts } = useMemo(
161
165
  () => createPaperTheme(theme.theme ?? defaultTheme, fontConfig, theme.colorMode),
@@ -0,0 +1,26 @@
1
+ import { useEffect } from 'react'
2
+ import { AppState, PixelRatio } from 'react-native'
3
+ import { useFontScale } from '../store/useFontScale'
4
+
5
+ /**
6
+ * Subscribes to app state and refreshes the global font scale when the app
7
+ * becomes active (cold start or returning from background). Call once near the
8
+ * root of the app (e.g. in _layout).
9
+ */
10
+ export function useRefreshFontScale(disableFontScaling = false) {
11
+ useEffect(() => {
12
+ if (disableFontScaling) {
13
+ useFontScale.setState({ fontScale: 1 })
14
+ return () => {}
15
+ }
16
+ const refresh = () => useFontScale.setState({ fontScale: PixelRatio.getFontScale() ?? 1 })
17
+
18
+ refresh()
19
+
20
+ const sub = AppState.addEventListener('change', nextState => {
21
+ if (nextState === 'active') refresh()
22
+ })
23
+
24
+ return () => sub.remove()
25
+ }, [disableFontScaling])
26
+ }
@@ -1 +1,2 @@
1
+ export * from './useFontScale'
1
2
  export * from './useScreen'
@@ -0,0 +1,8 @@
1
+ import { PixelRatio } from 'react-native'
2
+ import { create } from 'zustand'
3
+
4
+ // export const normalizeFontScale = (fontScale: number) =>
5
+ // fontScale > 1 ? (fontScale - 1) * 0.5 + 1 : fontScale
6
+ export const useFontScale = create<{ fontScale: number }>(() => ({
7
+ fontScale: PixelRatio.getFontScale() ?? 1,
8
+ }))