@momo-kits/foundation 0.169.7-beta.2 → 0.169.7-beta.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 (141) hide show
  1. package/Application/BottomSheet.hooks.ts +8 -8
  2. package/Application/BottomSheet.parts.tsx +34 -44
  3. package/Application/BottomSheet.tsx +37 -40
  4. package/Application/BottomTab/ActiveIndicator.tsx +14 -15
  5. package/Application/BottomTab/BottomTabBar.tsx +62 -49
  6. package/Application/BottomTab/BottomTabInset.tsx +4 -8
  7. package/Application/BottomTab/CurvedContainer.tsx +12 -14
  8. package/Application/BottomTab/CustomBottomTabItem.tsx +13 -13
  9. package/Application/BottomTab/DuoBarCompression.tsx +19 -13
  10. package/Application/BottomTab/DuoRailTabBar.tsx +24 -20
  11. package/Application/BottomTab/DuoTabBar.tsx +10 -8
  12. package/Application/BottomTab/TabBarIcon.tsx +29 -15
  13. package/Application/BottomTab/TabScreen.tsx +5 -1
  14. package/Application/BottomTab/index.tsx +30 -33
  15. package/Application/BottomTab/metrics.ts +23 -23
  16. package/Application/BottomTab/tabItems.ts +1 -1
  17. package/Application/BottomTab/usePressLift.ts +2 -2
  18. package/Application/Components/BackgroundImageView.tsx +0 -4
  19. package/Application/Components/DuoGlassBackground.tsx +4 -5
  20. package/Application/Components/HeaderAnimated.tsx +0 -4
  21. package/Application/Components/HeaderBackground.tsx +0 -4
  22. package/Application/Components/HeaderExtendHeader.tsx +10 -11
  23. package/Application/Components/HeaderLeft.tsx +1 -2
  24. package/Application/Components/HeaderRight.tsx +1 -2
  25. package/Application/Components/HeaderTitle.shared.ts +9 -11
  26. package/Application/Components/HeaderTitle.tsx +3 -4
  27. package/Application/Components/HeaderToolkitAction.tsx +20 -17
  28. package/Application/Components/NavigationButton.tsx +1 -2
  29. package/Application/Components/SearchHeader.tsx +10 -17
  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 +32 -17
  34. package/Application/KitAdoption/AdoptionBadge.tsx +119 -0
  35. package/Application/KitAdoption/AdoptionProbe.tsx +166 -0
  36. package/Application/KitAdoption/AdoptionStore.ts +80 -0
  37. package/Application/KitAdoption/Authorship/utils.ts +137 -0
  38. package/Application/KitAdoption/Slots/utils.ts +68 -0
  39. package/Application/KitAdoption/constants.ts +120 -0
  40. package/Application/KitAdoption/index.ts +12 -0
  41. package/Application/KitAdoption/styles.ts +55 -0
  42. package/Application/KitAdoption/types.ts +61 -0
  43. package/Application/KitAdoption/utils.ts +376 -0
  44. package/Application/Localize.ts +0 -7
  45. package/Application/ModalScreen.tsx +10 -10
  46. package/Application/Navigation.ts +16 -14
  47. package/Application/NavigationContainer.tsx +18 -19
  48. package/Application/Navigator.ts +48 -20
  49. package/Application/ScaleSizeProvider.tsx +6 -13
  50. package/Application/StackScreen.tracking.ts +33 -11
  51. package/Application/StackScreen.tsx +54 -10
  52. package/Application/TooltipPortal.tsx +5 -12
  53. package/Application/WidgetContainer.tsx +4 -10
  54. package/Application/__tests__/KitAdoption.integration.test.tsx +253 -0
  55. package/Application/__tests__/KitAdoption.test.ts +283 -0
  56. package/Application/__tests__/KitAdoptionAuthorship.test.ts +132 -0
  57. package/Application/__tests__/KitAdoptionStore.test.ts +110 -0
  58. package/Application/__tests__/KitAdoptionStructural.test.ts +193 -0
  59. package/Application/__tests__/modalLayout.test.ts +128 -0
  60. package/Application/modalLayout.ts +14 -16
  61. package/Application/navigationOptions.tsx +17 -21
  62. package/Badge/Badge.tsx +0 -5
  63. package/Badge/BadgeDot.tsx +0 -1
  64. package/Badge/BadgeDotAnimation.tsx +7 -15
  65. package/Badge/BadgeRibbon.tsx +38 -46
  66. package/Badge/Shape.tsx +0 -2
  67. package/Badge/types.ts +2 -2
  68. package/Button/index.tsx +16 -5
  69. package/Button/utils.ts +15 -9
  70. package/CheckBox/index.tsx +0 -4
  71. package/Consts/theme.ts +10 -10
  72. package/Context/index.ts +1 -5
  73. package/Divider/DashDivider.tsx +0 -1
  74. package/Divider/index.tsx +0 -4
  75. package/FoundationList/index.tsx +0 -4
  76. package/Icon/index.tsx +6 -6
  77. package/Icon/types.ts +1 -1
  78. package/IconButton/index.tsx +12 -4
  79. package/Image/index.tsx +7 -9
  80. package/Input/Input.tsx +9 -8
  81. package/Input/InputDropDown.tsx +12 -10
  82. package/Input/InputMoney.tsx +8 -12
  83. package/Input/InputMoneyView.tsx +7 -14
  84. package/Input/InputOTP.tsx +33 -35
  85. package/Input/InputPhoneNumber.tsx +9 -8
  86. package/Input/InputSearch.tsx +6 -4
  87. package/Input/InputTextArea.tsx +0 -4
  88. package/Input/SearchTextTyping.tsx +0 -4
  89. package/Input/SystemTextInput.tsx +2 -7
  90. package/Input/TextTyping.tsx +0 -4
  91. package/Input/common.tsx +12 -26
  92. package/Input/index.tsx +20 -17
  93. package/Input/moneyUtils.ts +4 -10
  94. package/Input/styles.ts +5 -0
  95. package/Input/utils.ts +12 -14
  96. package/Layout/Card.tsx +4 -7
  97. package/Layout/FloatingButton.tsx +0 -4
  98. package/Layout/Item.tsx +2 -6
  99. package/Layout/ItemList.tsx +7 -9
  100. package/Layout/ItemSectionList.tsx +1 -2
  101. package/Layout/ReservedRegions.tsx +25 -25
  102. package/Layout/Screen.tsx +58 -56
  103. package/Layout/Section.tsx +5 -8
  104. package/Layout/TrackingScope.tsx +0 -1
  105. package/Layout/screenContent.tsx +2 -4
  106. package/Layout/screenFooter.tsx +18 -28
  107. package/Layout/screenHeader.tsx +31 -34
  108. package/Layout/screenQuickReturn.tsx +20 -17
  109. package/Layout/screenScroll.ts +7 -4
  110. package/Layout/screenTypes.ts +2 -3
  111. package/Layout/types.ts +4 -2
  112. package/Layout/utils.ts +37 -31
  113. package/Loader/DotLoader.tsx +0 -4
  114. package/Loader/Loader.tsx +0 -4
  115. package/Loader/ProgressBar.tsx +0 -1
  116. package/Loader/Spinner.tsx +0 -4
  117. package/Loader/utils.ts +7 -11
  118. package/Pagination/Dot.tsx +0 -4
  119. package/Pagination/PaginationDot.tsx +0 -1
  120. package/Pagination/PaginationNumber.tsx +3 -5
  121. package/Pagination/PaginationScroll.tsx +0 -5
  122. package/Pagination/PaginationWhiteDot.tsx +0 -1
  123. package/Pagination/index.tsx +0 -4
  124. package/Pagination/types.ts +2 -2
  125. package/Popup/PopupNotify.tsx +48 -44
  126. package/Popup/PopupPromotion.tsx +7 -4
  127. package/Popup/types.ts +4 -4
  128. package/Popup/utils.ts +0 -4
  129. package/Radio/index.tsx +0 -4
  130. package/Skeleton/index.tsx +0 -8
  131. package/Switch/index.tsx +0 -1
  132. package/Tag/index.tsx +1 -5
  133. package/Tag/types.ts +3 -3
  134. package/Text/index.tsx +3 -14
  135. package/Text/styles.ts +1 -1
  136. package/Text/types.ts +6 -1
  137. package/Text/utils.ts +4 -20
  138. package/Title/index.tsx +32 -41
  139. package/ViewBoundary/index.tsx +2 -4
  140. package/index.ts +6 -0
  141. package/package.json +1 -1
@@ -25,10 +25,6 @@ type ScrollHandlerParams = {
25
25
  ref: any;
26
26
  };
27
27
 
28
- /**
29
- * Scroll handlers for Screen: feed the header animated values, retint an animated header
30
- * past 50pt, snap the quick return header and reset a search screen scrolled under 100pt.
31
- */
32
28
  export const createScrollHandlers = ({
33
29
  scrollable,
34
30
  animatedValue,
@@ -43,6 +39,9 @@ export const createScrollHandlers = ({
43
39
  }: ScrollHandlerParams) => {
44
40
  let handleScroll;
45
41
 
42
+ /**
43
+ * animated when use scroll && animated value
44
+ */
46
45
  if (scrollable) {
47
46
  handleScroll = Animated.event(
48
47
  [
@@ -81,6 +80,10 @@ export const createScrollHandlers = ({
81
80
  );
82
81
  }
83
82
 
83
+ /**
84
+ * handle scroll end
85
+ * @param e
86
+ */
84
87
  const handleMomentumScrollEnd = (
85
88
  e: NativeSyntheticEvent<NativeScrollEvent>,
86
89
  ) => {
@@ -38,7 +38,7 @@ export interface ScreenProps extends ViewProps {
38
38
  headerType?: HeaderType;
39
39
 
40
40
  /**
41
- * Optional. Animated banner header: its component, tint and title.
41
+ * Optional. Props for the animated component or bool used top navigation animated.
42
42
  */
43
43
  animatedHeader?: AnimatedHeader;
44
44
 
@@ -71,8 +71,7 @@ export interface ScreenProps extends ViewProps {
71
71
  backgroundColor?: string;
72
72
 
73
73
  /**
74
- * Optional. Shift of the content against the animated header banner bottom; negative
75
- * values overlap the banner.
74
+ * Optional. layout card offset overlap header banner.
76
75
  */
77
76
  layoutOffset?: -8 | -24 | -56 | number;
78
77
 
package/Layout/types.ts CHANGED
@@ -4,12 +4,14 @@ export type HeaderType = 'default' | 'extended' | 'none';
4
4
 
5
5
  export type ScreenRef = {
6
6
  /**
7
- * Applies navigation options to the screen's header.
7
+ * Set options for screen
8
+ * @param params
8
9
  */
9
10
  setOptions: (params: NavigationOptions) => void;
10
11
 
11
12
  /**
12
- * Replaces the header title with a search field.
13
+ * Show search header
14
+ * @param params
13
15
  */
14
16
  setSearchHeader: (params: SearchHeaderProps) => void;
15
17
  };
package/Layout/utils.ts CHANGED
@@ -15,8 +15,9 @@ import {
15
15
  import { ReservedRegion, ReservedRegionsContext } from './ReservedRegions';
16
16
 
17
17
  /**
18
- * Warns when a child is not one of `childrenTypes` (Fragments pass) and returns the
19
- * children, flattened to the valid elements when given an array.
18
+ * validate children type
19
+ * @param children
20
+ * @param childrenTypes
20
21
  */
21
22
  const validateChildren = (
22
23
  children: React.ReactNode | React.ReactNode[],
@@ -53,20 +54,20 @@ const validateChildren = (
53
54
  const NO_INSETS: EdgeInsets = { top: 0, right: 0, bottom: 0, left: 0 };
54
55
 
55
56
  /**
56
- * How far system regions (e.g. the camera, at either end depending on the rotation) reach
57
- * into a side strip from its top and bottom ends, plus the center y of the region reaching
58
- * furthest from the top.
57
+ * how far system regions reach into a side strip from its top and from its bottom end
58
+ * (e.g. the camera, which sits at either end depending on the rotation), and the center
59
+ * y of the region reaching furthest from the top
59
60
  */
60
61
  const getStripOcclusion = (
61
62
  regions: ReservedRegion[],
62
63
  stripLeft: number,
63
64
  stripRight: number,
64
65
  windowHeight: number,
65
- ) => {
66
- return regions.reduce(
66
+ ) =>
67
+ regions.reduce(
67
68
  (occlusion, region) => {
68
- const regionRight = region.x + region.width;
69
- const overlapsStrip = region.x < stripRight && regionRight > stripLeft;
69
+ const overlapsStrip =
70
+ region.x < stripRight && region.x + region.width > stripLeft;
70
71
  if (!overlapsStrip) {
71
72
  return occlusion;
72
73
  }
@@ -83,11 +84,10 @@ const getStripOcclusion = (
83
84
  },
84
85
  { top: 0, topCenter: 0, bottom: 0 },
85
86
  );
86
- };
87
87
 
88
88
  /**
89
- * How far the clock and battery clusters of a status bar on the top edge reach in from
90
- * each side. `undefined` without reserved regions there.
89
+ * how far the clock and battery clusters of a status bar on the top edge reach in from
90
+ * each side. `undefined` without reserved regions there
91
91
  */
92
92
  const getStatusBarClusters = (
93
93
  regions: ReservedRegion[],
@@ -95,11 +95,12 @@ const getStatusBarClusters = (
95
95
  topInset: number,
96
96
  ) => {
97
97
  const midX = windowWidth / 2;
98
- const clusters = regions.filter(region => {
99
- const isInTopInset = region.y + region.height <= topInset;
100
- const isOnOneSide = region.x + region.width <= midX || region.x >= midX;
101
- return region.y < topInset && isInTopInset && isOnOneSide;
102
- });
98
+ const clusters = regions.filter(
99
+ region =>
100
+ region.y < topInset &&
101
+ region.y + region.height <= topInset &&
102
+ (region.x + region.width <= midX || region.x >= midX),
103
+ );
103
104
  if (!clusters.length) {
104
105
  return undefined;
105
106
  }
@@ -117,10 +118,8 @@ const getStatusBarClusters = (
117
118
  );
118
119
  };
119
120
 
120
- /** iOS phone idiom: iPad keeps the plain header and is never treated as iPhone Duo. */
121
- const isIPhone = () => {
122
- return Platform.OS === 'ios' && Platform.constants.interfaceIdiom === 'phone';
123
- };
121
+ const isIPhone = () =>
122
+ Platform.OS === 'ios' && Platform.constants.interfaceIdiom === 'phone';
124
123
 
125
124
  /**
126
125
  * Header height and the room it keeps above the bar row for the status bar. On iPhone the
@@ -142,7 +141,7 @@ const getHeaderLayout = (topInset: number) => {
142
141
 
143
142
  /**
144
143
  * Header whose bar row is centered on a window y, at least iPhoneMinHeight tall and
145
- * reaching 8pt below a side bar control centered there.
144
+ * reaching 8pt below a side bar control centered there
146
145
  */
147
146
  const getCenteredHeaderLayout = (centerY: number) => {
148
147
  const headerHeight = Math.max(
@@ -222,7 +221,8 @@ const useScreenLayout = (): ScreenLayout => {
222
221
  if (sideInset >= DuoMetrics.controlSize + Spacing.M) {
223
222
  const edge = insets.right >= insets.left ? 'right' : 'left';
224
223
  const stripLeft = edge === 'right' ? width - sideInset : 0;
225
- // clear the camera and status bar cluster; region frames include the system margin
224
+ // keep controls clear of the camera and of the status bar cluster, which grows for
225
+ // calls and Live Activities. Region frames already include the system's margin
226
226
  const occlusion = getStripOcclusion(
227
227
  reservedRegions,
228
228
  stripLeft,
@@ -242,7 +242,8 @@ const useScreenLayout = (): ScreenLayout => {
242
242
  } else if (height >= DuoMetrics.innerMinHeight) {
243
243
  top = DuoMetrics.firstItemTopLandscape;
244
244
  } else {
245
- // outer landscape: title row centers on a camera at the top end, else on back
245
+ // outer display in landscape: no status bar in the strip, the title row centers
246
+ // on the camera when it sits at the top end, otherwise on the back button
246
247
  top = DuoMetrics.edgeInset;
247
248
  const cameraAtTop = occlusion.top > top;
248
249
  const backCenterY = top + DuoMetrics.controlSize / 2;
@@ -284,7 +285,7 @@ const useScreenLayout = (): ScreenLayout => {
284
285
 
285
286
  /**
286
287
  * Header row options for react-navigation: its height, the room for the status bar, and
287
- * on iPhone Duo inner portrait the buttons kept clear of the clock and battery clusters.
288
+ * on iPhone Duo inner portrait the buttons kept clear of the clock and battery clusters
288
289
  */
289
290
  const getHeaderRowOptions = ({
290
291
  headerHeight,
@@ -304,7 +305,9 @@ const getHeaderRowOptions = ({
304
305
  };
305
306
  };
306
307
 
307
- /** Side margin @react-navigation/elements Header adds to its content row. */
308
+ /**
309
+ * Side margin @react-navigation/elements Header adds to its content row
310
+ */
308
311
  const getHeaderMargin = (width: number) => {
309
312
  if (Platform.OS === 'ios' && width >= HeaderMetrics.largeWidth) {
310
313
  return HeaderMetrics.largeMargin;
@@ -318,9 +321,11 @@ const InnerEdgeStyles: Record<SideBarEdge, ViewStyle> = {
318
321
  };
319
322
 
320
323
  /**
321
- * Absolute style floating a header item into the side bar, 12pt from the strip's inner
322
- * edge, relative to the `container` rendering it; `slot` 0 is back, 1 the toolkit below.
324
+ * Absolute style that floats a header item into the side bar, relative to the header
325
+ * container (left or right) rendering it, 12pt from the strip's inner edge.
323
326
  * `undefined` while there is no side bar.
327
+ * @param container header container rendering the item
328
+ * @param slot position in the side bar, 0 for back, 1 for the toolkit below it
324
329
  */
325
330
  const useSideBarItemStyle = (
326
331
  container: 'left' | 'right',
@@ -333,8 +338,10 @@ const useSideBarItemStyle = (
333
338
 
334
339
  const margin = getHeaderMargin(width);
335
340
  const columnLeft = sideBar.edge === 'left' ? 0 : width - sideBar.width;
336
- const slotOffset = slot * (DuoMetrics.controlSize + Spacing.M);
337
- const top = sideBar.top - headerStatusBarHeight + slotOffset;
341
+ const top =
342
+ sideBar.top -
343
+ headerStatusBarHeight +
344
+ slot * (DuoMetrics.controlSize + Spacing.M);
338
345
  const innerEdgeStyle = InnerEdgeStyles[sideBar.edge];
339
346
 
340
347
  if (container === 'left') {
@@ -357,7 +364,6 @@ const useSideBarItemStyle = (
357
364
  };
358
365
  };
359
366
 
360
- /** Column count of the content grid: 24 on content wider than 600pt, otherwise 12. */
361
367
  const useGridSystem = () => {
362
368
  const { contentWidth } = useScreenLayout();
363
369
  const numberOfColumns = contentWidth > 600 ? 24 : 12;
@@ -6,10 +6,6 @@ import { ApplicationContext } from '../Context';
6
6
  import { hexToRGBA } from './utils';
7
7
  import { LoaderProps } from './types';
8
8
 
9
- /**
10
- * Three-dot Lottie loader recolored to `color` (theme primary by default).
11
- * Recoloring mutates the shared animation JSON, so `Loader` remounts on change.
12
- */
13
9
  const DotLoader: FC<LoaderProps> = ({ color, style }) => {
14
10
  const { theme } = useContext(ApplicationContext);
15
11
 
package/Loader/Loader.tsx CHANGED
@@ -3,10 +3,6 @@ import {LoaderProps} from './types';
3
3
  import DotLoader from './DotLoader';
4
4
  import Spinner from './Spinner';
5
5
 
6
- /**
7
- * Dot (default) or spinner loader. Keyed by `color` so a color change remounts
8
- * the Lottie view with the recolored source.
9
- */
10
6
  const Loader: FC<LoaderProps> = ({type = 'dot', ...props}) => {
11
7
  if (type === 'spinner') {
12
8
  return <Spinner {...props} key={props.color} />;
@@ -9,7 +9,6 @@ import styles from './styles';
9
9
  import { ProgressBarProps } from './types';
10
10
  import { ApplicationContext } from '../Context';
11
11
 
12
- /** Full-width bar that animates its fill to `percent`, clamped to 0–100. */
13
12
  const ProgressBar: FC<ProgressBarProps> = ({ percent = 0, style }) => {
14
13
  const { theme } = useContext(ApplicationContext);
15
14
  const animation = useSharedValue(0);
@@ -6,10 +6,6 @@ import { hexToRGBA } from './utils';
6
6
  import { ApplicationContext } from '../Context';
7
7
  import { LoaderProps } from './types';
8
8
 
9
- /**
10
- * Lottie spinner recolored to `color` (theme primary by default).
11
- * Recoloring mutates the shared animation JSON, so `Loader` remounts on change.
12
- */
13
9
  const Spinner: FC<LoaderProps> = ({ color, style }) => {
14
10
  const { theme } = useContext(ApplicationContext);
15
11
 
package/Loader/utils.ts CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * Converts `#rgb`/`#rrggbb` (the `#` is optional) to Lottie's `[r, g, b]` in
3
- * 0–1, rounded to 3 decimals. Throws on an invalid hex.
4
- */
5
1
  export const hexToRGBA = (hex: string) => {
6
2
  const normalizedHex = hex.startsWith('#') ? hex.slice(1) : hex;
7
3
 
@@ -9,13 +5,13 @@ export const hexToRGBA = (hex: string) => {
9
5
  throw new Error('Invalid HEX color.');
10
6
  }
11
7
 
12
- let expandedHex = normalizedHex;
13
- if (normalizedHex.length === 3) {
14
- expandedHex = normalizedHex
15
- .split('')
16
- .map(val => val + val)
17
- .join('');
18
- }
8
+ const expandedHex =
9
+ normalizedHex.length === 3
10
+ ? normalizedHex
11
+ .split('')
12
+ .map(val => val + val)
13
+ .join('')
14
+ : normalizedHex;
19
15
 
20
16
  const hexMatch = expandedHex.match(/.{2}/g);
21
17
 
@@ -4,10 +4,6 @@ import styles from './styles';
4
4
  import { DotProps } from './types';
5
5
  import { ApplicationContext } from '../Context';
6
6
 
7
- /**
8
- * One pagination dot: a wide bar in the caller's color when active, otherwise
9
- * a small dot in the theme pressed color.
10
- */
11
7
  const Dot: FC<DotProps> = ({ active, style }) => {
12
8
  const { theme } = useContext(ApplicationContext);
13
9
  const pressedColor = theme.colors.background.pressed;
@@ -6,7 +6,6 @@ import styles from './styles';
6
6
  import { Spacing } from '../Consts';
7
7
  import { ApplicationContext, MiniAppContext } from '../Context';
8
8
 
9
- /** Row of primary-color dots with the `activeIndex` dot widened. */
10
9
  const PaginationDot: FC<ChildPaginationProps> = ({
11
10
  dataLength = 2,
12
11
  activeIndex = 0,
@@ -6,7 +6,6 @@ import { Text } from '../Text';
6
6
  import { Colors } from '../Consts';
7
7
  import { MiniAppContext } from '../Context';
8
8
 
9
- /** `n/total` counter on a translucent dark pill. */
10
9
  const PaginationNumber: FC<ChildPaginationProps> = ({
11
10
  activeIndex = 0,
12
11
  dataLength = 2,
@@ -15,16 +14,15 @@ const PaginationNumber: FC<ChildPaginationProps> = ({
15
14
  const context = useContext<any>(MiniAppContext);
16
15
 
17
16
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
18
- const pageLabel = `${activeIndex + 1}/${dataLength}`;
19
17
 
20
18
  return (
21
19
  <View
22
20
  style={[style, styles.row, showBaseLineDebug && styles.debugBaseLine]}
23
21
  >
24
22
  <View style={styles.paginationNumberContainer}>
25
- <Text color={Colors.black_01} typography={'label_default_medium'}>
26
- {pageLabel}
27
- </Text>
23
+ <Text color={Colors.black_01} typography={'label_default_medium'}>{`${
24
+ activeIndex + 1
25
+ }/${dataLength}`}</Text>
28
26
  </View>
29
27
  </View>
30
28
  );
@@ -13,11 +13,6 @@ import { ApplicationContext, MiniAppContext } from '../Context';
13
13
 
14
14
  const INDICATOR_WIDTH = 24;
15
15
  const INDICATOR_CONTAINER_WIDTH = 72;
16
-
17
- /**
18
- * Horizontal scroll view with a small indicator that tracks the scroll offset.
19
- * The indicator shows only when the content is wider than the view.
20
- */
21
16
  const PaginationScroll: FC<ScrollIndicatorProps> = ({
22
17
  style,
23
18
  children,
@@ -6,7 +6,6 @@ import Dot from './Dot';
6
6
  import { Colors, Spacing } from '../Consts';
7
7
  import { MiniAppContext } from '../Context';
8
8
 
9
- /** Pagination dots on a translucent dark pill, for use over images. */
10
9
  const PaginationWhiteDot: FC<ChildPaginationProps> = ({
11
10
  dataLength = 2,
12
11
  activeIndex = 0,
@@ -5,10 +5,6 @@ import PaginationDot from './PaginationDot';
5
5
  import PaginationNumber from './PaginationNumber';
6
6
  import PaginationScroll from './PaginationScroll';
7
7
 
8
- /**
9
- * Page indicator: `type` picks plain dots, dots on a dark pill or an `n/total`
10
- * counter. `PaginationScroll` is the separate scroll-indicator variant.
11
- */
12
8
  const Pagination: FC<PaginationProps> = props => {
13
9
  const {type} = props;
14
10
 
@@ -5,9 +5,9 @@ export type PaginationProps = {
5
5
  /**
6
6
  * Optional. Defines the visual style of the Pagination component.
7
7
  * - 'default': Represents the default style.
8
- * - 'black_white': Represents dots on a translucent dark background.
8
+ * - 'black_white': Represents a pagination that have black background.
9
9
  * - 'number': Represents a style where pages are represented by numbers.
10
- * - 'scroll': Rendered as 'default'; use `PaginationScroll` instead.
10
+ * - 'scroll': Represents a scrollable style.
11
11
  */
12
12
  type?: 'default' | 'black_white' | 'number' | 'scroll';
13
13
 
@@ -11,13 +11,6 @@ import { useModalLayout } from '../Application/modalLayout';
11
11
  import { ModalIconButton } from '../Application/ModalIconButton';
12
12
  import { splitHighlightText } from './utils';
13
13
 
14
- const MAX_ROW_TITLE_LENGTH = 12;
15
-
16
- /**
17
- * Notify popup body: optional image, title, description, error code and one or
18
- * two actions. Actions close via `onRequestClose` if given, else pop the modal
19
- * and then run the callback.
20
- */
21
14
  const PopupNotify: React.FC<PopupNotifyProps> = ({
22
15
  image,
23
16
  title = 'Title',
@@ -50,6 +43,10 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
50
43
  descriptionStyle = { maxHeight: scaledMaxHeight };
51
44
  }
52
45
 
46
+ /**
47
+ * on action popup
48
+ * @param callback
49
+ */
53
50
  const onAction = (callback?: () => void) => {
54
51
  if (typeof onRequestClose === 'function') {
55
52
  onRequestClose?.(callback);
@@ -59,6 +56,9 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
59
56
  }
60
57
  };
61
58
 
59
+ /**
60
+ * build main action of popup
61
+ */
62
62
  const buildAction = () => {
63
63
  const renderRow = () => {
64
64
  return (
@@ -126,13 +126,10 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
126
126
  };
127
127
 
128
128
  if (buttonDirection === 'auto') {
129
- const secondaryTitle = secondary?.title;
130
- if (!secondaryTitle) {
131
- return renderRow();
132
- }
133
- const isLongSecondary = secondaryTitle.length > MAX_ROW_TITLE_LENGTH;
134
- const isLongPrimary = primary.title.length > MAX_ROW_TITLE_LENGTH;
135
- if (isLongSecondary || isLongPrimary) {
129
+ if (
130
+ secondary?.title &&
131
+ (secondary.title.length > 12 || primary.title.length > 12)
132
+ ) {
136
133
  return renderColumn();
137
134
  }
138
135
  return renderRow();
@@ -143,7 +140,9 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
143
140
  return renderColumn();
144
141
  };
145
142
 
146
- /** Highlighted keywords use weight 600 but keep the body size and line height. */
143
+ /**
144
+ * build description text, highlighted keywords keep size/lineHeight and use weight 600
145
+ */
147
146
  const renderDescription = (text: string) => {
148
147
  const segments = splitHighlightText(text, highlightText);
149
148
  if (!segments) {
@@ -161,6 +160,9 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
161
160
  });
162
161
  };
163
162
 
163
+ /**
164
+ * build close action
165
+ */
164
166
  const buildCloseIcon = () => {
165
167
  if (typeof onIconClose !== 'function') {
166
168
  return null;
@@ -178,44 +180,48 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
178
180
  );
179
181
  };
180
182
 
181
- const hasCloseIcon = typeof onIconClose === 'function';
182
- // keeps the title clear of the close button on a text only popup
183
- const titleStyle = !image && hasCloseIcon && styles.titleClearClose;
184
-
185
- let descriptionContent: React.ReactNode = description;
186
- if (typeof description === 'string') {
187
- descriptionContent = (
188
- <Text
189
- accessibilityLabel={'description_popup_notify'}
190
- typography={'body_default_regular'}
191
- onTextLayout={({ nativeEvent: { lines } }) => {
192
- const enableScroll = lines.length > 8.5;
193
- if (enableScroll !== scrollContent) {
194
- setScrollContent(enableScroll);
195
- }
196
- }}
197
- >
198
- {renderDescription(description)}
199
- </Text>
200
- );
201
- }
202
-
203
183
  const body = (
204
184
  <>
205
185
  {!!image && (
206
- <Image source={{ uri: image }} style={styles.image} />
186
+ <Image
187
+ source={{ uri: image }}
188
+ style={[
189
+ styles.image,
190
+ { borderTopLeftRadius: radius, borderTopRightRadius: radius },
191
+ ]}
192
+ />
207
193
  )}
208
194
  <View style={[styles.content, isFoldable && styles.shrink]}>
209
195
  <Text
210
196
  typography={'header_default_bold'}
211
- numberOfLines={2}
197
+ numberOfLines={3}
212
198
  accessibilityLabel={'title_popup_notify'}
213
- style={titleStyle}
199
+ // keeps the title clear of the close button on a text only popup
200
+ style={
201
+ !image &&
202
+ typeof onIconClose === 'function' &&
203
+ styles.titleClearClose
204
+ }
214
205
  >
215
206
  {title}
216
207
  </Text>
217
208
  <Description style={[styles.description, descriptionStyle]}>
218
- {descriptionContent}
209
+ {typeof description === 'string' ? (
210
+ <Text
211
+ accessibilityLabel={'description_popup_notify'}
212
+ typography={'body_default_regular'}
213
+ onTextLayout={({ nativeEvent: { lines } }) => {
214
+ const enableScroll = lines.length > 8.5;
215
+ if (enableScroll !== scrollContent) {
216
+ setScrollContent(enableScroll);
217
+ }
218
+ }}
219
+ >
220
+ {renderDescription(description)}
221
+ </Text>
222
+ ) : (
223
+ description
224
+ )}
219
225
  </Description>
220
226
  {!!error && (
221
227
  <View style={styles.information}>
@@ -244,7 +250,6 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
244
250
  width: popupWidth,
245
251
  maxHeight,
246
252
  },
247
- styles.card,
248
253
  showBaseLineDebug && styles.debugBaseLine,
249
254
  ]}
250
255
  >
@@ -257,10 +262,9 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
257
262
 
258
263
  const styles = StyleSheet.create({
259
264
  debugBaseLine: { borderWidth: 1, borderColor: Colors.green_06 },
260
- // clips the image and content to the card radius
261
- card: { overflow: 'hidden' },
262
265
  image: {
263
266
  aspectRatio: 1.7777,
267
+ overflow: 'hidden',
264
268
  },
265
269
  shrink: { flexShrink: 1 },
266
270
  content: { padding: Spacing.XL },
@@ -12,10 +12,6 @@ const ICON_CLOSE_SIZE = 20;
12
12
  // close button row under the image: marginTop + vertical padding + icon
13
13
  const CLOSE_ROW_HEIGHT = Spacing.S * 3 + ICON_CLOSE_SIZE;
14
14
 
15
- /**
16
- * Promotion popup body: a tappable portrait image with a close button under it.
17
- * Both close the popup first, then call `onActionClick` / `onIconClose`.
18
- */
19
15
  const PopupPromotion: React.FC<PopupPromotionProps> = ({
20
16
  image,
21
17
  onIconClose,
@@ -37,6 +33,10 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
37
33
 
38
34
  const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
39
35
 
36
+ /**
37
+ * on action popup
38
+ * @param callback
39
+ */
40
40
  const onAction = (callback?: () => void) => {
41
41
  if (typeof onRequestClose === 'function') {
42
42
  onRequestClose?.(callback);
@@ -46,6 +46,9 @@ const PopupPromotion: React.FC<PopupPromotionProps> = ({
46
46
  }
47
47
  };
48
48
 
49
+ /**
50
+ * build close action
51
+ */
49
52
  const buildCloseIcon = () => {
50
53
  return (
51
54
  <View style={styles.iconCloseContainer}>
package/Popup/types.ts CHANGED
@@ -56,7 +56,7 @@ export type PopupNotifyProps = {
56
56
  onIconClose?: () => void;
57
57
 
58
58
  /**
59
- * `onRequestClose`: Optional. Closes the modal, then runs `callback`. ModalScreen injects it; without it the popup uses `navigator.pop()`.
59
+ * onRequestClose on request close for modal
60
60
  */
61
61
  onRequestClose?: (callback?: () => void) => void;
62
62
  };
@@ -73,17 +73,17 @@ export type PopupPromotionProps = {
73
73
  image: string;
74
74
 
75
75
  /**
76
- * `onIconClose`: Optional. A callback function that is called after the popup closes from the close icon.
76
+ * `onClose`: Optional. A callback function that is called when the PopupPromotion component is closed.
77
77
  */
78
78
  onIconClose?: () => void;
79
79
 
80
80
  /**
81
- * `onActionClick`: Optional. A callback function that is called after the popup closes from an image tap.
81
+ * `onActionClick`: Optional. A callback function that is called when the PopupPromotion component is closed.
82
82
  */
83
83
  onActionClick?: () => void;
84
84
 
85
85
  /**
86
- * `onRequestClose`: Optional. Closes the modal, then runs `callback`. ModalScreen injects it; without it the popup uses `navigator.pop()`.
86
+ * onRequestClose on request close for modal
87
87
  */
88
88
  onRequestClose?: (callback?: () => void) => void;
89
89
  };
package/Popup/utils.ts CHANGED
@@ -1,9 +1,5 @@
1
1
  type HighlightSegment = { text: string; highlight: boolean };
2
2
 
3
- /**
4
- * True for cased-script letters, digits and `_`; caseless scripts (CJK, Thai)
5
- * count as word breaks.
6
- */
7
3
  const isWordChar = (char?: string) => {
8
4
  if (!char) {
9
5
  return false;
package/Radio/index.tsx CHANGED
@@ -11,10 +11,6 @@ import {
11
11
  MiniAppContext,
12
12
  } from '../Context';
13
13
 
14
- /**
15
- * Radio button, selected when `value === groupValue`. `onChange` is called on
16
- * press without arguments; the parent updates `groupValue`.
17
- */
18
14
  const Radio: FC<RadioProps> = ({
19
15
  value,
20
16
  groupValue,