@edge-zuq/core 1.2.7 → 1.3.4

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 (104) hide show
  1. package/README.md +2 -2
  2. package/lib/module/data/use-cases/remote-get-comment-list.js.map +1 -1
  3. package/lib/module/data/use-cases/remote-get-image-list.js.map +1 -1
  4. package/lib/module/infra/axios-http-client-adapter.js +45 -72
  5. package/lib/module/infra/axios-http-client-adapter.js.map +1 -1
  6. package/lib/module/infra/offline-mutation-queue.js.map +1 -1
  7. package/lib/module/infra/rnp-permission-manager-adapter.js.map +1 -1
  8. package/lib/module/presentation/components/atoms/UIIcon.js +40 -40
  9. package/lib/module/presentation/components/atoms/UIIcon.js.map +1 -1
  10. package/lib/module/presentation/components/atoms/UIProgress.js.map +1 -1
  11. package/lib/module/presentation/components/molecules/UIActionSheet.js.map +1 -1
  12. package/lib/module/presentation/components/molecules/UIButton.js +5 -5
  13. package/lib/module/presentation/components/molecules/UIButton.js.map +1 -1
  14. package/lib/module/presentation/components/molecules/UICurrencyInput.js.map +1 -1
  15. package/lib/module/presentation/components/molecules/UIDatetimeInput.js +1 -0
  16. package/lib/module/presentation/components/molecules/UIDatetimeInput.js.map +1 -1
  17. package/lib/module/presentation/components/molecules/UIImage.js.map +1 -1
  18. package/lib/module/presentation/components/molecules/UISkeleton.js +41 -9
  19. package/lib/module/presentation/components/molecules/UISkeleton.js.map +1 -1
  20. package/lib/module/presentation/components/molecules/UITextInput.js +6 -2
  21. package/lib/module/presentation/components/molecules/UITextInput.js.map +1 -1
  22. package/lib/module/presentation/components/molecules/UITextInputMask.js +6 -2
  23. package/lib/module/presentation/components/molecules/UITextInputMask.js.map +1 -1
  24. package/lib/module/presentation/components/organisms/UIFormButton.js.map +1 -1
  25. package/lib/module/presentation/components/organisms/UIFormCheckboxInput.js.map +1 -1
  26. package/lib/module/presentation/components/organisms/UIFormCurrencyInput.js.map +1 -1
  27. package/lib/module/presentation/components/organisms/UIFormDatetimeInput.js.map +1 -1
  28. package/lib/module/presentation/components/organisms/UIFormMultiselectInput.js.map +1 -1
  29. package/lib/module/presentation/components/organisms/UIFormSelectInput.js +8 -2
  30. package/lib/module/presentation/components/organisms/UIFormSelectInput.js.map +1 -1
  31. package/lib/module/presentation/components/organisms/UIFormTextInput.js.map +1 -1
  32. package/lib/module/presentation/components/organisms/UIMultipleSelectChip.js +129 -0
  33. package/lib/module/presentation/components/organisms/UIMultipleSelectChip.js.map +1 -0
  34. package/lib/module/presentation/components/organisms/UISelectChip.js +33 -2
  35. package/lib/module/presentation/components/organisms/UISelectChip.js.map +1 -1
  36. package/lib/module/presentation/components/organisms/UISignature.js +3 -2
  37. package/lib/module/presentation/components/organisms/UISignature.js.map +1 -1
  38. package/lib/module/presentation/components/organisms/UISlideButton.js.map +1 -1
  39. package/lib/module/presentation/components/organisms/index.js +1 -0
  40. package/lib/module/presentation/components/organisms/index.js.map +1 -1
  41. package/lib/module/presentation/components/permissions/request-permissions.js.map +1 -1
  42. package/lib/module/presentation/domain/offline/use-offline-mutation.js +1 -1
  43. package/lib/module/presentation/domain/offline/use-offline-mutation.js.map +1 -1
  44. package/lib/module/presentation/domain/offline/use-offline-query.js.map +1 -1
  45. package/lib/module/theme.js +22 -22
  46. package/lib/module/theme.js.map +1 -1
  47. package/lib/typescript/src/infra/axios-http-client-adapter.d.ts +1 -1
  48. package/lib/typescript/src/infra/axios-http-client-adapter.d.ts.map +1 -1
  49. package/lib/typescript/src/presentation/components/atoms/UIIcon.d.ts.map +1 -1
  50. package/lib/typescript/src/presentation/components/atoms/UIProgress.d.ts.map +1 -1
  51. package/lib/typescript/src/presentation/components/molecules/UIActionSheet.d.ts.map +1 -1
  52. package/lib/typescript/src/presentation/components/molecules/UIButton.d.ts.map +1 -1
  53. package/lib/typescript/src/presentation/components/molecules/UIDatetimeInput.d.ts.map +1 -1
  54. package/lib/typescript/src/presentation/components/molecules/UIImage.d.ts.map +1 -1
  55. package/lib/typescript/src/presentation/components/molecules/UISkeleton.d.ts +3 -1
  56. package/lib/typescript/src/presentation/components/molecules/UISkeleton.d.ts.map +1 -1
  57. package/lib/typescript/src/presentation/components/molecules/UITextInput.d.ts +1 -0
  58. package/lib/typescript/src/presentation/components/molecules/UITextInput.d.ts.map +1 -1
  59. package/lib/typescript/src/presentation/components/molecules/UITextInputMask.d.ts +1 -0
  60. package/lib/typescript/src/presentation/components/molecules/UITextInputMask.d.ts.map +1 -1
  61. package/lib/typescript/src/presentation/components/organisms/UIFormMultiselectInput.d.ts.map +1 -1
  62. package/lib/typescript/src/presentation/components/organisms/UIFormSelectInput.d.ts +4 -1
  63. package/lib/typescript/src/presentation/components/organisms/UIFormSelectInput.d.ts.map +1 -1
  64. package/lib/typescript/src/presentation/components/organisms/UIMultipleSelectChip.d.ts +17 -0
  65. package/lib/typescript/src/presentation/components/organisms/UIMultipleSelectChip.d.ts.map +1 -0
  66. package/lib/typescript/src/presentation/components/organisms/UISelectChip.d.ts +6 -2
  67. package/lib/typescript/src/presentation/components/organisms/UISelectChip.d.ts.map +1 -1
  68. package/lib/typescript/src/presentation/components/organisms/UISignature.d.ts.map +1 -1
  69. package/lib/typescript/src/presentation/components/organisms/UISlideButton.d.ts.map +1 -1
  70. package/lib/typescript/src/presentation/components/organisms/index.d.ts +1 -0
  71. package/lib/typescript/src/presentation/components/organisms/index.d.ts.map +1 -1
  72. package/lib/typescript/src/presentation/components/permissions/request-permissions.d.ts.map +1 -1
  73. package/package.json +71 -75
  74. package/src/data/use-cases/remote-get-comment-list.ts +1 -1
  75. package/src/data/use-cases/remote-get-image-list.ts +2 -2
  76. package/src/infra/axios-http-client-adapter.ts +46 -70
  77. package/src/infra/offline-mutation-queue.ts +4 -4
  78. package/src/infra/rnp-permission-manager-adapter.ts +4 -4
  79. package/src/presentation/components/atoms/UIIcon.tsx +75 -110
  80. package/src/presentation/components/atoms/UIProgress.tsx +2 -3
  81. package/src/presentation/components/molecules/UIActionSheet.tsx +9 -13
  82. package/src/presentation/components/molecules/UIButton.tsx +6 -7
  83. package/src/presentation/components/molecules/UICurrencyInput.tsx +2 -2
  84. package/src/presentation/components/molecules/UIDatetimeInput.tsx +1 -0
  85. package/src/presentation/components/molecules/UIImage.tsx +3 -5
  86. package/src/presentation/components/molecules/UISkeleton.tsx +19 -7
  87. package/src/presentation/components/molecules/UITextInput.tsx +8 -7
  88. package/src/presentation/components/molecules/UITextInputMask.tsx +8 -7
  89. package/src/presentation/components/organisms/UIFormButton.tsx +1 -1
  90. package/src/presentation/components/organisms/UIFormCheckboxInput.tsx +1 -1
  91. package/src/presentation/components/organisms/UIFormCurrencyInput.tsx +1 -1
  92. package/src/presentation/components/organisms/UIFormDatetimeInput.tsx +1 -1
  93. package/src/presentation/components/organisms/UIFormMultiselectInput.tsx +7 -9
  94. package/src/presentation/components/organisms/UIFormSelectInput.tsx +13 -6
  95. package/src/presentation/components/organisms/UIFormTextInput.tsx +1 -1
  96. package/src/presentation/components/organisms/UIMultipleSelectChip.tsx +139 -0
  97. package/src/presentation/components/organisms/UISelectChip.tsx +26 -3
  98. package/src/presentation/components/organisms/UISignature.tsx +10 -8
  99. package/src/presentation/components/organisms/UISlideButton.tsx +5 -7
  100. package/src/presentation/components/organisms/index.ts +1 -0
  101. package/src/presentation/components/permissions/request-permissions.tsx +5 -7
  102. package/src/presentation/domain/offline/use-offline-mutation.ts +2 -2
  103. package/src/presentation/domain/offline/use-offline-query.ts +1 -1
  104. package/src/theme.ts +22 -22
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { StyleSheet } from 'react-native';
2
+ import { StyleSheet, type ViewStyle, type StyleProp } from 'react-native';
3
3
  import Animated, {
4
4
  cancelAnimation,
5
5
  interpolate,
@@ -9,14 +9,17 @@ import Animated, {
9
9
  withTiming,
10
10
  } from 'react-native-reanimated';
11
11
  import { UIStack } from '../atoms';
12
+ import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
13
+ import { theme } from '../../../theme';
12
14
 
13
15
  type Props = {
14
16
  circle?: boolean;
15
17
  width: number;
16
18
  height: number;
19
+ style?: StyleProp<ViewStyle>;
17
20
  };
18
21
 
19
- export const UISkeleton = ({ width, height, circle }: Props) => {
22
+ export const UISkeleton = ({ width, height, circle, style }: Props) => {
20
23
  const translateX = useSharedValue(0);
21
24
  const animatedStyle = useAnimatedStyle(() => {
22
25
  return {
@@ -38,6 +41,7 @@ export const UISkeleton = ({ width, height, circle }: Props) => {
38
41
  style={[
39
42
  styles.skeleton,
40
43
  { width, height, borderRadius: circle ? width / 2 : 2 },
44
+ style,
41
45
  ]}
42
46
  >
43
47
  <Animated.View
@@ -46,20 +50,28 @@ export const UISkeleton = ({ width, height, circle }: Props) => {
46
50
  {
47
51
  width: 0.9 * width,
48
52
  height,
49
- opacity: 0.125,
50
53
  borderRadius: circle ? width / 2 : 2,
51
- backgroundColor: '#000',
52
54
  },
53
55
  ]}
54
- />
56
+ >
57
+ <Svg height={height} width={width}>
58
+ <Defs>
59
+ <LinearGradient id="grad" x1="0" y1="0" x2="1" y2="0">
60
+ <Stop offset="0" stopColor="white" stopOpacity="0" />
61
+ <Stop offset="0.5" stopColor="white" stopOpacity="0.5" />
62
+ <Stop offset="1" stopColor="white" stopOpacity="0" />
63
+ </LinearGradient>
64
+ </Defs>
65
+ <Rect x="0" y="0" width={width} height={height} fill="url(#grad)" />
66
+ </Svg>
67
+ </Animated.View>
55
68
  </UIStack>
56
69
  );
57
70
  };
58
71
 
59
72
  const styles = StyleSheet.create({
60
73
  skeleton: {
61
- backgroundColor: '#000',
62
- opacity: 0.1,
74
+ backgroundColor: theme.color.neutral.light['20'],
63
75
  borderRadius: 2,
64
76
  overflow: 'hidden',
65
77
  },
@@ -12,6 +12,7 @@ type Props = React.ComponentProps<typeof TextInput> & {
12
12
  label?: string;
13
13
  containerStyle?: StyleProp<ViewStyle>;
14
14
  wrapperStyle?: StyleProp<ViewStyle>;
15
+ required?: boolean;
15
16
  };
16
17
 
17
18
  export const UITextInput = React.forwardRef<TextInput, Props>(
@@ -29,6 +30,7 @@ export const UITextInput = React.forwardRef<TextInput, Props>(
29
30
  wrapperStyle,
30
31
  editable = true,
31
32
  value,
33
+ required,
32
34
  ...props
33
35
  },
34
36
  ref
@@ -36,7 +38,7 @@ export const UITextInput = React.forwardRef<TextInput, Props>(
36
38
  const [hidden, setHidden] = React.useState(secureTextEntry);
37
39
  const [focused, setFocused] = React.useState(false);
38
40
 
39
- const toggleHidden = () => setHidden((value) => !value);
41
+ const toggleHidden = () => setHidden(value => !value);
40
42
 
41
43
  return (
42
44
  <View style={wrapperStyle}>
@@ -44,9 +46,9 @@ export const UITextInput = React.forwardRef<TextInput, Props>(
44
46
  <UIText
45
47
  weight="700"
46
48
  variant="label"
47
- style={[styles.label, focused && styles.labelFocused]}
48
- >
49
+ style={[styles.label, focused && styles.labelFocused]}>
49
50
  {label}
51
+ {required && <UIText color="feedback-red-500"> *</UIText>}
50
52
  </UIText>
51
53
  )}
52
54
  <View
@@ -57,8 +59,7 @@ export const UITextInput = React.forwardRef<TextInput, Props>(
57
59
  Boolean(endIcon) && styles.endIcon,
58
60
  styles[variant],
59
61
  containerStyle,
60
- ]}
61
- >
62
+ ]}>
62
63
  {startIcon && React.cloneElement(startIcon, { focused })}
63
64
  <TextInput
64
65
  accessible
@@ -76,11 +77,11 @@ export const UITextInput = React.forwardRef<TextInput, Props>(
76
77
  Boolean(endIcon) && styles.endIcon,
77
78
  style,
78
79
  ]}
79
- onFocus={(e) => {
80
+ onFocus={e => {
80
81
  setFocused(true);
81
82
  onFocus?.(e);
82
83
  }}
83
- onBlur={(e) => {
84
+ onBlur={e => {
84
85
  setFocused(false);
85
86
  onBlur?.(e);
86
87
  }}
@@ -14,6 +14,7 @@ type Props = React.ComponentProps<typeof MaskInput> & {
14
14
  containerStyle?: StyleProp<ViewStyle>;
15
15
  wrapperStyle?: StyleProp<ViewStyle>;
16
16
  mask?: Mask;
17
+ required?: boolean;
17
18
  };
18
19
 
19
20
  export const UITextInputMask = React.forwardRef<TextInput, Props>(
@@ -32,6 +33,7 @@ export const UITextInputMask = React.forwardRef<TextInput, Props>(
32
33
  mask,
33
34
  value,
34
35
  editable = true,
36
+ required,
35
37
  ...props
36
38
  },
37
39
  ref
@@ -39,7 +41,7 @@ export const UITextInputMask = React.forwardRef<TextInput, Props>(
39
41
  const [hidden, setHidden] = React.useState(secureTextEntry);
40
42
  const [focused, setFocused] = React.useState(false);
41
43
 
42
- const toggleHidden = () => setHidden((value) => !value);
44
+ const toggleHidden = () => setHidden(value => !value);
43
45
 
44
46
  return (
45
47
  <View style={wrapperStyle}>
@@ -47,9 +49,9 @@ export const UITextInputMask = React.forwardRef<TextInput, Props>(
47
49
  <UIText
48
50
  weight="700"
49
51
  variant="label"
50
- style={[styles.label, focused && styles.labelFocused]}
51
- >
52
+ style={[styles.label, focused && styles.labelFocused]}>
52
53
  {label}
54
+ {required && <UIText color="feedback-red-500"> *</UIText>}
53
55
  </UIText>
54
56
  )}
55
57
  <View
@@ -58,8 +60,7 @@ export const UITextInputMask = React.forwardRef<TextInput, Props>(
58
60
  focused && styles.focused,
59
61
  styles[variant],
60
62
  containerStyle,
61
- ]}
62
- >
63
+ ]}>
63
64
  {startIcon && React.cloneElement(startIcon, { focused })}
64
65
  <MaskInput
65
66
  ref={ref}
@@ -76,11 +77,11 @@ export const UITextInputMask = React.forwardRef<TextInput, Props>(
76
77
  !editable && Boolean(value) && styles.disabled,
77
78
  style,
78
79
  ]}
79
- onFocus={(e) => {
80
+ onFocus={e => {
80
81
  setFocused(true);
81
82
  onFocus?.(e);
82
83
  }}
83
- onBlur={(e) => {
84
+ onBlur={e => {
84
85
  setFocused(false);
85
86
  onBlur?.(e);
86
87
  }}
@@ -18,7 +18,7 @@ export const UIFormButton = ({
18
18
  const { handleSubmit, setError, clearErrors, reset } = useFormContext();
19
19
 
20
20
  const onPress = handleSubmit(
21
- async (values) => {
21
+ async values => {
22
22
  try {
23
23
  await KeyboardController.dismiss({ animated: false, keepFocus: false });
24
24
  clearErrors('_formError');
@@ -19,7 +19,7 @@ export const UIFormCheckboxInput = ({
19
19
 
20
20
  return (
21
21
  <UICheckboxInput
22
- onPress={(e) => {
22
+ onPress={e => {
23
23
  onPress?.(e);
24
24
  const { value: current, onChange } = field;
25
25
  if (current?.includes(value)) {
@@ -33,7 +33,7 @@ export const UIFormCurrencyInput = React.forwardRef<TextInput, Props>(
33
33
  <UICurrencyInput
34
34
  ref={ref}
35
35
  value={value}
36
- onChangeValue={(value) => {
36
+ onChangeValue={value => {
37
37
  field.onChange(String(value ?? ''));
38
38
  onChangeValue?.(value);
39
39
  }}
@@ -27,7 +27,7 @@ export const UIFormDatetimeInput = ({
27
27
  <UIStack style={[styles.container, formContainerStyle]}>
28
28
  <UIDatetimeInput
29
29
  value={field.value && new Date(field.value)}
30
- onSelect={(date) => {
30
+ onSelect={date => {
31
31
  field.onChange(date.getTime());
32
32
  }}
33
33
  {...props}
@@ -109,12 +109,12 @@ export const UIFormMultiselectInput = <T,>({
109
109
  const onSelect = (item: T) => {
110
110
  const current = (getValuesContext(name) ?? []) as T[];
111
111
  const isSelected = current.find(
112
- (value) => getItemKey(value) === getItemKey(item)
112
+ value => getItemKey(value) === getItemKey(item)
113
113
  );
114
114
  if (isSelected) {
115
115
  setValueContext(
116
116
  name,
117
- current.filter((data) => getItemKey(data) !== getItemKey(item))
117
+ current.filter(data => getItemKey(data) !== getItemKey(item))
118
118
  );
119
119
  } else {
120
120
  setValueContext(name, [...current, item]);
@@ -136,7 +136,7 @@ export const UIFormMultiselectInput = <T,>({
136
136
  if (!data) return [];
137
137
  if (!Array.isArray(data)) return [];
138
138
  if (!search) return data;
139
- return data.filter((item) =>
139
+ return data.filter(item =>
140
140
  String(getItemLabel(item) ?? '')
141
141
  .toLowerCase()
142
142
  .includes(search.toLowerCase())
@@ -145,7 +145,7 @@ export const UIFormMultiselectInput = <T,>({
145
145
 
146
146
  const value = React.useMemo(() => {
147
147
  const current = (getValuesContext(name) ?? []) as T[];
148
- return current.map((value) => getItemLabel(value)).join(', ');
148
+ return current.map(value => getItemLabel(value)).join(', ');
149
149
  }, [name, getItemLabel, getValuesContext, watchContext(name)]); //eslint-disable-line
150
150
 
151
151
  return (
@@ -165,8 +165,7 @@ export const UIFormMultiselectInput = <T,>({
165
165
  visible={visible}
166
166
  onRequestClose={onClose}
167
167
  title={title}
168
- style={[styles.sheet, sheetStyle]}
169
- >
168
+ style={[styles.sheet, sheetStyle]}>
170
169
  <UIStack>
171
170
  <UIForm schema={schema} form={form} style={styles.form}>
172
171
  <UIFormTextInput
@@ -185,8 +184,7 @@ export const UIFormMultiselectInput = <T,>({
185
184
  loading={isCreating}
186
185
  variant={createVariant}
187
186
  onSubmit={onSubmit}
188
- getErrorMessage={getErrorMessage}
189
- >
187
+ getErrorMessage={getErrorMessage}>
190
188
  <UIStack style={styles.create} horizontal center>
191
189
  <UIText color="neutral-light-00">{createMessage}</UIText>
192
190
  <UIIcon
@@ -218,7 +216,7 @@ export const UIFormMultiselectInput = <T,>({
218
216
  renderItem={({ item }) => {
219
217
  const current = (watchContext(name) ?? []) as T[];
220
218
  const isSelected = Boolean(
221
- current.find((value) => getItemKey(value) === getItemKey(item))
219
+ current.find(value => getItemKey(value) === getItemKey(item))
222
220
  );
223
221
  const label = String(getItemLabel(item));
224
222
  return (
@@ -73,6 +73,9 @@ type Props<T> = {
73
73
  enableClientSearch?: boolean;
74
74
  onFocus?: () => void;
75
75
  onBlur?: () => void;
76
+ testID?: string;
77
+ accessibilityLabel?: string;
78
+ required?: boolean;
76
79
  };
77
80
 
78
81
  export const UIFormSelectInput = <T,>({
@@ -111,6 +114,9 @@ export const UIFormSelectInput = <T,>({
111
114
  inputFormContainerStyle,
112
115
  onFocus,
113
116
  onBlur,
117
+ testID,
118
+ accessibilityLabel,
119
+ required,
114
120
  }: Props<T>) => {
115
121
  const ref = React.useRef<TextInput>(null);
116
122
  const { visible, onClose: onCloseFromHook, onOpen } = useActionSheet();
@@ -168,7 +174,7 @@ export const UIFormSelectInput = <T,>({
168
174
  if (!Array.isArray(data)) return [];
169
175
  let filtered = data;
170
176
  if (enableClientSearch && search) {
171
- filtered = data.filter((item) =>
177
+ filtered = data.filter(item =>
172
178
  String(getItemLabel(item) ?? '')
173
179
  .toLowerCase()
174
180
  .includes(search.toLowerCase())
@@ -218,14 +224,16 @@ export const UIFormSelectInput = <T,>({
218
224
  style={inputStyle}
219
225
  containerStyle={inputContainerStyle}
220
226
  formContainerStyle={inputFormContainerStyle}
227
+ testID={testID}
228
+ accessibilityLabel={accessibilityLabel}
229
+ required={required}
221
230
  />
222
231
  <UIActionSheet
223
232
  visible={visible}
224
233
  onRequestClose={onClose}
225
234
  title={title}
226
235
  style={sheetStyle}
227
- estimatedHeight={520}
228
- >
236
+ estimatedHeight={520}>
229
237
  <UIStack flex={1}>
230
238
  <UIForm schema={schema} form={form} style={styles.form}>
231
239
  <UIStack horizontal center>
@@ -233,7 +241,7 @@ export const UIFormSelectInput = <T,>({
233
241
  name="search"
234
242
  placeholder={searchPlaceholder}
235
243
  variant={searchVariant}
236
- onChangeText={(text) => onSearchDebounced(text)}
244
+ onChangeText={text => onSearchDebounced(text)}
237
245
  endIcon={<UIInputIcon position="end" name="search" size={24} />}
238
246
  />
239
247
  {action}
@@ -248,8 +256,7 @@ export const UIFormSelectInput = <T,>({
248
256
  loading={isCreating}
249
257
  variant={createVariant}
250
258
  onSubmit={onSubmit}
251
- getErrorMessage={getErrorMessage}
252
- >
259
+ getErrorMessage={getErrorMessage}>
253
260
  <UIStack style={styles.create} horizontal center>
254
261
  <UIText color="neutral-light-00">{createMessage}</UIText>
255
262
  <UIIcon
@@ -36,7 +36,7 @@ export const UIFormTextInput = React.forwardRef<TextInput, Props>(
36
36
  ref={ref}
37
37
  value={field.value}
38
38
  editable={isSubmitting || editable}
39
- onChangeText={(text) => {
39
+ onChangeText={text => {
40
40
  field.onChange(text);
41
41
  onChangeText?.(text);
42
42
  }}
@@ -0,0 +1,139 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { UIButton, UIChip, UIList, UISkeleton } from '../molecules';
3
+ import { UIIcon, UISeparator, UISpacer, UIStack, UIText } from '../atoms';
4
+ import { theme } from '../../../theme';
5
+
6
+ type PropsToOmit = 'renderItem' | 'ItemSeparatorComponent';
7
+
8
+ type Props<T> = Omit<React.ComponentProps<typeof UIList<T>>, PropsToOmit> & {
9
+ data: T[];
10
+ getItemLabel: (item: T) => string;
11
+ getItemKey: (item: T) => string;
12
+ selected: T[];
13
+ onSelect: (item: T) => void;
14
+ onReset: () => void;
15
+ loading?: boolean;
16
+ };
17
+
18
+ export const UIMultipleSelectChip = <T,>({
19
+ data,
20
+ getItemLabel,
21
+ getItemKey,
22
+ selected,
23
+ onSelect,
24
+ onReset,
25
+ loading = false,
26
+ ...props
27
+ }: Props<T>) => {
28
+ const isAllSelected = selected.length === 0;
29
+
30
+ const isSelected = (item: T) => {
31
+ return selected.some(
32
+ currentItem => getItemKey(currentItem) === getItemKey(item)
33
+ );
34
+ };
35
+
36
+ if (loading) return <UIMultipleSelectChip.Skeleton />;
37
+
38
+ return (
39
+ <UIList
40
+ horizontal
41
+ data={data}
42
+ ListHeaderComponent={() => (
43
+ <UIStack horizontal center size="md" style={styles.header}>
44
+ <UIButton onPress={() => onReset()} style={styles.button}>
45
+ <UIChip
46
+ content={
47
+ <UIStack horizontal center>
48
+ {isAllSelected && (
49
+ <UIIcon
50
+ name="check-alt"
51
+ color={theme.color.neutral.light['00']}
52
+ />
53
+ )}
54
+ <UIText
55
+ weight="500"
56
+ color={
57
+ isAllSelected ? 'neutral-light-00' : 'neutral-mid-60'
58
+ }>
59
+ Todos
60
+ </UIText>
61
+ </UIStack>
62
+ }
63
+ color={isAllSelected ? 'brand-violet-500' : 'neutral-light-05'}
64
+ borderColor={
65
+ isAllSelected ? 'brand-violet-500' : 'neutral-light-50'
66
+ }
67
+ style={styles.chip}
68
+ />
69
+ </UIButton>
70
+ <UISeparator horizontal={false} />
71
+ </UIStack>
72
+ )}
73
+ renderItem={({ item }) => {
74
+ const isSelectedItem = isSelected(item);
75
+ return (
76
+ <UIButton onPress={() => onSelect(item)} style={styles.button}>
77
+ <UIChip
78
+ content={
79
+ <UIStack horizontal center>
80
+ {isSelectedItem && (
81
+ <UIIcon
82
+ name="check-alt"
83
+ color={theme.color.neutral.light['00']}
84
+ />
85
+ )}
86
+ <UIText
87
+ weight="500"
88
+ color={
89
+ isSelectedItem ? 'neutral-light-00' : 'neutral-mid-60'
90
+ }>
91
+ {getItemLabel(item)}
92
+ </UIText>
93
+ </UIStack>
94
+ }
95
+ color={isSelectedItem ? 'brand-violet-500' : 'neutral-light-05'}
96
+ borderColor={
97
+ isSelectedItem ? 'brand-violet-500' : 'neutral-light-50'
98
+ }
99
+ style={styles.chip}
100
+ />
101
+ </UIButton>
102
+ );
103
+ }}
104
+ ItemSeparatorComponent={() => <UISpacer horizontal />}
105
+ {...props}
106
+ />
107
+ );
108
+ };
109
+
110
+ UIMultipleSelectChip.Skeleton = () => {
111
+ return (
112
+ <UIList
113
+ horizontal
114
+ data={Array.from({ length: 3 })}
115
+ renderItem={() => <UISkeleton width={100} height={36} circle />}
116
+ ListHeaderComponent={() => (
117
+ <UIStack horizontal center size="md" style={styles.header}>
118
+ <UISkeleton width={85} height={36} circle />
119
+ <UISeparator horizontal={false} />
120
+ </UIStack>
121
+ )}
122
+ ItemSeparatorComponent={() => <UISpacer horizontal />}
123
+ />
124
+ );
125
+ };
126
+
127
+ const styles = StyleSheet.create({
128
+ chip: {
129
+ paddingTop: 6,
130
+ paddingBottom: 6,
131
+ paddingHorizontal: 16,
132
+ },
133
+ header: {
134
+ marginRight: 8,
135
+ },
136
+ button: {
137
+ padding: 0,
138
+ },
139
+ });
@@ -1,5 +1,5 @@
1
1
  import { StyleSheet } from 'react-native';
2
- import { UIButton, UIChip, UIList } from '../molecules';
2
+ import { UIButton, UIChip, UIList, UISkeleton } from '../molecules';
3
3
  import { UIIcon, UISeparator, UISpacer, UIStack, UIText } from '../atoms';
4
4
  import { theme } from '../../../theme';
5
5
 
@@ -9,9 +9,10 @@ type Props<T> = Omit<React.ComponentProps<typeof UIList<T>>, PropsToOmit> & {
9
9
  data: T[];
10
10
  getItemLabel: (item: T) => string;
11
11
  getItemKey: (item: T) => string;
12
- selected: T;
12
+ selected: T | null;
13
13
  onSelect: (item: T) => void;
14
14
  onReset: () => void;
15
+ loading?: boolean;
15
16
  };
16
17
 
17
18
  export const UISelectChip = <T,>({
@@ -21,14 +22,19 @@ export const UISelectChip = <T,>({
21
22
  selected,
22
23
  onSelect,
23
24
  onReset,
25
+ loading = false,
24
26
  ...props
25
27
  }: Props<T>) => {
28
+ if (loading) return <UISelectChip.Skeleton />;
29
+
26
30
  return (
27
31
  <UIList
28
32
  horizontal
29
33
  data={data}
30
34
  renderItem={({ item }) => {
31
- const isSelected = getItemKey(selected) === getItemKey(item);
35
+ const isSelected = Boolean(
36
+ selected && getItemKey(selected) === getItemKey(item)
37
+ );
32
38
  return (
33
39
  <UIButton onPress={() => onSelect(item)} style={styles.button}>
34
40
  <UIChip
@@ -89,6 +95,23 @@ export const UISelectChip = <T,>({
89
95
  );
90
96
  };
91
97
 
98
+ UISelectChip.Skeleton = () => {
99
+ return (
100
+ <UIList
101
+ horizontal
102
+ data={Array.from({ length: 3 })}
103
+ renderItem={() => <UISkeleton width={100} height={36} circle />}
104
+ ListHeaderComponent={() => (
105
+ <UIStack horizontal center size="md" style={styles.header}>
106
+ <UISkeleton width={85} height={36} circle />
107
+ <UISeparator horizontal={false} />
108
+ </UIStack>
109
+ )}
110
+ ItemSeparatorComponent={() => <UISpacer horizontal />}
111
+ />
112
+ );
113
+ };
114
+
92
115
  const styles = StyleSheet.create({
93
116
  chip: {
94
117
  paddingTop: 6,
@@ -6,7 +6,7 @@ import {
6
6
  useCanvasRef,
7
7
  } from '@shopify/react-native-skia';
8
8
  import React from 'react';
9
- import { Dimensions, Image, StyleSheet } from 'react-native';
9
+ import { Dimensions, Image, Platform, StyleSheet } from 'react-native';
10
10
  import ReactNativeBlobUtil from 'react-native-blob-util';
11
11
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
12
12
  import { useSharedValue } from 'react-native-reanimated';
@@ -76,7 +76,11 @@ export const UISignature = ({
76
76
  const image = canvasRef.current?.makeImageSnapshot(SNAPSHOT_PARAMS);
77
77
  if (!image) return;
78
78
  const name = `${Date.now()}.png`;
79
- const path = ReactNativeBlobUtil.fs.dirs.DCIMDir + `/signatures/${name}`;
79
+ const directory =
80
+ Platform.OS === 'android'
81
+ ? ReactNativeBlobUtil.fs.dirs.DCIMDir
82
+ : ReactNativeBlobUtil.fs.dirs.DocumentDir;
83
+ const path = directory + `/signatures/${name}`;
80
84
  const base64 = image.encodeToBase64();
81
85
  await ReactNativeBlobUtil.fs.writeFile(path, base64, 'base64');
82
86
  const values = {
@@ -93,13 +97,13 @@ export const UISignature = ({
93
97
  .averageTouches(true)
94
98
  .maxPointers(1)
95
99
  .minDistance(1)
96
- .onStart((e) => {
100
+ .onStart(e => {
97
101
  currentPath.value.moveTo(e.x, e.y);
98
102
  currentPath.value.lineTo(e.x, e.y);
99
103
  notifyChange(currentPath);
100
104
  if (onTouchStart) scheduleOnRN(onTouchStart);
101
105
  })
102
- .onUpdate((e) => {
106
+ .onUpdate(e => {
103
107
  scheduleOnRN(setIsDirty, true);
104
108
  currentPath.value.lineTo(e.x, e.y);
105
109
  notifyChange(currentPath);
@@ -136,8 +140,7 @@ export const UISignature = ({
136
140
  ref={canvasRef}
137
141
  testID={testID}
138
142
  accessibilityLabel={accessibilityLabel}
139
- style={[styles.container, signatureStyle]}
140
- >
143
+ style={[styles.container, signatureStyle]}>
141
144
  <Path
142
145
  path={currentPath}
143
146
  strokeWidth={5}
@@ -154,8 +157,7 @@ export const UISignature = ({
154
157
  <UIButton
155
158
  style={styles.clear}
156
159
  onPress={resetSignature}
157
- disabled={disabled}
158
- >
160
+ disabled={disabled}>
159
161
  <UIIcon name="close" />
160
162
  </UIButton>
161
163
  </UIStack>
@@ -46,7 +46,7 @@ export const UISlideButton = ({ children, helperText, onPress }: Props) => {
46
46
  });
47
47
 
48
48
  const pan = Gesture.Pan()
49
- .onUpdate((event) => {
49
+ .onUpdate(event => {
50
50
  animation.value = interpolate(
51
51
  clamp(event.translationX, 0, max),
52
52
  [0, max],
@@ -69,10 +69,9 @@ export const UISlideButton = ({ children, helperText, onPress }: Props) => {
69
69
  return (
70
70
  <UIStack
71
71
  style={styles.container}
72
- onLayout={(event) => {
72
+ onLayout={event => {
73
73
  setContainerWidth(event.nativeEvent.layout.width);
74
- }}
75
- >
74
+ }}>
76
75
  {helperText && (
77
76
  <Animated.View style={[styles.text, labelAnimatedStyle]}>
78
77
  <UIText weight="600">{helperText}</UIText>
@@ -83,10 +82,9 @@ export const UISlideButton = ({ children, helperText, onPress }: Props) => {
83
82
  <UIButton
84
83
  variant="contained"
85
84
  style={styles.button}
86
- onLayout={(event) => {
85
+ onLayout={event => {
87
86
  setButtonWidth(event.nativeEvent.layout.width);
88
- }}
89
- >
87
+ }}>
90
88
  {children}
91
89
  </UIButton>
92
90
  </Animated.View>
@@ -19,3 +19,4 @@ export * from './UISearchInput';
19
19
  export * from './UISelectChip';
20
20
  export * from './UIErrorBoundary';
21
21
  export * from './UISignature';
22
+ export * from './UIMultipleSelectChip';