@momo-kits/foundation 0.169.5 → 0.169.6-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 (127) hide show
  1. package/Application/BottomSheet.hooks.ts +8 -8
  2. package/Application/BottomSheet.parts.tsx +34 -44
  3. package/Application/BottomSheet.tsx +26 -35
  4. package/Application/BottomTab/ActiveIndicator.tsx +14 -15
  5. package/Application/BottomTab/BottomTabBar.styles.ts +18 -1
  6. package/Application/BottomTab/BottomTabBar.tsx +40 -63
  7. package/Application/BottomTab/BottomTabInset.tsx +4 -8
  8. package/Application/BottomTab/CurvedContainer.tsx +20 -16
  9. package/Application/BottomTab/CustomBottomTabItem.tsx +13 -16
  10. package/Application/BottomTab/DuoBarCompression.tsx +19 -13
  11. package/Application/BottomTab/DuoRailTabBar.tsx +13 -17
  12. package/Application/BottomTab/DuoTabBar.tsx +24 -12
  13. package/Application/BottomTab/TabBarIcon.tsx +8 -13
  14. package/Application/BottomTab/TabScreen.tsx +5 -1
  15. package/Application/BottomTab/index.tsx +30 -38
  16. package/Application/BottomTab/metrics.ts +46 -24
  17. package/Application/BottomTab/tabItems.ts +1 -1
  18. package/Application/BottomTab/usePressLift.ts +2 -2
  19. package/Application/Components/BackgroundImageView.tsx +0 -4
  20. package/Application/Components/DuoGlassBackground.tsx +4 -5
  21. package/Application/Components/HeaderAnimated.tsx +0 -4
  22. package/Application/Components/HeaderBackground.tsx +0 -4
  23. package/Application/Components/HeaderExtendHeader.tsx +10 -11
  24. package/Application/Components/HeaderLeft.tsx +1 -2
  25. package/Application/Components/HeaderRight.tsx +1 -2
  26. package/Application/Components/HeaderTitle.shared.ts +9 -11
  27. package/Application/Components/HeaderTitle.tsx +3 -4
  28. package/Application/Components/HeaderToolkitAction.tsx +20 -17
  29. package/Application/Components/NavigationButton.tsx +1 -2
  30. package/Application/Components/SearchHeader.tsx +10 -17
  31. package/Application/Components/TitleJourney.tsx +2 -2
  32. package/Application/Components/TitleLocation.tsx +2 -2
  33. package/Application/Components/TitleUser.tsx +2 -2
  34. package/Application/Components/useToolkitActions.tsx +32 -17
  35. package/Application/Localize.ts +0 -7
  36. package/Application/ModalScreen.tsx +3 -9
  37. package/Application/Navigation.ts +16 -14
  38. package/Application/NavigationContainer.tsx +16 -19
  39. package/Application/Navigator.ts +48 -20
  40. package/Application/StackScreen.tracking.ts +26 -11
  41. package/Application/StackScreen.tsx +35 -8
  42. package/Application/TooltipPortal.tsx +5 -12
  43. package/Application/WidgetContainer.tsx +4 -10
  44. package/Application/__tests__/modalLayout.test.ts +128 -0
  45. package/Application/modalLayout.ts +14 -13
  46. package/Application/navigationOptions.tsx +17 -21
  47. package/Application/types.tabs.ts +0 -1
  48. package/Badge/Badge.tsx +0 -5
  49. package/Badge/BadgeDot.tsx +0 -1
  50. package/Badge/BadgeDotAnimation.tsx +7 -15
  51. package/Badge/BadgeRibbon.tsx +38 -46
  52. package/Badge/Shape.tsx +0 -2
  53. package/Badge/types.ts +2 -2
  54. package/Button/index.tsx +16 -5
  55. package/Button/utils.ts +15 -9
  56. package/CheckBox/index.tsx +0 -4
  57. package/Consts/theme.ts +10 -10
  58. package/Context/index.ts +0 -1
  59. package/Divider/DashDivider.tsx +0 -1
  60. package/Divider/index.tsx +0 -4
  61. package/FoundationList/index.tsx +0 -4
  62. package/Icon/index.tsx +6 -6
  63. package/Icon/types.ts +1 -1
  64. package/IconButton/index.tsx +12 -4
  65. package/Image/index.tsx +7 -9
  66. package/Input/Input.tsx +9 -8
  67. package/Input/InputDropDown.tsx +12 -10
  68. package/Input/InputMoney.tsx +8 -12
  69. package/Input/InputMoneyView.tsx +7 -14
  70. package/Input/InputOTP.tsx +33 -35
  71. package/Input/InputPhoneNumber.tsx +9 -8
  72. package/Input/InputSearch.tsx +6 -4
  73. package/Input/InputTextArea.tsx +0 -4
  74. package/Input/SearchTextTyping.tsx +0 -4
  75. package/Input/SystemTextInput.tsx +2 -7
  76. package/Input/TextTyping.tsx +0 -4
  77. package/Input/common.tsx +12 -26
  78. package/Input/index.tsx +20 -17
  79. package/Input/moneyUtils.ts +4 -10
  80. package/Input/styles.ts +5 -0
  81. package/Input/utils.ts +12 -14
  82. package/Layout/Card.tsx +4 -7
  83. package/Layout/FloatingButton.tsx +0 -4
  84. package/Layout/Item.tsx +2 -6
  85. package/Layout/ItemList.tsx +7 -9
  86. package/Layout/ItemSectionList.tsx +1 -2
  87. package/Layout/ReservedRegions.tsx +25 -25
  88. package/Layout/Screen.tsx +58 -56
  89. package/Layout/Section.tsx +5 -8
  90. package/Layout/TrackingScope.tsx +0 -1
  91. package/Layout/screenContent.tsx +2 -4
  92. package/Layout/screenFooter.tsx +18 -28
  93. package/Layout/screenHeader.tsx +31 -34
  94. package/Layout/screenQuickReturn.tsx +20 -17
  95. package/Layout/screenScroll.ts +7 -4
  96. package/Layout/screenTypes.ts +2 -3
  97. package/Layout/types.ts +4 -2
  98. package/Layout/utils.ts +37 -31
  99. package/Loader/DotLoader.tsx +0 -4
  100. package/Loader/Loader.tsx +0 -4
  101. package/Loader/ProgressBar.tsx +0 -1
  102. package/Loader/Spinner.tsx +0 -4
  103. package/Loader/utils.ts +7 -11
  104. package/Pagination/Dot.tsx +0 -4
  105. package/Pagination/PaginationDot.tsx +0 -1
  106. package/Pagination/PaginationNumber.tsx +3 -5
  107. package/Pagination/PaginationScroll.tsx +0 -5
  108. package/Pagination/PaginationWhiteDot.tsx +0 -1
  109. package/Pagination/index.tsx +0 -4
  110. package/Pagination/types.ts +2 -2
  111. package/Popup/PopupNotify.tsx +48 -44
  112. package/Popup/PopupPromotion.tsx +7 -4
  113. package/Popup/types.ts +4 -4
  114. package/Popup/utils.ts +0 -4
  115. package/Radio/index.tsx +0 -4
  116. package/Skeleton/index.tsx +0 -8
  117. package/Switch/index.tsx +0 -1
  118. package/Tag/index.tsx +1 -5
  119. package/Tag/types.ts +3 -3
  120. package/Text/index.tsx +3 -14
  121. package/Text/styles.ts +1 -1
  122. package/Text/types.ts +6 -1
  123. package/Text/utils.ts +0 -9
  124. package/Title/index.tsx +32 -41
  125. package/ViewBoundary/index.tsx +2 -4
  126. package/index.ts +6 -0
  127. package/package.json +1 -1
package/Input/index.tsx CHANGED
@@ -36,7 +36,7 @@ export interface InputProps extends TextInputProps {
36
36
  errorMessage?: string;
37
37
 
38
38
  /**
39
- * Optional. Trailing icon name or URL; any other string is shown as a text action.
39
+ * Optional. Represents the name or key of the icon to be displayed in the Input component.
40
40
  */
41
41
  trailing?: string;
42
42
 
@@ -69,18 +69,19 @@ export interface InputProps extends TextInputProps {
69
69
  required?: boolean;
70
70
 
71
71
  /**
72
- * Optional. If `true`, keeps an empty error row when there is no error or hint.
72
+ * Optional. If `true`,
73
+ * include spacing when Input not have error message.
73
74
  * Defaults to `false` if not provided.
74
75
  */
75
76
  errorSpacing?: boolean;
76
77
 
77
78
  /**
78
- * Optional. If `true`, shows a loading spinner in place of the trailing icon.
79
+ * If true, the icon of input will use be show indicator loading.
79
80
  */
80
81
  loading?: boolean;
81
82
 
82
83
  /**
83
- * Optional. Represents the leading icon in the Input component.
84
+ * Optional. Represents the leading icon in the Input component.
84
85
  */
85
86
  leadingIcon?: string;
86
87
 
@@ -110,13 +111,12 @@ export interface InputProps extends TextInputProps {
110
111
  hintText?: string;
111
112
 
112
113
  /**
113
- * Optional. Callback function to be called when the floating icon is pressed.
114
+ * Optional. Represents the style of the Input component.
114
115
  */
115
116
  onPressFloatingIcon?: () => void;
116
117
 
117
118
  /**
118
- * Optional. If `true`, shows a clear icon while focused with a value.
119
- * Defaults to `true` if not provided.
119
+ * Optional. Represents the style of the Input component.
120
120
  */
121
121
  showClearIcon?: boolean;
122
122
  }
@@ -137,12 +137,12 @@ export interface InputSearchProps extends TextInputProps {
137
137
 
138
138
  /**
139
139
  * Optional. If `true`, the text on the search button will be displayed.
140
- * Defaults to `true` if not provided.
140
+ * Defaults to `false` if not provided.
141
141
  */
142
142
  showButtonText?: boolean;
143
143
 
144
144
  /**
145
- * Optional. Callback function to be called when the search button is pressed.
145
+ * Optional. Represents the value for the floating title in the InputSearch component.
146
146
  */
147
147
  onPressButtonText?: () => void;
148
148
 
@@ -180,7 +180,7 @@ export interface InputSearchProps extends TextInputProps {
180
180
  onPressTrailing?: () => void;
181
181
 
182
182
  /**
183
- * Optional. Background color of the search field. Defaults to the surface color.
183
+ * Optional. If `true`, the user won't be able to interact with the Input component.
184
184
  */
185
185
  backgroundColor?: string;
186
186
 
@@ -195,7 +195,8 @@ export interface InputSearchProps extends TextInputProps {
195
195
  typingData?: string[];
196
196
 
197
197
  /**
198
- * Optional. Called when the field is pressed while showing `typingData`.
198
+ * Optional. Represents the callback function to be called when the search button is pressed.
199
+ * @param e
199
200
  */
200
201
  onPress?: (e: GestureResponderEvent) => void;
201
202
  }
@@ -258,7 +259,7 @@ export interface InputDropDownProps extends TouchableOpacityProps {
258
259
  placeholder?: string;
259
260
 
260
261
  /**
261
- * Optional. If `true`, the value wraps to multiple lines and the chevron aligns to the top.
262
+ * Optional. Represents the data for the dropdown.
262
263
  */
263
264
  multiline?: boolean;
264
265
 
@@ -302,18 +303,19 @@ export interface InputDropDownProps extends TouchableOpacityProps {
302
303
  required?: boolean;
303
304
 
304
305
  /**
305
- * Optional. If `true`, keeps an empty error row when there is no error or hint.
306
+ * Optional. If `true`,
307
+ * include spacing when Input not have error message.
306
308
  * Defaults to `false` if not provided.
307
309
  */
308
310
  errorSpacing?: boolean;
309
311
 
310
312
  /**
311
- * Optional. If `true`, shows a loading spinner in place of the trailing icon.
313
+ * If true, the icon of input will use be show indicator loading.
312
314
  */
313
315
  loading?: boolean;
314
316
 
315
317
  /**
316
- * Optional. Represents the leading icon in the Input component.
318
+ * Optional. Represents the leading icon in the Input component.
317
319
  */
318
320
  leadingIcon?: string;
319
321
 
@@ -338,14 +340,15 @@ export interface InputDropDownProps extends TouchableOpacityProps {
338
340
  hintText?: string;
339
341
 
340
342
  /**
341
- * Optional. Callback function to be called when the floating icon is pressed.
343
+ * Optional. Represents the style of the Input component.
342
344
  */
343
345
  onPressFloatingIcon?: () => void;
344
346
  }
345
347
 
346
348
  export interface InputPhoneNumberProps extends InputProps {
347
349
  /**
348
- * Optional. Currently unused: the displayed prefix is always `+84`.
350
+ * Optional. Represents the country code to be displayed in the InputPhoneNumber component.
351
+ * It should be in the format of a string, e.g., "+1" for the United States.
349
352
  */
350
353
  countryCode?: string;
351
354
  }
@@ -1,21 +1,15 @@
1
1
  export const moneyFormatter = new Intl.NumberFormat('vi-VN');
2
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
3
  export const findEdit = (old: string, text: string) => {
9
4
  let start = 0;
10
5
  while (start < text.length && old[start] === text[start]) {
11
6
  start += 1;
12
7
  }
13
- const maxSuffix = Math.min(text.length, old.length) - start;
14
8
  let suffix = 0;
15
- while (suffix < maxSuffix) {
16
- if (old[old.length - 1 - suffix] !== text[text.length - 1 - suffix]) {
17
- break;
18
- }
9
+ while (
10
+ suffix < Math.min(text.length, old.length) - start &&
11
+ old[old.length - 1 - suffix] === text[text.length - 1 - suffix]
12
+ ) {
19
13
  suffix += 1;
20
14
  }
21
15
  const size = old.length + text.length - 2 * (start + suffix);
package/Input/styles.ts CHANGED
@@ -2,6 +2,7 @@ import { Platform, StyleSheet } from 'react-native';
2
2
  import { Colors, Radius, Spacing } from '../Consts';
3
3
 
4
4
  export default StyleSheet.create({
5
+ //input style
5
6
  input: {
6
7
  flex: 1,
7
8
  paddingLeft: Spacing.M,
@@ -64,6 +65,7 @@ export default StyleSheet.create({
64
65
  marginTop: Spacing.S,
65
66
  },
66
67
 
68
+ //text area style
67
69
  textAreaView: {
68
70
  flex: 1,
69
71
  },
@@ -92,6 +94,7 @@ export default StyleSheet.create({
92
94
  marginBottom: Spacing.XS,
93
95
  },
94
96
 
97
+ //searchInput
95
98
  searchInputWrapper: {
96
99
  flexDirection: 'row',
97
100
  borderRadius: Radius.XL,
@@ -133,6 +136,7 @@ export default StyleSheet.create({
133
136
  ios: 36,
134
137
  }),
135
138
  },
139
+ //OTP
136
140
  otpWrapper: {
137
141
  width: '100%',
138
142
  marginTop: Spacing.M,
@@ -179,6 +183,7 @@ export default StyleSheet.create({
179
183
  opacity: 0.02,
180
184
  letterSpacing: Spacing.XXL,
181
185
  },
186
+ //DropDown
182
187
  inputDropDownWrapper: {
183
188
  flexDirection: 'row',
184
189
  marginTop: Spacing.S,
package/Input/utils.ts CHANGED
@@ -1,9 +1,5 @@
1
1
  import { Localize } from '../Application';
2
2
 
3
- /**
4
- * Formats a number Vietnamese-style (`.` thousands, `,` decimals) with
5
- * `currency` appended; 0, NaN or a falsy value gives `0<currency>`.
6
- */
7
3
  const formatNumberToMoney = (number: number, currency = '') => {
8
4
  if (!number || isNaN(number) || Number(number) === 0) {
9
5
  return `0${currency}`;
@@ -45,10 +41,6 @@ const formatNumberToMoney = (number: number, currency = '') => {
45
41
  return isNegative ? `-${result}${currency}` : `${result}${currency}`;
46
42
  };
47
43
 
48
- /**
49
- * Parses a formatted money string back to a number by stripping
50
- * `currencyUnit`, separators, `đ` and spaces; unparsable text gives 0.
51
- */
52
44
  const formatMoneyToNumber = (money: string, currencyUnit: string) => {
53
45
  if (money && money.length > 0) {
54
46
  const moneyString = money
@@ -67,20 +59,26 @@ const formatMoneyToNumber = (money: string, currencyUnit: string) => {
67
59
  return Number(money);
68
60
  };
69
61
 
62
+ // --- PHONE VALIDATION ---
70
63
  function formatPhoneNumber(phone: string): string {
71
64
  return phone.replace(/\D/g, '');
72
65
  }
73
66
 
74
- /**
75
- * Keeps the digits of `phone` (prepending the `0` a 9-char local number lacks)
76
- * and returns a localized error when empty or not 10-11 digits.
77
- */
78
67
  function checkValidPhoneNumber(phone: string): {
79
68
  phoneFormatted: string;
80
69
  error?: string;
81
70
  } {
82
- const isMissingLeadingZero = phone.length === 9 && /^[1-9]/.test(phone);
83
- const phoneNumber = isMissingLeadingZero ? `0${phone}` : phone;
71
+ let phoneNumber = phone;
72
+
73
+ // if not starting with 0 and has 9 digits => prepend 0
74
+ if (
75
+ phoneNumber.length > 0 &&
76
+ phoneNumber[0] !== '0' &&
77
+ /^\d$/.test(phoneNumber[0]) &&
78
+ phoneNumber.length === 9
79
+ ) {
80
+ phoneNumber = '0' + phoneNumber;
81
+ }
84
82
 
85
83
  const phoneFormatted = formatPhoneNumber(phoneNumber);
86
84
  const localize = new Localize({ vi: {}, en: {} });
package/Layout/Card.tsx CHANGED
@@ -20,10 +20,6 @@ export interface CardProps extends ViewProps {
20
20
  useShadow?: boolean;
21
21
  }
22
22
 
23
- /**
24
- * Surface card across the content width minus 12pt margins, with its own grid for child
25
- * Items; optional background image and light shadow.
26
- */
27
23
  const Card: React.FC<CardProps> = ({
28
24
  children,
29
25
  style,
@@ -38,9 +34,10 @@ const Card: React.FC<CardProps> = ({
38
34
  const gutterSize = 8;
39
35
  const margin = 12;
40
36
  const widthSection = contentWidth - margin * 2;
41
- const innerWidth = widthSection - margin * 2;
42
- const columnsWidth = innerWidth - gutterSize * (numberOfColumns - 1);
43
- const sizePerSpan = columnsWidth / numberOfColumns - 1 / numberOfColumns;
37
+ let sizePerSpan =
38
+ (widthSection - margin * 2 - gutterSize * (numberOfColumns - 1)) /
39
+ numberOfColumns -
40
+ 1 / numberOfColumns;
44
41
 
45
42
  const gridContext: GridContextProps = {
46
43
  numberOfColumns,
@@ -31,10 +31,6 @@ export interface FloatingButtonProps {
31
31
  renderComponent?: () => React.ReactNode;
32
32
  }
33
33
 
34
- /**
35
- * Floating action button above the screen bottom. With a label and a scroll value it
36
- * shrinks to its icon while scrolling down and expands again on scroll up.
37
- */
38
34
  export const FloatingButton: React.FC<FloatingButtonProps> = ({
39
35
  renderComponent,
40
36
  label = '',
package/Layout/Item.tsx CHANGED
@@ -7,20 +7,16 @@ import { SpanNumber } from './types';
7
7
 
8
8
  export interface ItemProps extends ViewProps {
9
9
  /**
10
- * Width in grid columns (1-12). Defaults to the full row.
10
+ * Represents the width of the Card component in terms of span numbers (1-12).
11
11
  */
12
12
  widthSpan?: SpanNumber;
13
13
 
14
14
  /**
15
- * Optional. Height in grid spans (1-12). Unset keeps the content height.
15
+ * Optional. Represents the height of the Card component in terms of span numbers (1-12).
16
16
  */
17
17
  heightSpan?: SpanNumber;
18
18
  }
19
19
 
20
- /**
21
- * Grid cell sized from the enclosing GridContext; outlined when the mini app turns on
22
- * the baseline debug feature.
23
- */
24
20
  const Item: React.FC<ItemProps> = ({
25
21
  widthSpan,
26
22
  heightSpan,
@@ -7,16 +7,12 @@ import { SpanNumber } from './types';
7
7
 
8
8
  export interface ItemListProps extends FlatListProps<any> {
9
9
  /**
10
- * Width of each item in grid columns (1-12). Defaults to the full row.
10
+ * Represents the width of the Card component in terms of span numbers (1-12).
11
11
  */
12
12
  widthSpan?: SpanNumber;
13
13
  data: any[];
14
14
  }
15
15
 
16
- /**
17
- * FlatList on the grid: `widthSpan` sets how many items share a row, and every item but
18
- * the first of a row gets the gutter on its left.
19
- */
20
16
  const ItemList = forwardRef(
21
17
  (
22
18
  {
@@ -34,9 +30,6 @@ const ItemList = forwardRef(
34
30
  const indexBegin = props?.data?.map(
35
31
  (_i: any, index: number) => index * numColumns,
36
32
  );
37
- const defaultKeyExtractor = (item: any, index: number) => {
38
- return (item?.id ?? item?.key ?? index).toString();
39
- };
40
33
  const _renderItem = (item: any) => {
41
34
  if (indexBegin?.includes(item?.index)) {
42
35
  return <Item widthSpan={widthItem}>{renderItem?.(item)}</Item>;
@@ -53,7 +46,12 @@ const ItemList = forwardRef(
53
46
  ref={ref as React.RefObject<FlatList>}
54
47
  {...props}
55
48
  key={`ItemList-${numColumns}`}
56
- keyExtractor={(props as any)?.keyExtractor ?? defaultKeyExtractor}
49
+ keyExtractor={
50
+ // prefer caller's keyExtractor; fallback to common id/key/index
51
+ (props as any)?.keyExtractor ??
52
+ ((item: any, index: number) =>
53
+ (item?.id ?? item?.key ?? index).toString())
54
+ }
57
55
  numColumns={numColumns}
58
56
  renderItem={_renderItem}
59
57
  horizontal={false}
@@ -7,12 +7,11 @@ import { SpanNumber } from './types';
7
7
 
8
8
  export interface ItemSectionListProps extends SectionListProps<any> {
9
9
  /**
10
- * Width of each item in grid columns (1-12). Defaults to the full row.
10
+ * Represents the width of the Card component in terms of span numbers (1-12).
11
11
  */
12
12
  widthSpan?: SpanNumber;
13
13
  }
14
14
 
15
- /** SectionList whose items sit on the grid, `widthSpan` columns wide, a gutter apart. */
16
15
  const ItemSectionList: FC<ItemSectionListProps> = ({
17
16
  renderItem,
18
17
  widthSpan,
@@ -19,43 +19,43 @@ try {
19
19
  }
20
20
 
21
21
  /**
22
- * Screen regions the system currently occludes, relative to the provider, which fills
23
- * the root view so they line up with window coordinates.
22
+ * screen regions the system currently occludes, relative to the provider, which fills
23
+ * the root view so they line up with window coordinates
24
24
  */
25
25
  const ReservedRegionsContext = createContext<ReservedRegion[]>([]);
26
26
 
27
27
  /**
28
- * Vertical seam splitting the display into left and right halves, e.g. iPhone Duo
29
- * half folded. `undefined` while the display is flat or the system reports none.
28
+ * vertical seam splitting the display into left and right halves, e.g. iPhone Duo
29
+ * half folded. `undefined` while the display is flat or the system reports none
30
30
  */
31
31
  const HingeContext = createContext<ReservedRegion | undefined>(undefined);
32
32
 
33
- /** Frame of the vertical hinge (see HingeContext), `undefined` while the display is flat. */
34
33
  const useHinge = () => useContext(HingeContext);
35
34
 
36
35
  /**
37
- * Provides the occlusion regions and the vertical division (hinge) reported by the native
38
- * provider.
36
+ * keeps the occlusion regions and the vertical division reported by the native provider
39
37
  */
40
38
  const OcclusionRegions: React.FC<{
41
39
  useRegions: NativeReservedRegions['useReservedRegions'];
42
40
  children: ReactNode;
43
41
  }> = ({ useRegions, children }) => {
44
42
  const regions = useRegions();
45
- const occlusion = useMemo(() => {
46
- return regions
47
- .filter(region => region.kind === 'occlusion')
48
- .map(region => region.frame);
49
- }, [regions]);
50
- const hinge = useMemo(() => {
51
- const division = regions.find(region => {
52
- if (region.kind !== 'division') {
53
- return false;
54
- }
55
- return region.frame.height > region.frame.width;
56
- });
57
- return division?.frame;
58
- }, [regions]);
43
+ const occlusion = useMemo(
44
+ () =>
45
+ regions
46
+ .filter(region => region.kind === 'occlusion')
47
+ .map(region => region.frame),
48
+ [regions],
49
+ );
50
+ const hinge = useMemo(
51
+ () =>
52
+ regions.find(
53
+ region =>
54
+ region.kind === 'division' &&
55
+ region.frame.height > region.frame.width,
56
+ )?.frame,
57
+ [regions],
58
+ );
59
59
 
60
60
  return (
61
61
  <ReservedRegionsContext.Provider value={occlusion}>
@@ -65,8 +65,8 @@ const OcclusionRegions: React.FC<{
65
65
  };
66
66
 
67
67
  /**
68
- * Tracks the system occlusion regions (iOS 27.1+), e.g. the iPhone Duo status bar
69
- * cluster growing for a call or a Live Activity.
68
+ * tracks the system occlusion regions (iOS 27.1+), e.g. the iPhone Duo status bar
69
+ * cluster growing for a call or a Live Activity
70
70
  */
71
71
  const ReservedRegionsProvider: React.FC<{ children: ReactNode }> = ({
72
72
  children,
@@ -75,8 +75,8 @@ const ReservedRegionsProvider: React.FC<{ children: ReactNode }> = ({
75
75
  return <>{children}</>;
76
76
  }
77
77
 
78
- const NativeProvider = nativeLib.ReservedRegionsProvider;
79
- const { useReservedRegions } = nativeLib;
78
+ const { ReservedRegionsProvider: NativeProvider, useReservedRegions } =
79
+ nativeLib;
80
80
  return (
81
81
  <NativeProvider style={styles.container}>
82
82
  <OcclusionRegions useRegions={useReservedRegions}>
package/Layout/Screen.tsx CHANGED
@@ -37,10 +37,6 @@ import { useScreenQuickReturn } from './screenQuickReturn';
37
37
 
38
38
  export type { ScreenProps };
39
39
 
40
- /**
41
- * Screen container: sets the navigation header, lays children on the grid, and adds the
42
- * scroll view, floating button and footer, with iPhone Duo side bar and tab bar insets.
43
- */
44
40
  const Screen = forwardRef(
45
41
  (
46
42
  {
@@ -112,12 +108,14 @@ const Screen = forwardRef(
112
108
  const isIOS = Platform.OS === 'ios';
113
109
  const bottomInset = isIOS ? Math.min(insets.bottom, 21) : insets.bottom;
114
110
  const hasSideBar = !!layout.sideBar;
115
- const isPlainHeader = headerType === 'default' || headerType === 'extended';
116
- const hasCustomHeader = !!animatedHeader || !!inputSearchProps;
117
- const useDuoGlass = hasSideBar && isPlainHeader && !hasCustomHeader;
111
+ const useDuoGlass =
112
+ hasSideBar &&
113
+ (headerType === 'default' || headerType === 'extended') &&
114
+ !animatedHeader &&
115
+ !inputSearchProps;
118
116
 
119
- const hasOverlayHeader = useDuoGlass || !!animatedHeader;
120
- const useQuickReturn = hasSideBar && scrollable && hasOverlayHeader;
117
+ const useQuickReturn =
118
+ hasSideBar && scrollable && (useDuoGlass || !!animatedHeader);
121
119
  const { quickReturnOptions, snapQuickReturnHeader } = useScreenQuickReturn(
122
120
  sharedValue,
123
121
  useQuickReturn,
@@ -125,10 +123,18 @@ const Screen = forwardRef(
125
123
  );
126
124
 
127
125
  let keyboardOffset = heightHeader - bottomInset;
128
- if (headerType === 'extended' || hasCustomHeader || useDuoGlass) {
126
+ if (
127
+ headerType === 'extended' ||
128
+ animatedHeader ||
129
+ inputSearchProps ||
130
+ useDuoGlass
131
+ ) {
129
132
  keyboardOffset = -bottomInset;
130
133
  }
131
134
 
135
+ /**
136
+ * inject params for screen tracking
137
+ */
132
138
  screen?.onSetParams?.(trackingParams);
133
139
 
134
140
  const { setSearchHeader, currentTint } = useScreenHeader({
@@ -146,7 +152,9 @@ const Screen = forwardRef(
146
152
  layoutOffset,
147
153
  });
148
154
 
149
- // mutates the content node so callers keep its methods plus the header setters
155
+ /**
156
+ * expose ref for screen
157
+ */
150
158
  useImperativeHandle(ref, () => {
151
159
  return Object.assign(screenRef.current || {}, {
152
160
  setOptions: (params: NavigationOptions) => {
@@ -157,18 +165,19 @@ const Screen = forwardRef(
157
165
  });
158
166
  });
159
167
 
160
- const scrollHandlers = createScrollHandlers({
161
- scrollable,
162
- animatedValue: animatedValue.current,
163
- sharedValue,
164
- scrollViewProps,
165
- animatedHeader,
166
- inputSearchProps,
167
- currentTint,
168
- navigation,
169
- snapQuickReturnHeader,
170
- ref,
171
- });
168
+ const { handleScroll, handleScrollEnd, handleMomentumScrollEnd } =
169
+ createScrollHandlers({
170
+ scrollable,
171
+ animatedValue: animatedValue.current,
172
+ sharedValue,
173
+ scrollViewProps,
174
+ animatedHeader,
175
+ inputSearchProps,
176
+ currentTint,
177
+ navigation,
178
+ snapQuickReturnHeader,
179
+ ref,
180
+ });
172
181
  const Component: any = scrollable ? Animated.ScrollView : View;
173
182
 
174
183
  const getHeight = () => {
@@ -198,35 +207,6 @@ const Screen = forwardRef(
198
207
  floatingButtonBottom = 12 + duoTabInset;
199
208
  }
200
209
 
201
- const renderHeaderLayer = () => {
202
- if (useDuoGlass) {
203
- return (
204
- <DuoScrollGradient
205
- animatedValue={sharedValue}
206
- gradientColor={gradientColor}
207
- headerBackground={headerBackground}
208
- heightHeader={heightHeader}
209
- extended={headerType === 'extended'}
210
- followScroll={useQuickReturn}
211
- />
212
- );
213
- }
214
- return (
215
- <HeaderExtendHeader
216
- headerType={headerType}
217
- heightHeader={heightHeader}
218
- headerRightWidth={headerRightWidth}
219
- animatedValue={sharedValue}
220
- inputSearchProps={inputSearchProps}
221
- navigation={navigation}
222
- inputSearchRef={inputSearchRef}
223
- useShadowHeader={useShadowHeader}
224
- gradientColor={gradientColor}
225
- headerBackground={headerBackground}
226
- />
227
- );
228
- };
229
-
230
210
  return (
231
211
  <View
232
212
  style={[
@@ -237,7 +217,29 @@ const Screen = forwardRef(
237
217
  },
238
218
  ]}
239
219
  >
240
- {renderHeaderLayer()}
220
+ {useDuoGlass ? (
221
+ <DuoScrollGradient
222
+ animatedValue={sharedValue}
223
+ gradientColor={gradientColor}
224
+ headerBackground={headerBackground}
225
+ heightHeader={heightHeader}
226
+ extended={headerType === 'extended'}
227
+ followScroll={useQuickReturn}
228
+ />
229
+ ) : (
230
+ <HeaderExtendHeader
231
+ headerType={headerType}
232
+ heightHeader={heightHeader}
233
+ headerRightWidth={headerRightWidth}
234
+ animatedValue={sharedValue}
235
+ inputSearchProps={inputSearchProps}
236
+ navigation={navigation}
237
+ inputSearchRef={inputSearchRef}
238
+ useShadowHeader={useShadowHeader}
239
+ gradientColor={gradientColor}
240
+ headerBackground={headerBackground}
241
+ />
242
+ )}
241
243
 
242
244
  <KeyboardAvoidingView
243
245
  style={[
@@ -257,9 +259,9 @@ const Screen = forwardRef(
257
259
  {...scrollViewProps}
258
260
  ref={screenRef}
259
261
  showsVerticalScrollIndicator={false}
260
- onScroll={scrollHandlers.handleScroll}
261
- onScrollEndDrag={scrollHandlers.handleScrollEnd}
262
- onMomentumScrollEnd={scrollHandlers.handleMomentumScrollEnd}
262
+ onScroll={handleScroll}
263
+ onScrollEndDrag={handleScrollEnd}
264
+ onMomentumScrollEnd={handleMomentumScrollEnd}
263
265
  scrollEventThrottle={16}
264
266
  style={[
265
267
  Styles.flex,
@@ -15,8 +15,8 @@ export interface SectionProps extends ViewProps {
15
15
  expanded?: boolean;
16
16
 
17
17
  /**
18
- * Optional. If `true`, 12pt side margins are applied to the Section component.
19
- * Defaults to `true`.
18
+ * Optional. If `true`, margin will be applied to the Section component.
19
+ * Defaults to `false` if not provided.
20
20
  */
21
21
  useMargin?: boolean;
22
22
 
@@ -26,10 +26,6 @@ export interface SectionProps extends ViewProps {
26
26
  backgroundImage?: string;
27
27
  }
28
28
 
29
- /**
30
- * Content-wide grid row (12 or 24 columns) with optional side margins; child Items size
31
- * themselves from its GridContext.
32
- */
33
29
  const Section: React.FC<SectionProps> = ({
34
30
  children,
35
31
  useMargin = true,
@@ -47,8 +43,9 @@ const Section: React.FC<SectionProps> = ({
47
43
  }
48
44
  const widthSection = contentWidth - margin * 2;
49
45
 
50
- const columnsWidth = widthSection - gutterSize * (numberOfColumns - 1);
51
- const sizePerSpan = columnsWidth / numberOfColumns - 1 / numberOfColumns;
46
+ const sizePerSpan =
47
+ (widthSection - gutterSize * (numberOfColumns - 1)) / numberOfColumns -
48
+ 1 / numberOfColumns;
52
49
 
53
50
  const gridContext: GridContextProps = {
54
51
  numberOfColumns,
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { TrackingScopeContext } from '../Context';
3
3
 
4
- /** Names a tracking scope; components inside prefix their component ids with it. */
5
4
  const TrackingScope = ({
6
5
  scopeName,
7
6
  children,