@momo-kits/foundation 0.169.4 → 0.169.5

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 (125) hide show
  1. package/Application/BottomSheet.hooks.ts +8 -8
  2. package/Application/BottomSheet.parts.tsx +44 -34
  3. package/Application/BottomSheet.tsx +35 -26
  4. package/Application/BottomTab/ActiveIndicator.tsx +15 -14
  5. package/Application/BottomTab/BottomTabBar.tsx +43 -34
  6. package/Application/BottomTab/BottomTabInset.tsx +8 -4
  7. package/Application/BottomTab/CurvedContainer.tsx +14 -12
  8. package/Application/BottomTab/CustomBottomTabItem.tsx +10 -6
  9. package/Application/BottomTab/DuoBarCompression.tsx +13 -19
  10. package/Application/BottomTab/DuoRailTabBar.tsx +13 -13
  11. package/Application/BottomTab/DuoTabBar.tsx +8 -9
  12. package/Application/BottomTab/TabBarIcon.tsx +13 -8
  13. package/Application/BottomTab/TabScreen.tsx +1 -5
  14. package/Application/BottomTab/index.tsx +38 -30
  15. package/Application/BottomTab/metrics.ts +21 -20
  16. package/Application/BottomTab/tabItems.ts +1 -1
  17. package/Application/BottomTab/usePressLift.ts +2 -2
  18. package/Application/Components/BackgroundImageView.tsx +4 -0
  19. package/Application/Components/DuoGlassBackground.tsx +5 -4
  20. package/Application/Components/HeaderAnimated.tsx +4 -0
  21. package/Application/Components/HeaderBackground.tsx +4 -0
  22. package/Application/Components/HeaderExtendHeader.tsx +11 -10
  23. package/Application/Components/HeaderLeft.tsx +2 -1
  24. package/Application/Components/HeaderRight.tsx +2 -1
  25. package/Application/Components/HeaderTitle.shared.ts +11 -9
  26. package/Application/Components/HeaderTitle.tsx +4 -3
  27. package/Application/Components/HeaderToolkitAction.tsx +17 -20
  28. package/Application/Components/NavigationButton.tsx +2 -1
  29. package/Application/Components/SearchHeader.tsx +17 -10
  30. package/Application/Components/TitleJourney.tsx +2 -2
  31. package/Application/Components/TitleLocation.tsx +2 -2
  32. package/Application/Components/TitleUser.tsx +2 -2
  33. package/Application/Components/useToolkitActions.tsx +17 -32
  34. package/Application/Localize.ts +7 -0
  35. package/Application/ModalScreen.tsx +9 -3
  36. package/Application/Navigation.ts +14 -16
  37. package/Application/NavigationContainer.tsx +19 -16
  38. package/Application/Navigator.ts +20 -48
  39. package/Application/StackScreen.tracking.ts +11 -26
  40. package/Application/StackScreen.tsx +8 -35
  41. package/Application/TooltipPortal.tsx +12 -5
  42. package/Application/WidgetContainer.tsx +10 -4
  43. package/Application/modalLayout.ts +11 -12
  44. package/Application/navigationOptions.tsx +21 -17
  45. package/Badge/Badge.tsx +5 -0
  46. package/Badge/BadgeDot.tsx +1 -0
  47. package/Badge/BadgeDotAnimation.tsx +15 -7
  48. package/Badge/BadgeRibbon.tsx +46 -38
  49. package/Badge/Shape.tsx +2 -0
  50. package/Badge/types.ts +2 -2
  51. package/Button/index.tsx +5 -16
  52. package/Button/utils.ts +9 -15
  53. package/CheckBox/index.tsx +4 -0
  54. package/Consts/theme.ts +10 -10
  55. package/Context/index.ts +1 -0
  56. package/Divider/DashDivider.tsx +1 -0
  57. package/Divider/index.tsx +4 -0
  58. package/FoundationList/index.tsx +4 -0
  59. package/Icon/index.tsx +6 -6
  60. package/Icon/types.ts +1 -1
  61. package/IconButton/index.tsx +4 -12
  62. package/Image/index.tsx +9 -7
  63. package/Input/Input.tsx +8 -9
  64. package/Input/InputDropDown.tsx +10 -12
  65. package/Input/InputMoney.tsx +12 -8
  66. package/Input/InputMoneyView.tsx +14 -7
  67. package/Input/InputOTP.tsx +35 -33
  68. package/Input/InputPhoneNumber.tsx +8 -9
  69. package/Input/InputSearch.tsx +4 -6
  70. package/Input/InputTextArea.tsx +4 -0
  71. package/Input/SearchTextTyping.tsx +4 -0
  72. package/Input/SystemTextInput.tsx +7 -2
  73. package/Input/TextTyping.tsx +4 -0
  74. package/Input/common.tsx +26 -12
  75. package/Input/index.tsx +17 -20
  76. package/Input/moneyUtils.ts +10 -4
  77. package/Input/styles.ts +0 -5
  78. package/Input/utils.ts +14 -12
  79. package/Layout/Card.tsx +7 -4
  80. package/Layout/FloatingButton.tsx +4 -0
  81. package/Layout/Item.tsx +6 -2
  82. package/Layout/ItemList.tsx +9 -7
  83. package/Layout/ItemSectionList.tsx +2 -1
  84. package/Layout/ReservedRegions.tsx +25 -25
  85. package/Layout/Screen.tsx +56 -58
  86. package/Layout/Section.tsx +8 -5
  87. package/Layout/TrackingScope.tsx +1 -0
  88. package/Layout/screenContent.tsx +4 -2
  89. package/Layout/screenFooter.tsx +28 -18
  90. package/Layout/screenHeader.tsx +34 -31
  91. package/Layout/screenQuickReturn.tsx +17 -20
  92. package/Layout/screenScroll.ts +4 -7
  93. package/Layout/screenTypes.ts +3 -2
  94. package/Layout/types.ts +2 -4
  95. package/Layout/utils.ts +31 -37
  96. package/Loader/DotLoader.tsx +4 -0
  97. package/Loader/Loader.tsx +4 -0
  98. package/Loader/ProgressBar.tsx +1 -0
  99. package/Loader/Spinner.tsx +4 -0
  100. package/Loader/utils.ts +11 -7
  101. package/Pagination/Dot.tsx +4 -0
  102. package/Pagination/PaginationDot.tsx +1 -0
  103. package/Pagination/PaginationNumber.tsx +5 -3
  104. package/Pagination/PaginationScroll.tsx +5 -0
  105. package/Pagination/PaginationWhiteDot.tsx +1 -0
  106. package/Pagination/index.tsx +4 -0
  107. package/Pagination/types.ts +2 -2
  108. package/Popup/PopupNotify.tsx +39 -39
  109. package/Popup/PopupPromotion.tsx +4 -7
  110. package/Popup/types.ts +4 -4
  111. package/Popup/utils.ts +4 -0
  112. package/Radio/index.tsx +4 -0
  113. package/Skeleton/index.tsx +8 -0
  114. package/Switch/index.tsx +1 -0
  115. package/Tag/index.tsx +5 -1
  116. package/Tag/types.ts +3 -3
  117. package/Text/index.tsx +14 -3
  118. package/Text/styles.ts +1 -1
  119. package/Text/types.ts +1 -6
  120. package/Text/utils.ts +9 -0
  121. package/Title/index.tsx +41 -32
  122. package/ViewBoundary/index.tsx +4 -2
  123. package/index.ts +0 -6
  124. package/package.json +1 -1
  125. package/Application/__tests__/modalLayout.test.ts +0 -128
package/Text/index.tsx CHANGED
@@ -111,6 +111,10 @@ const deprecatedValues: Typography[] = [
111
111
  'action_s',
112
112
  ];
113
113
 
114
+ /**
115
+ * Text style of a typography token with sizes scaled by `useScaleSize` and the
116
+ * font file name for its weight. Calls hooks, so it only runs during render.
117
+ */
114
118
  const TypoStyles = (typo: Typography, newFontFamily?: string) => {
115
119
  const { theme } = useContext(ApplicationContext);
116
120
  const styleSheet: {
@@ -158,9 +162,7 @@ const TypoStyles = (typo: Typography, newFontFamily?: string) => {
158
162
  fontSize: useScaleSize(fontSize),
159
163
  lineHeight: useScaleSize(lineHeight),
160
164
  fontStyle,
161
- // fontFamily da mang san weight. Tren Android, ReactFontManager doi
162
- // `fonts/<family>_bold.ttf` khi fontWeight >= 700; file do khong ton tai nen
163
- // font se roi ve font he thong. Bo fontWeight de Android dung dung file.
165
+ // Weight is in fontFamily; fontWeight >= 700 makes Android seek a missing <family>_bold.ttf.
164
166
  fontWeight: undefined,
165
167
  };
166
168
  };
@@ -169,6 +171,11 @@ const skeletonStyles = StyleSheet.create({
169
171
  overlay: { position: 'absolute' },
170
172
  });
171
173
 
174
+ /**
175
+ * Design-system text: renders a `typography` token in the theme font with
176
+ * scaled sizes and OS font scaling off. Warns on deprecated tokens and shows a
177
+ * skeleton overlay while a SkeletonContext is loading.
178
+ */
172
179
  const Text: React.FC<TextProps> = ({
173
180
  typography = 'body_default_regular',
174
181
  color,
@@ -228,6 +235,10 @@ const Text: React.FC<TextProps> = ({
228
235
  );
229
236
  };
230
237
 
238
+ /**
239
+ * Theme font family for a loose weight name ('bold', 'semibold', 'regular').
240
+ * The `typography` argument is ignored; it calls hooks, so use it during render.
241
+ */
231
242
  const exportFontFamily = (
232
243
  fontWeight: string,
233
244
  typography?: Typography,
package/Text/styles.ts CHANGED
@@ -39,7 +39,7 @@ export default {
39
39
  action_s_bold: { fontSize: 14, lineHeight: 20, fontWeight: '700' },
40
40
  action_xs_bold: { fontSize: 12, lineHeight: 18, fontWeight: '700' },
41
41
  action_xxs_bold: { fontSize: 10, lineHeight: 14, fontWeight: '700' },
42
- /**non-support**/
42
+ // Legacy tokens kept for old callers; not in the current type scale.
43
43
  headline_default: {
44
44
  fontSize: 28,
45
45
  lineHeight: 34,
package/Text/types.ts CHANGED
@@ -14,9 +14,7 @@ export type TypographyWeight = {
14
14
  };
15
15
 
16
16
  export type Typography =
17
- /**
18
- * @deprecated
19
- **/
17
+ // Deprecated up to 'action_s': Text warns at runtime when one is used.
20
18
  | 'headline_default'
21
19
  | 'headline_l'
22
20
  | 'headline_xl'
@@ -29,9 +27,6 @@ export type Typography =
29
27
  | 'paragraph_italic'
30
28
  | 'label_xxs'
31
29
  | 'action_s'
32
- /**
33
- * end
34
- **/
35
30
  | 'headline_l_bold'
36
31
  | 'headline_default_bold'
37
32
  | 'header_m_bold'
package/Text/utils.ts CHANGED
@@ -6,6 +6,11 @@ const DEFAULT_SCREEN_SIZE = 375;
6
6
  const MAX_FONT_SCALE = 1.5;
7
7
  const MAX_DEVICE_SCALE = 5;
8
8
 
9
+ /**
10
+ * Scales `size` by screen width (at most +5) and OS font scale (at most
11
+ * `scaleRate`, default 1.5), taking the larger; a mini app can opt out of the
12
+ * OS rate and use its own `fontScale.userScaleRate` instead.
13
+ */
9
14
  const useScaleSize = (size: number, scaleRate?: number) => {
10
15
  const { width } = useWindowDimensions();
11
16
  const context = useContext<any>(MiniAppContext);
@@ -37,6 +42,10 @@ const useScaleSize = (size: number, scaleRate?: number) => {
37
42
  return Math.max(fontSizeDeviceScale, fontSizeOSScale);
38
43
  };
39
44
 
45
+ /**
46
+ * Non-hook `useScaleSize` with the default cap and no mini app rate, for use
47
+ * outside render. Reads the window width at call time, so it misses resizes.
48
+ */
40
49
  const scaleSize = (size: number) => {
41
50
  const fontScale = PixelRatio.getFontScale();
42
51
  const deviceScale = Dimensions.get('window').width / DEFAULT_SCREEN_SIZE;
package/Title/index.tsx CHANGED
@@ -15,6 +15,11 @@ import styles from './styles';
15
15
  import { TitleProps } from './types';
16
16
  import { Typography } from '../Text/types';
17
17
 
18
+ /**
19
+ * Section or card heading with optional icon, badge, description, trailing
20
+ * chevron and right action (chevron, or a text button when `buttonTitle` is
21
+ * set). `textOnly` renders the title text alone.
22
+ */
18
23
  const Title: FC<TitleProps> = ({
19
24
  accessibilityLabel,
20
25
  title = 'Title',
@@ -43,7 +48,6 @@ const Title: FC<TitleProps> = ({
43
48
 
44
49
  const size18 = useScaleSize(18);
45
50
  const size22 = useScaleSize(22);
46
- // Dynamic styles using useScaleSize hook
47
51
  const dynamicStyles = {
48
52
  card_small: {
49
53
  fontSize: useScaleSize(14),
@@ -204,39 +208,44 @@ const Title: FC<TitleProps> = ({
204
208
 
205
209
  const lineHeight = styleSheet[typography].lineHeight;
206
210
 
211
+ let action = (
212
+ <TouchableOpacity
213
+ onPress={onPressRightAction}
214
+ style={[
215
+ styles.iconRight,
216
+ {
217
+ backgroundColor: theme.colors.primary + '0F',
218
+ },
219
+ ]}
220
+ accessibilityLabel={componentId + '|label-right-action-touch'}
221
+ >
222
+ <Icon
223
+ source={'arrow_chevron_right_small'}
224
+ size={size22}
225
+ color={theme.colors.primary}
226
+ />
227
+ </TouchableOpacity>
228
+ );
229
+ if (buttonTitle) {
230
+ action = (
231
+ <TouchableOpacity
232
+ onPress={onPressRightAction}
233
+ accessibilityLabel={componentId + '|label-right-action-touch'}
234
+ >
235
+ <Text
236
+ color={theme.colors.primary}
237
+ typography={buttonTypo}
238
+ accessibilityLabel={componentId + '|label-right-action-text'}
239
+ >
240
+ {buttonTitle}
241
+ </Text>
242
+ </TouchableOpacity>
243
+ );
244
+ }
245
+
207
246
  return (
208
247
  <View style={[styles.actionRightView, { height: lineHeight }]}>
209
- {!buttonTitle ? (
210
- <TouchableOpacity
211
- onPress={onPressRightAction}
212
- style={[
213
- styles.iconRight,
214
- {
215
- backgroundColor: theme.colors.primary + '0F',
216
- },
217
- ]}
218
- accessibilityLabel={componentId + '|label-right-action-touch'}
219
- >
220
- <Icon
221
- source={'arrow_chevron_right_small'}
222
- size={size22}
223
- color={theme.colors.primary}
224
- />
225
- </TouchableOpacity>
226
- ) : (
227
- <TouchableOpacity
228
- onPress={onPressRightAction}
229
- accessibilityLabel={componentId + '|label-right-action-touch'}
230
- >
231
- <Text
232
- color={theme.colors.primary}
233
- typography={buttonTypo}
234
- accessibilityLabel={componentId + '|label-right-action-text'}
235
- >
236
- {buttonTitle}
237
- </Text>
238
- </TouchableOpacity>
239
- )}
248
+ {action}
240
249
  </View>
241
250
  );
242
251
  };
@@ -14,6 +14,10 @@ interface ViewBoundaryState {
14
14
  error: Error | null;
15
15
  }
16
16
 
17
+ /**
18
+ * Error boundary: renders `fallback` (or nothing) after a render error and
19
+ * reports it to native `MiniAppModule.onJSBoundaryCrash` when available.
20
+ */
17
21
  class ViewBoundary extends React.Component<
18
22
  ViewBoundaryProps,
19
23
  ViewBoundaryState
@@ -33,7 +37,6 @@ class ViewBoundary extends React.Component<
33
37
  this.props.onError?.(error, errorInfo);
34
38
 
35
39
  const context = (this as any).context ?? {};
36
- // check exist native module method onJSBoundaryCrash
37
40
  const nativeMethod = NativeModules?.MiniAppModule?.onJSBoundaryCrash;
38
41
  if (typeof nativeMethod === 'function') {
39
42
  try {
@@ -49,7 +52,6 @@ class ViewBoundary extends React.Component<
49
52
  componentStack: errorInfo?.componentStack?.substring(0, 500) ?? '',
50
53
  },
51
54
  });
52
- console.info('[ViewBoundary] onJSBoundaryCrash success!');
53
55
  } catch (_e) {
54
56
  console.warn('[ViewBoundary] onJSBoundaryCrash failed:', _e);
55
57
  }
package/index.ts CHANGED
@@ -1,14 +1,8 @@
1
- /**
2
- * native export
3
- */
4
1
  import { TouchableOpacity } from 'react-native';
5
2
 
6
3
  export * from 'react-native-linear-gradient';
7
4
  export * from 'react-native-safe-area-context';
8
5
 
9
- /**
10
- * foundation component
11
- */
12
6
  export * from './Consts';
13
7
  export * from './Context';
14
8
  export * from './Layout';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.169.4",
3
+ "version": "0.169.5",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -1,128 +0,0 @@
1
- // document/__mocks__ shadows react-native with react-native-web for the doc site
2
- jest.mock('react-native', () => jest.requireActual('react-native'));
3
-
4
- import { getModalLayout } from '../modalLayout';
5
-
6
- const NO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
7
-
8
- describe('getModalLayout', () => {
9
- it('keeps the phone look', () => {
10
- const layout = getModalLayout({
11
- width: 390,
12
- height: 844,
13
- insets: { top: 47, right: 0, bottom: 34, left: 0 },
14
- isDuo: false,
15
- });
16
- expect(layout.isFoldable).toBe(false);
17
- expect(layout.popup.width).toBe(342);
18
- expect(layout.popup.maxHeight).toBeUndefined();
19
- expect(layout.popup.radius).toBe(24);
20
- expect(layout.sheet.width).toBeUndefined();
21
- expect(layout.sheet.maxHeight).toBeUndefined();
22
- expect(layout.sheet.radius).toBe(24);
23
- expect(layout.scrimOpacity).toBe(0.6);
24
- });
25
-
26
- it('keeps the phone look in landscape', () => {
27
- const layout = getModalLayout({
28
- width: 844,
29
- height: 390,
30
- insets: { top: 0, right: 47, bottom: 21, left: 47 },
31
- isDuo: false,
32
- });
33
- expect(layout.isFoldable).toBe(false);
34
- expect(layout.popup.width).toBe(844 - 48);
35
- expect(layout.popup.maxHeight).toBeUndefined();
36
- expect(layout.popup.radius).toBe(24);
37
- expect(layout.sheet.width).toBeUndefined();
38
- expect(layout.scrimOpacity).toBe(0.6);
39
- });
40
-
41
- it('caps popup and sheet on a wide foldable window', () => {
42
- const layout = getModalLayout({
43
- width: 884,
44
- height: 1104,
45
- insets: { top: 24, right: 0, bottom: 20, left: 0 },
46
- isDuo: false,
47
- });
48
- expect(layout.isFoldable).toBe(true);
49
- expect(layout.popup).toMatchObject({
50
- width: 450,
51
- minWidth: 280,
52
- maxWidth: 450,
53
- maxHeight: 600,
54
- margin: 24,
55
- radius: 24,
56
- });
57
- expect(layout.sheet).toMatchObject({
58
- width: 653,
59
- maxHeight: 1104 - 24 - 12,
60
- minHeight: 230,
61
- margin: 12,
62
- radius: 24,
63
- });
64
- expect(layout.scrimOpacity).toBe(0.2);
65
- });
66
-
67
- it('limits popup height to the safe area minus 48', () => {
68
- const layout = getModalLayout({
69
- width: 900,
70
- height: 600,
71
- insets: { top: 24, right: 0, bottom: 20, left: 0 },
72
- isDuo: false,
73
- });
74
- expect(layout.popup.maxHeight).toBe(600 - 24 - 20 - 48);
75
- });
76
-
77
- it('places modals left of the control column on the iPhone Duo outer display', () => {
78
- const layout = getModalLayout({
79
- width: 420,
80
- height: 760,
81
- insets: { top: 0, right: 64, bottom: 20, left: 0 },
82
- isDuo: true,
83
- });
84
- expect(layout.isFoldable).toBe(true);
85
- expect(layout.placement).toEqual({ x: 0, y: 0, width: 356, height: 740 });
86
- expect(layout.popup.margin).toBe(12);
87
- expect(layout.popup.width).toBe(356 - 24);
88
- expect(layout.sheet.width).toBe(356 - 24);
89
- });
90
-
91
- it('never grows past the margins when the space is under the min width', () => {
92
- const layout = getModalLayout({
93
- width: 300,
94
- height: 600,
95
- insets: NO_INSETS,
96
- isDuo: true,
97
- });
98
- expect(layout.popup.width).toBe(300 - 24);
99
- expect(layout.popup.minWidth).toBe(300 - 24);
100
- expect(layout.sheet.width).toBe(300 - 24);
101
- });
102
-
103
- it('moves to the right half when iPhone Duo is half folded', () => {
104
- const layout = getModalLayout({
105
- width: 1000,
106
- height: 800,
107
- insets: NO_INSETS,
108
- isDuo: true,
109
- hinge: { x: 495, y: 0, width: 10, height: 800 },
110
- });
111
- expect(layout.placement).toEqual({ x: 505, y: 0, width: 495, height: 800 });
112
- expect(layout.popup.margin).toBe(12);
113
- expect(layout.popup.width).toBe(450);
114
- expect(layout.sheet.width).toBe(495 - 24);
115
- });
116
-
117
- it('ignores a division off the iPhone Duo', () => {
118
- const layout = getModalLayout({
119
- width: 1000,
120
- height: 800,
121
- insets: NO_INSETS,
122
- isDuo: false,
123
- hinge: { x: 495, y: 0, width: 10, height: 800 },
124
- });
125
- expect(layout.placement.x).toBe(0);
126
- expect(layout.popup.margin).toBe(24);
127
- });
128
- });