@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.
- package/Application/BottomSheet.hooks.ts +8 -8
- package/Application/BottomSheet.parts.tsx +34 -44
- package/Application/BottomSheet.tsx +26 -35
- package/Application/BottomTab/ActiveIndicator.tsx +14 -15
- package/Application/BottomTab/BottomTabBar.styles.ts +18 -1
- package/Application/BottomTab/BottomTabBar.tsx +40 -63
- package/Application/BottomTab/BottomTabInset.tsx +4 -8
- package/Application/BottomTab/CurvedContainer.tsx +20 -16
- package/Application/BottomTab/CustomBottomTabItem.tsx +13 -16
- package/Application/BottomTab/DuoBarCompression.tsx +19 -13
- package/Application/BottomTab/DuoRailTabBar.tsx +13 -17
- package/Application/BottomTab/DuoTabBar.tsx +24 -12
- package/Application/BottomTab/TabBarIcon.tsx +8 -13
- package/Application/BottomTab/TabScreen.tsx +5 -1
- package/Application/BottomTab/index.tsx +30 -38
- package/Application/BottomTab/metrics.ts +46 -24
- package/Application/BottomTab/tabItems.ts +1 -1
- package/Application/BottomTab/usePressLift.ts +2 -2
- package/Application/Components/BackgroundImageView.tsx +0 -4
- package/Application/Components/DuoGlassBackground.tsx +4 -5
- package/Application/Components/HeaderAnimated.tsx +0 -4
- package/Application/Components/HeaderBackground.tsx +0 -4
- package/Application/Components/HeaderExtendHeader.tsx +10 -11
- package/Application/Components/HeaderLeft.tsx +1 -2
- package/Application/Components/HeaderRight.tsx +1 -2
- package/Application/Components/HeaderTitle.shared.ts +9 -11
- package/Application/Components/HeaderTitle.tsx +3 -4
- package/Application/Components/HeaderToolkitAction.tsx +20 -17
- package/Application/Components/NavigationButton.tsx +1 -2
- package/Application/Components/SearchHeader.tsx +10 -17
- package/Application/Components/TitleJourney.tsx +2 -2
- package/Application/Components/TitleLocation.tsx +2 -2
- package/Application/Components/TitleUser.tsx +2 -2
- package/Application/Components/useToolkitActions.tsx +32 -17
- package/Application/Localize.ts +0 -7
- package/Application/ModalScreen.tsx +3 -9
- package/Application/Navigation.ts +16 -14
- package/Application/NavigationContainer.tsx +16 -19
- package/Application/Navigator.ts +48 -20
- package/Application/StackScreen.tracking.ts +26 -11
- package/Application/StackScreen.tsx +35 -8
- package/Application/TooltipPortal.tsx +5 -12
- package/Application/WidgetContainer.tsx +4 -10
- package/Application/__tests__/modalLayout.test.ts +128 -0
- package/Application/modalLayout.ts +14 -13
- package/Application/navigationOptions.tsx +17 -21
- package/Application/types.tabs.ts +0 -1
- package/Badge/Badge.tsx +0 -5
- package/Badge/BadgeDot.tsx +0 -1
- package/Badge/BadgeDotAnimation.tsx +7 -15
- package/Badge/BadgeRibbon.tsx +38 -46
- package/Badge/Shape.tsx +0 -2
- package/Badge/types.ts +2 -2
- package/Button/index.tsx +16 -5
- package/Button/utils.ts +15 -9
- package/CheckBox/index.tsx +0 -4
- package/Consts/theme.ts +10 -10
- package/Context/index.ts +0 -1
- package/Divider/DashDivider.tsx +0 -1
- package/Divider/index.tsx +0 -4
- package/FoundationList/index.tsx +0 -4
- package/Icon/index.tsx +6 -6
- package/Icon/types.ts +1 -1
- package/IconButton/index.tsx +12 -4
- package/Image/index.tsx +7 -9
- package/Input/Input.tsx +9 -8
- package/Input/InputDropDown.tsx +12 -10
- package/Input/InputMoney.tsx +8 -12
- package/Input/InputMoneyView.tsx +7 -14
- package/Input/InputOTP.tsx +33 -35
- package/Input/InputPhoneNumber.tsx +9 -8
- package/Input/InputSearch.tsx +6 -4
- package/Input/InputTextArea.tsx +0 -4
- package/Input/SearchTextTyping.tsx +0 -4
- package/Input/SystemTextInput.tsx +2 -7
- package/Input/TextTyping.tsx +0 -4
- package/Input/common.tsx +12 -26
- package/Input/index.tsx +20 -17
- package/Input/moneyUtils.ts +4 -10
- package/Input/styles.ts +5 -0
- package/Input/utils.ts +12 -14
- package/Layout/Card.tsx +4 -7
- package/Layout/FloatingButton.tsx +0 -4
- package/Layout/Item.tsx +2 -6
- package/Layout/ItemList.tsx +7 -9
- package/Layout/ItemSectionList.tsx +1 -2
- package/Layout/ReservedRegions.tsx +25 -25
- package/Layout/Screen.tsx +58 -56
- package/Layout/Section.tsx +5 -8
- package/Layout/TrackingScope.tsx +0 -1
- package/Layout/screenContent.tsx +2 -4
- package/Layout/screenFooter.tsx +18 -28
- package/Layout/screenHeader.tsx +31 -34
- package/Layout/screenQuickReturn.tsx +20 -17
- package/Layout/screenScroll.ts +7 -4
- package/Layout/screenTypes.ts +2 -3
- package/Layout/types.ts +4 -2
- package/Layout/utils.ts +37 -31
- package/Loader/DotLoader.tsx +0 -4
- package/Loader/Loader.tsx +0 -4
- package/Loader/ProgressBar.tsx +0 -1
- package/Loader/Spinner.tsx +0 -4
- package/Loader/utils.ts +7 -11
- package/Pagination/Dot.tsx +0 -4
- package/Pagination/PaginationDot.tsx +0 -1
- package/Pagination/PaginationNumber.tsx +3 -5
- package/Pagination/PaginationScroll.tsx +0 -5
- package/Pagination/PaginationWhiteDot.tsx +0 -1
- package/Pagination/index.tsx +0 -4
- package/Pagination/types.ts +2 -2
- package/Popup/PopupNotify.tsx +48 -44
- package/Popup/PopupPromotion.tsx +7 -4
- package/Popup/types.ts +4 -4
- package/Popup/utils.ts +0 -4
- package/Radio/index.tsx +0 -4
- package/Skeleton/index.tsx +0 -8
- package/Switch/index.tsx +0 -1
- package/Tag/index.tsx +1 -5
- package/Tag/types.ts +3 -3
- package/Text/index.tsx +3 -14
- package/Text/styles.ts +1 -1
- package/Text/types.ts +6 -1
- package/Text/utils.ts +0 -9
- package/Title/index.tsx +32 -41
- package/ViewBoundary/index.tsx +2 -4
- package/index.ts +6 -0
- 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.
|
|
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`,
|
|
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
|
-
*
|
|
79
|
+
* If true, the icon of input will use be show indicator loading.
|
|
79
80
|
*/
|
|
80
81
|
loading?: boolean;
|
|
81
82
|
|
|
82
83
|
/**
|
|
83
|
-
*
|
|
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.
|
|
114
|
+
* Optional. Represents the style of the Input component.
|
|
114
115
|
*/
|
|
115
116
|
onPressFloatingIcon?: () => void;
|
|
116
117
|
|
|
117
118
|
/**
|
|
118
|
-
* Optional.
|
|
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 `
|
|
140
|
+
* Defaults to `false` if not provided.
|
|
141
141
|
*/
|
|
142
142
|
showButtonText?: boolean;
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
|
-
* Optional.
|
|
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.
|
|
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.
|
|
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.
|
|
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`,
|
|
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
|
-
*
|
|
313
|
+
* If true, the icon of input will use be show indicator loading.
|
|
312
314
|
*/
|
|
313
315
|
loading?: boolean;
|
|
314
316
|
|
|
315
317
|
/**
|
|
316
|
-
*
|
|
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.
|
|
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.
|
|
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
|
}
|
package/Input/moneyUtils.ts
CHANGED
|
@@ -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 (
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
*
|
|
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.
|
|
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,
|
package/Layout/ItemList.tsx
CHANGED
|
@@ -7,16 +7,12 @@ import { SpanNumber } from './types';
|
|
|
7
7
|
|
|
8
8
|
export interface ItemListProps extends FlatListProps<any> {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
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={
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
*
|
|
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 =
|
|
79
|
-
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
111
|
+
const useDuoGlass =
|
|
112
|
+
hasSideBar &&
|
|
113
|
+
(headerType === 'default' || headerType === 'extended') &&
|
|
114
|
+
!animatedHeader &&
|
|
115
|
+
!inputSearchProps;
|
|
118
116
|
|
|
119
|
-
const
|
|
120
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
{
|
|
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={
|
|
261
|
-
onScrollEndDrag={
|
|
262
|
-
onMomentumScrollEnd={
|
|
262
|
+
onScroll={handleScroll}
|
|
263
|
+
onScrollEndDrag={handleScrollEnd}
|
|
264
|
+
onMomentumScrollEnd={handleMomentumScrollEnd}
|
|
263
265
|
scrollEventThrottle={16}
|
|
264
266
|
style={[
|
|
265
267
|
Styles.flex,
|
package/Layout/Section.tsx
CHANGED
|
@@ -15,8 +15,8 @@ export interface SectionProps extends ViewProps {
|
|
|
15
15
|
expanded?: boolean;
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Optional. If `true`,
|
|
19
|
-
* Defaults to `
|
|
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
|
|
51
|
-
|
|
46
|
+
const sizePerSpan =
|
|
47
|
+
(widthSection - gutterSize * (numberOfColumns - 1)) / numberOfColumns -
|
|
48
|
+
1 / numberOfColumns;
|
|
52
49
|
|
|
53
50
|
const gridContext: GridContextProps = {
|
|
54
51
|
numberOfColumns,
|