@momo-kits/foundation 0.169.9 → 0.169.10-beta.1

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 (56) hide show
  1. package/Application/BottomSheet.hooks.ts +17 -27
  2. package/Application/BottomSheet.tsx +27 -35
  3. package/Application/BottomTab/BottomTabBar.tsx +6 -6
  4. package/Application/BottomTab/DuoRailTabBar.tsx +5 -5
  5. package/Application/BottomTab/TabScreen.tsx +10 -11
  6. package/Application/BottomTab/index.tsx +5 -5
  7. package/Application/BottomTab/usePressLift.ts +3 -3
  8. package/Application/Components/HeaderAnimated.tsx +38 -13
  9. package/Application/Components/HeaderBackground.tsx +16 -3
  10. package/Application/Components/HeaderExtendHeader.tsx +41 -28
  11. package/Application/Components/HeaderLeft.tsx +4 -18
  12. package/Application/Components/HeaderRight.styles.ts +15 -13
  13. package/Application/Components/HeaderTitle.shared.ts +10 -11
  14. package/Application/Components/HeaderToolkitAction.tsx +21 -54
  15. package/Application/Components/NavigationButton.tsx +9 -6
  16. package/Application/Components/SearchHeader.tsx +20 -7
  17. package/Application/Components/useToolkitActions.tsx +21 -22
  18. package/Application/ModalScreen.tsx +15 -19
  19. package/Application/StackScreen.tsx +18 -13
  20. package/Application/headerLayout.ts +165 -0
  21. package/Application/index.ts +11 -1
  22. package/Application/modalLayout.ts +0 -1
  23. package/Application/navigationOptions.tsx +6 -15
  24. package/Application/types.header.ts +7 -2
  25. package/Application/types.ts +7 -0
  26. package/Context/index.ts +1 -3
  27. package/Image/index.tsx +6 -6
  28. package/Input/Input.tsx +37 -40
  29. package/Input/InputDropDown.tsx +10 -13
  30. package/Input/InputMoney.tsx +17 -17
  31. package/Input/InputMoneyView.tsx +12 -12
  32. package/Input/InputOTP.tsx +34 -46
  33. package/Input/InputPhoneNumber.tsx +43 -48
  34. package/Input/InputSearch.tsx +39 -26
  35. package/Input/InputTextArea.tsx +23 -29
  36. package/Input/common.tsx +257 -0
  37. package/Input/index.tsx +7 -1
  38. package/Input/moneyUtils.ts +23 -0
  39. package/Input/utils.ts +7 -126
  40. package/Layout/FloatingButton.tsx +24 -38
  41. package/Layout/Screen.tsx +3 -0
  42. package/Layout/layoutMetrics.ts +34 -43
  43. package/Layout/screenHeader.tsx +55 -52
  44. package/Layout/screenTypes.ts +13 -4
  45. package/Pagination/PaginationScroll.tsx +3 -5
  46. package/Pagination/types.ts +5 -3
  47. package/Popup/PopupNotify.tsx +14 -17
  48. package/Popup/PopupPromotion.tsx +4 -5
  49. package/Popup/types.ts +4 -2
  50. package/Popup/utils.ts +4 -7
  51. package/Skeleton/index.tsx +12 -15
  52. package/package.json +1 -1
  53. package/Input/ErrorView.tsx +0 -59
  54. package/Input/FloatingView.tsx +0 -101
  55. package/Input/RenderTrailing.tsx +0 -79
  56. package/Input/constants.ts +0 -8
@@ -0,0 +1,257 @@
1
+ import React, { FC, ReactNode, useContext } from 'react';
2
+ import {
3
+ GestureResponderEvent,
4
+ TouchableOpacity,
5
+ View,
6
+ ViewStyle,
7
+ } from 'react-native';
8
+ import { ApplicationContext } from '../Context';
9
+ import { Theme } from '../Application/types';
10
+ import { Styles } from '../Consts';
11
+ import { Icon } from '../Icon';
12
+ import { useScaleSize, Text } from '../Text';
13
+ import styles from './styles';
14
+ import { Loader } from '../Loader';
15
+ import IconSources from '../Assets/icon.json';
16
+
17
+ type FloatingViewProps = {
18
+ floatingValue?: string;
19
+ floatingIconColor?: string;
20
+ componentId?: string;
21
+ disabled?: boolean;
22
+ floatingIcon?: string;
23
+ required?: boolean;
24
+ style?: ViewStyle;
25
+ onPress?: (e: GestureResponderEvent) => void;
26
+ };
27
+
28
+ type TrailingProps = {
29
+ loading?: boolean;
30
+ color?: string;
31
+ icon?: string;
32
+ componentId?: string;
33
+ onPressIcon?: () => void;
34
+ };
35
+
36
+ export const MAX_LENGTH = 300;
37
+
38
+ /** Border color by state; priority is disabled > error > focused > default. */
39
+ export const getBorderColor = (
40
+ theme: Theme,
41
+ focused: boolean,
42
+ errorMessage?: string,
43
+ disabled?: boolean,
44
+ ) => {
45
+ let borderColor = theme.colors.border.default;
46
+
47
+ if (focused) {
48
+ borderColor = theme.colors.primary;
49
+ }
50
+
51
+ if (errorMessage) {
52
+ borderColor = theme.colors.error.primary;
53
+ }
54
+
55
+ if (disabled) {
56
+ borderColor = theme.colors.border.disable;
57
+ }
58
+
59
+ return { borderColor };
60
+ };
61
+
62
+ /**
63
+ * Container style for `size`; multiline uses `height` as minHeight so the
64
+ * field can grow with its content.
65
+ */
66
+ export const getSizeStyle = (
67
+ size?: 'small' | 'large',
68
+ multiline: boolean = false,
69
+ height?: number,
70
+ ) => {
71
+ let scaleStyle: ViewStyle = {};
72
+ if (height) {
73
+ scaleStyle = { height };
74
+ }
75
+
76
+ if (multiline) {
77
+ return [
78
+ styles.multilineContainer,
79
+ {
80
+ minHeight: height,
81
+ },
82
+ ];
83
+ }
84
+
85
+ if (size === 'small') {
86
+ return [styles.smallContainer, scaleStyle];
87
+ }
88
+ return [styles.container, scaleStyle];
89
+ };
90
+
91
+ /**
92
+ * Error or hint row under an input (error wins); with neither, `errorSpacing`
93
+ * keeps an empty row so the layout doesn't jump when an error appears.
94
+ */
95
+ export const ErrorView: FC<{
96
+ errorMessage?: string;
97
+ errorSpacing?: boolean;
98
+ hintText?: string;
99
+ componentId?: string;
100
+ }> = ({ errorMessage, errorSpacing, hintText, componentId }) => {
101
+ const { theme } = useContext(ApplicationContext);
102
+ const errorColor = theme.colors.error.primary;
103
+ const hintColor = theme.colors.text.hint;
104
+ const hintTextDefault = hintText ?? 'Không thể chỉnh sửa';
105
+ const scaledIconSize = useScaleSize(16);
106
+
107
+ if (errorMessage || hintText) {
108
+ const messageColor = errorMessage ? errorColor : hintColor;
109
+ const messageType = errorMessage ? 'error' : 'hint';
110
+ return (
111
+ <View style={styles.errorView}>
112
+ <View style={styles.errorIcon}>
113
+ <Icon color={messageColor} source="ic_error" size={scaledIconSize} />
114
+ </View>
115
+ <Text
116
+ accessibilityLabel={`${componentId}|${messageType}-text`}
117
+ style={Styles.flex}
118
+ color={messageColor}
119
+ typography={'description_default_regular'}
120
+ >
121
+ {errorMessage ?? hintTextDefault}
122
+ </Text>
123
+ </View>
124
+ );
125
+ }
126
+ if (errorSpacing) {
127
+ return <View style={[styles.errorView, styles.errorSpacing]} />;
128
+ }
129
+ return <View />;
130
+ };
131
+
132
+ /**
133
+ * Floating label on the input's top border with a required `*` and an
134
+ * optional pressable icon; renders nothing without `floatingValue`.
135
+ */
136
+ export const FloatingView: FC<FloatingViewProps> = ({
137
+ floatingValue,
138
+ floatingIconColor,
139
+ disabled,
140
+ floatingIcon,
141
+ required,
142
+ style,
143
+ onPress,
144
+ componentId,
145
+ }) => {
146
+ const { theme } = useContext(ApplicationContext);
147
+ const scaledTop = useScaleSize(10);
148
+ if (floatingValue) {
149
+ let floatingTextColor = theme.colors.text.hint;
150
+ let floatingIconTintColor = floatingIconColor;
151
+ if (disabled) {
152
+ floatingTextColor = theme.colors.text.disable;
153
+ floatingIconTintColor = theme.colors.text.disable;
154
+ }
155
+
156
+ return (
157
+ <View
158
+ style={[
159
+ styles.floatingView,
160
+ styles.floatingViewLayer,
161
+ {
162
+ backgroundColor: theme.colors.background.surface,
163
+ top: -scaledTop,
164
+ },
165
+ style,
166
+ ]}
167
+ >
168
+ <Text
169
+ color={floatingTextColor}
170
+ typography={'label_s_medium'}
171
+ accessibilityLabel={`${componentId}|floating-text`}
172
+ >
173
+ {floatingValue}
174
+ {required && (
175
+ <Text
176
+ typography={'label_s_medium'}
177
+ color={theme.colors.error.primary}
178
+ >
179
+ *
180
+ </Text>
181
+ )}
182
+ </Text>
183
+ {!!floatingIcon && (
184
+ <TouchableOpacity
185
+ activeOpacity={onPress ? 0.6 : 1}
186
+ onPress={onPress}
187
+ accessibilityLabel={`${componentId}|floating-icon-touch`}
188
+ >
189
+ <Icon
190
+ color={floatingIconTintColor}
191
+ source={floatingIcon}
192
+ size={16}
193
+ style={styles.floatingIcon}
194
+ accessibilityLabel={`${componentId}|floating-icon`}
195
+ />
196
+ </TouchableOpacity>
197
+ )}
198
+ </View>
199
+ );
200
+ }
201
+ return null;
202
+ };
203
+
204
+ /**
205
+ * Trailing slot: spinner while `loading`, an icon when `icon` is a known icon
206
+ * name or URL, otherwise `icon` as a text action (first 15 chars).
207
+ */
208
+ export const RenderTrailing: FC<TrailingProps> = ({
209
+ loading,
210
+ color,
211
+ icon,
212
+ onPressIcon,
213
+ componentId,
214
+ }) => {
215
+ const { theme } = useContext(ApplicationContext);
216
+ if (loading) {
217
+ return <Loader type={'spinner'} color={color} style={styles.icon} />;
218
+ }
219
+
220
+ if (icon) {
221
+ const isIconName = !!(IconSources as any)?.[icon]?.uri;
222
+ const isIcon = isIconName || icon.includes('http');
223
+ const renderIconTouchable = (content: ReactNode) => {
224
+ return (
225
+ <TouchableOpacity
226
+ accessibilityLabel={`${componentId}|trailing-touch`}
227
+ onPress={onPressIcon}
228
+ style={styles.icon}
229
+ >
230
+ {content}
231
+ </TouchableOpacity>
232
+ );
233
+ };
234
+
235
+ if (isIcon) {
236
+ return renderIconTouchable(
237
+ <Icon
238
+ color={color}
239
+ source={icon as string}
240
+ size={24}
241
+ accessibilityLabel={`${componentId}|trailing-icon`}
242
+ />,
243
+ );
244
+ }
245
+ return renderIconTouchable(
246
+ <Text
247
+ typography="action_xs_bold"
248
+ color={color ?? theme.colors.primary}
249
+ numberOfLines={1}
250
+ accessibilityLabel={`${componentId}|trailing-text`}
251
+ >
252
+ {icon!.substring(0, 15)}
253
+ </Text>,
254
+ );
255
+ }
256
+ return null;
257
+ };
package/Input/index.tsx CHANGED
@@ -194,6 +194,12 @@ export interface InputSearchProps extends TextInputProps {
194
194
  */
195
195
  typingData?: string[];
196
196
 
197
+ /**
198
+ * Optional. `header` is the 32pt field with a 20pt search icon that sits in the
199
+ * navigation header. Defaults to `default`, the 36pt field for content.
200
+ */
201
+ size?: 'default' | 'header';
202
+
197
203
  /**
198
204
  * Optional. Called when the field is pressed while showing `typingData`.
199
205
  */
@@ -367,4 +373,4 @@ export {
367
373
  InputPhoneNumber,
368
374
  };
369
375
 
370
- export {checkValidPhoneNumber};
376
+ export { checkValidPhoneNumber };
@@ -0,0 +1,23 @@
1
+ export const moneyFormatter = new Intl.NumberFormat('vi-VN');
2
+
3
+ /**
4
+ * Locates the single edited span between `old` and `text`: common prefix
5
+ * length (`start`), common suffix length (`suffix`) and removed + inserted
6
+ * char count (`size`).
7
+ */
8
+ export const findEdit = (old: string, text: string) => {
9
+ let start = 0;
10
+ while (start < text.length && old[start] === text[start]) {
11
+ start += 1;
12
+ }
13
+ const maxSuffix = Math.min(text.length, old.length) - start;
14
+ let suffix = 0;
15
+ while (suffix < maxSuffix) {
16
+ if (old[old.length - 1 - suffix] !== text[text.length - 1 - suffix]) {
17
+ break;
18
+ }
19
+ suffix += 1;
20
+ }
21
+ const size = old.length + text.length - 2 * (start + suffix);
22
+ return { old, start, suffix, size };
23
+ };
package/Input/utils.ts CHANGED
@@ -1,110 +1,4 @@
1
- import { type ViewStyle } from 'react-native';
2
- import Localize from '../Application/Localize';
3
- import { type Theme } from '../Application/types';
4
- import styles from './styles';
5
-
6
- const SMALL_HEIGHT = 48;
7
- const LARGE_HEIGHT = 56;
8
- const SMALL_LEADING_ICON_SIZE = 24;
9
- const LARGE_LEADING_ICON_SIZE = 32;
10
- const THOUSANDS_GROUP_SIZE = 3;
11
- const PHONE_DIGITS_WITHOUT_ZERO = 9;
12
- const MIN_PHONE_DIGITS = 10;
13
- const MAX_PHONE_DIGITS = 11;
14
-
15
- /** vi-VN number format (`.` thousands) for the InputMoney display value. */
16
- const moneyFormatter = new Intl.NumberFormat('vi-VN');
17
-
18
- /** Field height for `size` before font scaling; unset means large. */
19
- const getInputHeight = (size?: 'small' | 'large') => {
20
- if (size === 'small') {
21
- return SMALL_HEIGHT;
22
- }
23
- return LARGE_HEIGHT;
24
- };
25
-
26
- /** Leading icon size for `size`; unset means large. */
27
- const getLeadingIconSize = (size?: 'small' | 'large') => {
28
- if (size === 'small') {
29
- return SMALL_LEADING_ICON_SIZE;
30
- }
31
- return LARGE_LEADING_ICON_SIZE;
32
- };
33
-
34
- /** Border color by state; priority is disabled > error > focused > default. */
35
- const getBorderColor = (
36
- theme: Theme,
37
- isFocused: boolean,
38
- errorMessage?: string,
39
- isDisabled?: boolean,
40
- ) => {
41
- let borderColor = theme.colors.border.default;
42
-
43
- if (isFocused) {
44
- borderColor = theme.colors.primary;
45
- }
46
-
47
- if (errorMessage) {
48
- borderColor = theme.colors.error.primary;
49
- }
50
-
51
- if (isDisabled) {
52
- borderColor = theme.colors.border.disable;
53
- }
54
-
55
- return { borderColor };
56
- };
57
-
58
- /**
59
- * Container style for `size`; multiline uses `height` as minHeight so the
60
- * field can grow with its content.
61
- */
62
- const getSizeStyle = (
63
- size?: 'small' | 'large',
64
- isMultiline: boolean = false,
65
- height?: number,
66
- ) => {
67
- let scaleStyle: ViewStyle = {};
68
- if (height) {
69
- scaleStyle = { height };
70
- }
71
-
72
- if (isMultiline) {
73
- return [
74
- styles.multilineContainer,
75
- {
76
- minHeight: height,
77
- },
78
- ];
79
- }
80
-
81
- if (size === 'small') {
82
- return [styles.smallContainer, scaleStyle];
83
- }
84
- return [styles.container, scaleStyle];
85
- };
86
-
87
- /**
88
- * Locates the single edited span between `old` and `text`: common prefix
89
- * length (`start`), common suffix length (`suffix`) and removed + inserted
90
- * char count (`size`).
91
- */
92
- const findEdit = (old: string, text: string) => {
93
- let start = 0;
94
- while (start < text.length && old[start] === text[start]) {
95
- start += 1;
96
- }
97
- const maxSuffix = Math.min(text.length, old.length) - start;
98
- let suffix = 0;
99
- while (suffix < maxSuffix) {
100
- if (old[old.length - 1 - suffix] !== text[text.length - 1 - suffix]) {
101
- break;
102
- }
103
- suffix += 1;
104
- }
105
- const size = old.length + text.length - 2 * (start + suffix);
106
- return { old, start, suffix, size };
107
- };
1
+ import { Localize } from '../Application';
108
2
 
109
3
  /**
110
4
  * Formats a number Vietnamese-style (`.` thousands, `,` decimals) with
@@ -124,7 +18,7 @@ const formatNumberToMoney = (number: number, currency = '') => {
124
18
  }
125
19
 
126
20
  const numberString = Math.abs(number).toString();
127
- if (numberString.length < THOUSANDS_GROUP_SIZE) {
21
+ if (numberString.length < 3) {
128
22
  const sign = isNegative ? '-' : '';
129
23
  return `${sign}${numberString}${currency}`;
130
24
  }
@@ -138,7 +32,7 @@ const formatNumberToMoney = (number: number, currency = '') => {
138
32
  } else {
139
33
  array.push(numberString[i] as string);
140
34
  }
141
- if (count === THOUSANDS_GROUP_SIZE && i >= 1) {
35
+ if (count === 3 && i >= 1) {
142
36
  array.push('.');
143
37
  count = 0;
144
38
  }
@@ -173,7 +67,6 @@ const formatMoneyToNumber = (money: string, currencyUnit: string) => {
173
67
  return Number(money);
174
68
  };
175
69
 
176
- /** Digits of `phone`, every other char stripped. */
177
70
  function formatPhoneNumber(phone: string): string {
178
71
  return phone.replace(/\D/g, '');
179
72
  }
@@ -186,32 +79,20 @@ function checkValidPhoneNumber(phone: string): {
186
79
  phoneFormatted: string;
187
80
  error?: string;
188
81
  } {
189
- const hasLengthWithoutZero = phone.length === PHONE_DIGITS_WITHOUT_ZERO;
190
- const isMissingLeadingZero = hasLengthWithoutZero && /^[1-9]/.test(phone);
82
+ const isMissingLeadingZero = phone.length === 9 && /^[1-9]/.test(phone);
191
83
  const phoneNumber = isMissingLeadingZero ? `0${phone}` : phone;
192
84
 
193
85
  const phoneFormatted = formatPhoneNumber(phoneNumber);
194
- const digitCount = phoneFormatted.length;
195
86
  const localize = new Localize({ vi: {}, en: {} });
196
87
  let error: string | undefined;
197
88
 
198
- if (digitCount === 0) {
89
+ if (phoneFormatted.length === 0) {
199
90
  error = localize.translate('enterPhoneNumber');
200
- } else if (digitCount < MIN_PHONE_DIGITS || digitCount > MAX_PHONE_DIGITS) {
91
+ } else if (phoneFormatted.length < 10 || phoneFormatted.length > 11) {
201
92
  error = localize.translate('invalidPhoneNumber');
202
93
  }
203
94
 
204
95
  return { phoneFormatted: phoneFormatted, error };
205
96
  }
206
97
 
207
- export {
208
- moneyFormatter,
209
- getInputHeight,
210
- getLeadingIconSize,
211
- getBorderColor,
212
- getSizeStyle,
213
- findEdit,
214
- formatMoneyToNumber,
215
- formatNumberToMoney,
216
- checkValidPhoneNumber,
217
- };
98
+ export { formatMoneyToNumber, formatNumberToMoney, checkValidPhoneNumber };
@@ -13,22 +13,12 @@ import Animated, {
13
13
  } from 'react-native-reanimated';
14
14
  import { scheduleOnRN } from 'react-native-worklets';
15
15
  import { ApplicationContext } from '../Context';
16
- import { Colors, Spacing } from '../Consts';
16
+ import { Colors } from '../Consts';
17
17
  import { Icon } from '../Icon';
18
18
  import { useScaleSize, exportFontFamily } from '../Text';
19
19
  import { type AnimatedCompatValue } from '../Application/utils';
20
20
  import { useNormalizedSharedValue } from '../Application/hooks';
21
21
 
22
- const DEFAULT_BOTTOM = Spacing.M;
23
- const PILL_RADIUS = 100;
24
- const LABEL_FONT_SIZE = 16;
25
- const LABEL_LINE_HEIGHT = 22;
26
- const SMALL_SIZE = 36;
27
- const LARGE_SIZE = 48;
28
- const SMALL_ICON_SIZE = 12;
29
- const LARGE_ICON_SIZE = 24;
30
- const ANIMATION_DURATION = 100;
31
-
32
22
  export interface FloatingButtonProps {
33
23
  label?: string;
34
24
  onPress?: () => void;
@@ -54,64 +44,60 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
54
44
  iconColor = '',
55
45
  size = 'small',
56
46
  animatedValue,
57
- bottom = DEFAULT_BOTTOM,
47
+ bottom = 12,
58
48
  }: FloatingButtonProps) => {
59
49
  const { theme } = useContext(ApplicationContext);
60
- const hasScrollValue = animatedValue != null;
50
+ const enabled = animatedValue != null;
61
51
  const sharedValue = useNormalizedSharedValue(animatedValue);
62
- const scaledFontSize = useScaleSize(LABEL_FONT_SIZE);
63
- const scaledLineHeight = useScaleSize(LABEL_LINE_HEIGHT);
52
+ const scaledFontSize = useScaleSize(16);
53
+ const scaledLineHeight = useScaleSize(22);
64
54
  const labelFontFamily = exportFontFamily('bold');
65
55
  const maxWidth = useSharedValue(0);
66
- const minWidth = size === 'small' ? SMALL_SIZE : LARGE_SIZE;
56
+ const minWidth = size === 'small' ? 36 : 48;
67
57
  const opacityAnimated = useSharedValue(0);
68
58
  const widthAnimated = useSharedValue<number | null>(null);
69
59
  const lastOffset = useSharedValue(0);
70
60
  const lastDirection = useSharedValue<string | null>(null);
71
- const [isLabelShown, setIsLabelShown] = useState(true);
61
+ const [showText, setShowText] = useState(true);
72
62
 
73
63
  useEffect(() => {
74
64
  if (!label) return;
75
- opacityAnimated.value = withTiming(1, { duration: ANIMATION_DURATION });
65
+ opacityAnimated.value = withTiming(1, { duration: 100 });
76
66
  }, [label, opacityAnimated]);
77
67
 
78
68
  useAnimatedReaction(
79
69
  () => sharedValue.value,
80
70
  value => {
81
71
  'worklet';
82
- if (!label || !hasScrollValue) return;
72
+ if (!label || !enabled) return;
83
73
  if (value !== lastOffset.value && value > 0) {
84
74
  const direction = value > lastOffset.value ? 'down' : 'up';
85
75
  lastOffset.value = value;
86
76
  if (lastDirection.value !== direction) {
87
77
  lastDirection.value = direction;
88
78
  if (direction === 'down') {
89
- opacityAnimated.value = withTiming(0, {
90
- duration: ANIMATION_DURATION,
91
- });
79
+ opacityAnimated.value = withTiming(0, { duration: 100 });
92
80
  widthAnimated.value = withTiming(
93
81
  minWidth,
94
- { duration: ANIMATION_DURATION },
82
+ { duration: 100 },
95
83
  finished => {
96
- if (finished) scheduleOnRN(setIsLabelShown, false);
84
+ if (finished) scheduleOnRN(setShowText, false);
97
85
  },
98
86
  );
99
87
  } else {
100
- opacityAnimated.value = withTiming(1, {
101
- duration: ANIMATION_DURATION,
102
- });
88
+ opacityAnimated.value = withTiming(1, { duration: 100 });
103
89
  widthAnimated.value = withTiming(
104
90
  maxWidth.value,
105
- { duration: ANIMATION_DURATION },
91
+ { duration: 100 },
106
92
  finished => {
107
- if (finished) scheduleOnRN(setIsLabelShown, true);
93
+ if (finished) scheduleOnRN(setShowText, true);
108
94
  },
109
95
  );
110
96
  }
111
97
  }
112
98
  }
113
99
  },
114
- [label, hasScrollValue, minWidth],
100
+ [label, enabled, minWidth],
115
101
  );
116
102
 
117
103
  const containerStyle = useAnimatedStyle(() => ({
@@ -160,10 +146,10 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
160
146
  <TouchableOpacity style={styles.content} onPress={onPress}>
161
147
  <Icon
162
148
  source={icon}
163
- size={size === 'small' ? SMALL_ICON_SIZE : LARGE_ICON_SIZE}
149
+ size={size === 'small' ? 12 : 24}
164
150
  color={iconColor}
165
151
  />
166
- {isLabelShown && !!label && (
152
+ {showText && !!label && (
167
153
  <Animated.Text
168
154
  allowFontScaling={false}
169
155
  style={[
@@ -192,19 +178,19 @@ const styles = StyleSheet.create({
192
178
  alignContent: 'center',
193
179
  alignItems: 'center',
194
180
  position: 'absolute',
195
- borderRadius: PILL_RADIUS,
196
- paddingHorizontal: Spacing.M,
181
+ borderRadius: 100,
182
+ paddingHorizontal: 12,
197
183
  flexWrap: 'wrap',
198
184
  alignSelf: 'flex-end',
199
185
  },
200
186
  label: {
201
- marginLeft: Spacing.S,
187
+ marginLeft: 8,
202
188
  },
203
- alignRight: { right: Spacing.M },
189
+ alignRight: { right: 12 },
204
190
  alignCenter: { alignSelf: 'center' },
205
191
  alignEnd: { alignSelf: 'flex-end' },
206
- small: { height: SMALL_SIZE },
207
- large: { height: LARGE_SIZE },
192
+ small: { height: 36 },
193
+ large: { height: 48 },
208
194
  content: {
209
195
  flexDirection: 'row',
210
196
  alignItems: 'center',
package/Layout/Screen.tsx CHANGED
@@ -67,6 +67,7 @@ const Screen = forwardRef(
67
67
  headerBackground,
68
68
  gradientColor,
69
69
  trackingParams,
70
+ contentLayout,
70
71
  }: ScreenProps,
71
72
  ref: any,
72
73
  ) => {
@@ -144,6 +145,7 @@ const Screen = forwardRef(
144
145
  gradientColor,
145
146
  headerBackground,
146
147
  layoutOffset,
148
+ contentLayout,
147
149
  });
148
150
 
149
151
  // mutates the content node so callers keep its methods plus the header setters
@@ -223,6 +225,7 @@ const Screen = forwardRef(
223
225
  useShadowHeader={useShadowHeader}
224
226
  gradientColor={gradientColor}
225
227
  headerBackground={headerBackground}
228
+ contentLayout={contentLayout}
226
229
  />
227
230
  );
228
231
  };