@momo-kits/foundation 0.167.1-beta.7 → 0.167.1-duo.12
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.tsx +115 -14
- package/Application/BottomTab/BottomTabBar.tsx +6 -3
- package/Application/BottomTab/DuoBarCompression.tsx +135 -0
- package/Application/BottomTab/DuoTabBar.tsx +462 -0
- package/Application/BottomTab/index.tsx +155 -134
- package/Application/Components/DuoGlassBackground.tsx +179 -0
- package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
- package/Application/Components/HeaderExtendHeader.tsx +65 -28
- package/Application/Components/HeaderLeft.tsx +23 -0
- package/Application/Components/HeaderRight.tsx +104 -9
- package/Application/Components/HeaderTitle.tsx +47 -21
- package/Application/Components/OptionalGlassView.ts +11 -0
- package/Application/Components/SearchHeader.tsx +15 -14
- package/Application/Components/SideBarButton.tsx +128 -0
- package/Application/ModalScreen.tsx +16 -2
- package/Application/NavigationContainer.tsx +36 -48
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/WidgetContainer.tsx +9 -15
- package/Application/device.ts +29 -0
- package/Application/types.ts +10 -1
- package/Application/utils.tsx +10 -3
- package/Consts/index.ts +0 -1
- package/Consts/theme.ts +3 -4
- package/Input/Input.tsx +3 -4
- package/Input/InputMoney.tsx +31 -51
- package/Input/InputPhoneNumber.tsx +3 -4
- package/Input/InputSearch.tsx +3 -4
- package/Input/InputTextArea.tsx +3 -4
- package/Layout/Card.tsx +8 -26
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/Item.tsx +1 -10
- package/Layout/ReservedRegions.tsx +47 -0
- package/Layout/Screen.tsx +240 -48
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +5 -0
- package/Layout/utils.ts +375 -5
- package/Popup/PopupNotify.tsx +33 -22
- package/Popup/PopupPromotion.tsx +20 -8
- package/Popup/utils.ts +32 -0
- package/Text/index.tsx +5 -15
- package/Text/utils.ts +1 -2
- package/package.json +3 -2
- package/Consts/designSystemFont.ts +0 -25
- package/Layout/GridSystem.tsx +0 -137
package/Layout/Screen.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import React, {
|
|
|
9
9
|
useContext,
|
|
10
10
|
useEffect,
|
|
11
11
|
useImperativeHandle,
|
|
12
|
+
useMemo,
|
|
12
13
|
useRef,
|
|
13
14
|
} from 'react';
|
|
14
15
|
import {
|
|
@@ -21,11 +22,14 @@ import {
|
|
|
21
22
|
ScrollViewProps,
|
|
22
23
|
StatusBar,
|
|
23
24
|
StatusBarStyle,
|
|
24
|
-
useWindowDimensions,
|
|
25
25
|
View,
|
|
26
26
|
ViewProps,
|
|
27
27
|
} from 'react-native';
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
useAnimatedReaction,
|
|
30
|
+
useSharedValue,
|
|
31
|
+
withTiming,
|
|
32
|
+
} from 'react-native-reanimated';
|
|
29
33
|
import {
|
|
30
34
|
useSafeAreaFrame,
|
|
31
35
|
useSafeAreaInsets,
|
|
@@ -44,7 +48,7 @@ import styles from './styles';
|
|
|
44
48
|
import { HeaderType } from './types';
|
|
45
49
|
import { InputRef } from '../Input';
|
|
46
50
|
import { exportHeaderTitle, getOptions } from '../Application/utils';
|
|
47
|
-
import { validateChildren } from './utils';
|
|
51
|
+
import { getHeaderMargin, useScreenLayout, validateChildren } from './utils';
|
|
48
52
|
import Section from './Section';
|
|
49
53
|
import {
|
|
50
54
|
HeaderBackground,
|
|
@@ -53,6 +57,12 @@ import {
|
|
|
53
57
|
HeaderTitle,
|
|
54
58
|
SearchHeader,
|
|
55
59
|
} from '../Application';
|
|
60
|
+
import {
|
|
61
|
+
DuoGlassBackground,
|
|
62
|
+
DuoScrollGradient,
|
|
63
|
+
} from '../Application/Components/DuoGlassBackground';
|
|
64
|
+
import { DuoQuickReturnHeader } from '../Application/Components/DuoQuickReturnHeader';
|
|
65
|
+
import { useDuoTabBarInset } from '../Application/BottomTab/DuoTabBar';
|
|
56
66
|
|
|
57
67
|
export interface ScreenProps extends ViewProps {
|
|
58
68
|
/**
|
|
@@ -118,7 +128,8 @@ export interface ScreenProps extends ViewProps {
|
|
|
118
128
|
layoutOffset?: -8 | -24 | -56 | number;
|
|
119
129
|
|
|
120
130
|
/**
|
|
121
|
-
* Optional. Width of the right header.
|
|
131
|
+
* Optional. Width of the right header. Defaults to the toolkit width (73), or 0 when
|
|
132
|
+
* iPhone Duo floats the toolkit into its side bar.
|
|
122
133
|
*/
|
|
123
134
|
headerRightWidth?: 0 | 73 | 110 | number;
|
|
124
135
|
|
|
@@ -187,7 +198,7 @@ const Screen = forwardRef(
|
|
|
187
198
|
footerComponent: Footer,
|
|
188
199
|
marginFooter = true,
|
|
189
200
|
layoutOffset = -56,
|
|
190
|
-
headerRightWidth
|
|
201
|
+
headerRightWidth,
|
|
191
202
|
backgroundColor,
|
|
192
203
|
headerType = 'default',
|
|
193
204
|
floatingButtonProps,
|
|
@@ -204,8 +215,8 @@ const Screen = forwardRef(
|
|
|
204
215
|
ref: any,
|
|
205
216
|
) => {
|
|
206
217
|
const screenRef = useRef<View | ScrollView>(null);
|
|
207
|
-
const
|
|
208
|
-
const { theme
|
|
218
|
+
const layout = useScreenLayout();
|
|
219
|
+
const { theme } = useContext(ApplicationContext);
|
|
209
220
|
const screen: any = useContext(ScreenContext);
|
|
210
221
|
const insets = useSafeAreaInsets();
|
|
211
222
|
const frame = useSafeAreaFrame();
|
|
@@ -245,15 +256,66 @@ const Screen = forwardRef(
|
|
|
245
256
|
}, [customAnimatedValue, internalShared]);
|
|
246
257
|
|
|
247
258
|
const currentTint = useRef<string | undefined>(undefined);
|
|
248
|
-
|
|
259
|
+
|
|
249
260
|
const isTab = !!screen?.bottomTab;
|
|
261
|
+
// Duo floating tab bar overlays the tab content instead of taking layout space
|
|
262
|
+
const duoTabInset = useDuoTabBarInset();
|
|
250
263
|
|
|
251
264
|
let handleScroll;
|
|
252
265
|
let Component: any = View;
|
|
253
266
|
|
|
254
|
-
const bottomInset =
|
|
267
|
+
const bottomInset =
|
|
268
|
+
Platform.OS === 'ios' ? Math.min(insets.bottom, 21) : insets.bottom;
|
|
269
|
+
const hasSideBar = !!layout.sideBar;
|
|
270
|
+
// iPhone Duo: content scrolls under a glass header instead of starting below it
|
|
271
|
+
const useDuoGlass =
|
|
272
|
+
hasSideBar &&
|
|
273
|
+
(headerType === 'default' || headerType === 'extended') &&
|
|
274
|
+
!animatedHeader &&
|
|
275
|
+
!inputSearchProps;
|
|
276
|
+
|
|
277
|
+
// iPhone Duo: the header leaves with the content and returns on a reverse scroll
|
|
278
|
+
const useQuickReturn =
|
|
279
|
+
hasSideBar && scrollable && (useDuoGlass || !!animatedHeader);
|
|
280
|
+
const headerHide = useSharedValue(0);
|
|
281
|
+
const lastScrollY = useSharedValue(0);
|
|
282
|
+
|
|
283
|
+
useAnimatedReaction(
|
|
284
|
+
() => sharedValue.value,
|
|
285
|
+
y => {
|
|
286
|
+
const delta = y - lastScrollY.value;
|
|
287
|
+
lastScrollY.value = y;
|
|
288
|
+
if (!useQuickReturn || y <= 0) {
|
|
289
|
+
headerHide.value = 0;
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
headerHide.value = Math.min(
|
|
293
|
+
Math.max(headerHide.value + delta, 0),
|
|
294
|
+
heightHeader,
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
[useQuickReturn, heightHeader],
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const quickReturnOptions: StackNavigationOptions = useMemo(
|
|
301
|
+
() =>
|
|
302
|
+
useQuickReturn
|
|
303
|
+
? {
|
|
304
|
+
header: (props: any) => (
|
|
305
|
+
<DuoQuickReturnHeader {...props} offset={headerHide} />
|
|
306
|
+
),
|
|
307
|
+
}
|
|
308
|
+
: { header: undefined },
|
|
309
|
+
[useQuickReturn, headerHide],
|
|
310
|
+
);
|
|
311
|
+
|
|
255
312
|
let keyboardOffset = heightHeader - bottomInset;
|
|
256
|
-
if (
|
|
313
|
+
if (
|
|
314
|
+
headerType === 'extended' ||
|
|
315
|
+
animatedHeader ||
|
|
316
|
+
inputSearchProps ||
|
|
317
|
+
useDuoGlass
|
|
318
|
+
) {
|
|
257
319
|
keyboardOffset = -bottomInset;
|
|
258
320
|
}
|
|
259
321
|
|
|
@@ -280,9 +342,13 @@ const Screen = forwardRef(
|
|
|
280
342
|
|
|
281
343
|
case 'extended':
|
|
282
344
|
options = {
|
|
345
|
+
...quickReturnOptions,
|
|
283
346
|
headerShown: true,
|
|
284
347
|
headerTransparent: true,
|
|
285
|
-
headerBackground: () =>
|
|
348
|
+
headerBackground: () =>
|
|
349
|
+
hasSideBar ? (
|
|
350
|
+
<DuoGlassBackground animatedValue={sharedValue} />
|
|
351
|
+
) : null,
|
|
286
352
|
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
287
353
|
};
|
|
288
354
|
if (inputSearchProps) {
|
|
@@ -305,6 +371,19 @@ const Screen = forwardRef(
|
|
|
305
371
|
break;
|
|
306
372
|
|
|
307
373
|
default:
|
|
374
|
+
if (hasSideBar && !inputSearchProps) {
|
|
375
|
+
options = {
|
|
376
|
+
...quickReturnOptions,
|
|
377
|
+
headerTransparent: true,
|
|
378
|
+
headerTintColor: Colors.black_17,
|
|
379
|
+
headerShown: true,
|
|
380
|
+
headerBackground: () => (
|
|
381
|
+
<DuoGlassBackground animatedValue={sharedValue} />
|
|
382
|
+
),
|
|
383
|
+
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
384
|
+
};
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
308
387
|
options = {
|
|
309
388
|
headerTransparent: false,
|
|
310
389
|
headerTintColor: Colors.black_17,
|
|
@@ -339,7 +418,7 @@ const Screen = forwardRef(
|
|
|
339
418
|
}
|
|
340
419
|
}
|
|
341
420
|
|
|
342
|
-
navigation?.instance?.setOptions(options);
|
|
421
|
+
navigation?.instance?.setOptions({ header: undefined, ...options });
|
|
343
422
|
},
|
|
344
423
|
[
|
|
345
424
|
gradientColor,
|
|
@@ -348,6 +427,8 @@ const Screen = forwardRef(
|
|
|
348
427
|
navigation?.instance,
|
|
349
428
|
sharedValue,
|
|
350
429
|
useShadowHeader,
|
|
430
|
+
hasSideBar,
|
|
431
|
+
quickReturnOptions,
|
|
351
432
|
],
|
|
352
433
|
);
|
|
353
434
|
|
|
@@ -363,18 +444,26 @@ const Screen = forwardRef(
|
|
|
363
444
|
}
|
|
364
445
|
|
|
365
446
|
options = {
|
|
447
|
+
...quickReturnOptions,
|
|
366
448
|
headerTintColor: currentTint.current ?? Colors.black_17,
|
|
367
449
|
headerTransparent: true,
|
|
368
|
-
headerBackground: (props: any) =>
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
450
|
+
headerBackground: (props: any) =>
|
|
451
|
+
hasSideBar ? (
|
|
452
|
+
// glass shows once the banner has scrolled under the header
|
|
453
|
+
<DuoGlassBackground
|
|
454
|
+
animatedValue={sharedValue}
|
|
455
|
+
fadeStart={Math.max(210 + layoutOffset - heightHeader, 0)}
|
|
456
|
+
/>
|
|
457
|
+
) : (
|
|
458
|
+
<HeaderBackground
|
|
459
|
+
{...props}
|
|
460
|
+
animatedValue={sharedValue}
|
|
461
|
+
useGradient={false}
|
|
462
|
+
useShadowHeader={useShadowHeader}
|
|
463
|
+
headerBackground={headerBackground}
|
|
464
|
+
gradientColor={gradientColor}
|
|
465
|
+
/>
|
|
466
|
+
),
|
|
378
467
|
headerTitle: (props: any) => {
|
|
379
468
|
return <HeaderTitle {...props} />;
|
|
380
469
|
},
|
|
@@ -395,6 +484,10 @@ const Screen = forwardRef(
|
|
|
395
484
|
navigation?.instance,
|
|
396
485
|
sharedValue,
|
|
397
486
|
useShadowHeader,
|
|
487
|
+
hasSideBar,
|
|
488
|
+
layoutOffset,
|
|
489
|
+
heightHeader,
|
|
490
|
+
quickReturnOptions,
|
|
398
491
|
],
|
|
399
492
|
);
|
|
400
493
|
|
|
@@ -418,14 +511,20 @@ const Screen = forwardRef(
|
|
|
418
511
|
),
|
|
419
512
|
};
|
|
420
513
|
|
|
421
|
-
navigation?.instance?.setOptions(options);
|
|
514
|
+
navigation?.instance?.setOptions({ header: undefined, ...options });
|
|
422
515
|
}, [navigation?.instance, sharedValue]);
|
|
423
516
|
|
|
424
517
|
/**
|
|
425
518
|
* export search header
|
|
426
519
|
*/
|
|
427
520
|
const setSearchHeader = (params: SearchHeaderProps) => {
|
|
428
|
-
|
|
521
|
+
let searchWidth = layout.width - 24;
|
|
522
|
+
let searchLeft = Spacing.M;
|
|
523
|
+
if (layout.sideBar) {
|
|
524
|
+
// back floats in the side bar: the search spans the content width
|
|
525
|
+
searchWidth = layout.contentWidth - Spacing.M * 2;
|
|
526
|
+
searchLeft = Spacing.M - getHeaderMargin(layout.width);
|
|
527
|
+
}
|
|
429
528
|
const options: StackNavigationOptions = {
|
|
430
529
|
headerRight: undefined,
|
|
431
530
|
headerTitleContainerStyle: {
|
|
@@ -437,10 +536,10 @@ const Screen = forwardRef(
|
|
|
437
536
|
marginHorizontal: 0,
|
|
438
537
|
marginVertical: 0,
|
|
439
538
|
margin: 0,
|
|
440
|
-
left:
|
|
539
|
+
left: searchLeft,
|
|
441
540
|
},
|
|
442
541
|
headerLeft: (props: any) =>
|
|
443
|
-
params?.hiddenBack ? null : <HeaderLeft {...props} />,
|
|
542
|
+
params?.hiddenBack ? null : <HeaderLeft {...props} floating />,
|
|
444
543
|
headerTitle: () => (
|
|
445
544
|
<SearchHeader {...params} animatedValue={sharedValue} />
|
|
446
545
|
),
|
|
@@ -540,8 +639,36 @@ const Screen = forwardRef(
|
|
|
540
639
|
* handle scroll end
|
|
541
640
|
* @param e
|
|
542
641
|
*/
|
|
642
|
+
/**
|
|
643
|
+
* a half-shown quick return header settles fully in or out
|
|
644
|
+
*/
|
|
645
|
+
const snapQuickReturnHeader = (offsetY: number) => {
|
|
646
|
+
const hide = headerHide.value;
|
|
647
|
+
// above heightHeader the header still sits on the content
|
|
648
|
+
if (
|
|
649
|
+
!useQuickReturn ||
|
|
650
|
+
offsetY < heightHeader ||
|
|
651
|
+
hide <= 0 ||
|
|
652
|
+
hide >= heightHeader
|
|
653
|
+
) {
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
headerHide.value = withTiming(
|
|
657
|
+
hide > heightHeader / 2 ? heightHeader : 0,
|
|
658
|
+
{ duration: 200 },
|
|
659
|
+
);
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
const handleMomentumScrollEnd = (
|
|
663
|
+
e: NativeSyntheticEvent<NativeScrollEvent>,
|
|
664
|
+
) => {
|
|
665
|
+
snapQuickReturnHeader(e.nativeEvent.contentOffset.y);
|
|
666
|
+
scrollViewProps?.onMomentumScrollEnd?.(e);
|
|
667
|
+
};
|
|
668
|
+
|
|
543
669
|
const handleScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
544
670
|
const offsetY = e.nativeEvent.contentOffset.y;
|
|
671
|
+
snapQuickReturnHeader(offsetY);
|
|
545
672
|
if (inputSearchProps && offsetY < 100 && offsetY > 0) {
|
|
546
673
|
Animated.timing(animatedValue.current, {
|
|
547
674
|
toValue: 0,
|
|
@@ -591,6 +718,8 @@ const Screen = forwardRef(
|
|
|
591
718
|
key={`ScreenItem${index}`}
|
|
592
719
|
style={{
|
|
593
720
|
marginTop: space,
|
|
721
|
+
marginLeft: layout.insetLeft,
|
|
722
|
+
marginRight: layout.insetRight,
|
|
594
723
|
flex: item.props?.expanded ? 1 : undefined,
|
|
595
724
|
}}
|
|
596
725
|
onLayout={item.props?.onLayout}
|
|
@@ -611,6 +740,8 @@ const Screen = forwardRef(
|
|
|
611
740
|
key={`ScreenItem`}
|
|
612
741
|
style={{
|
|
613
742
|
marginTop: space,
|
|
743
|
+
marginLeft: layout.insetLeft,
|
|
744
|
+
marginRight: layout.insetRight,
|
|
614
745
|
flex: item?.props?.expanded ? 1 : undefined,
|
|
615
746
|
}}
|
|
616
747
|
onLayout={item?.props?.onLayout}
|
|
@@ -637,6 +768,15 @@ const Screen = forwardRef(
|
|
|
637
768
|
return newHeight;
|
|
638
769
|
};
|
|
639
770
|
|
|
771
|
+
// without the grid, the content container keeps clear of the horizontal insets.
|
|
772
|
+
// Only set when there are insets, so a caller's paddingHorizontal is never overridden.
|
|
773
|
+
const hasContentInset = layout.insetLeft > 0 || layout.insetRight > 0;
|
|
774
|
+
const contentInsetStyle = !useGridLayout &&
|
|
775
|
+
hasContentInset && {
|
|
776
|
+
paddingLeft: layout.insetLeft,
|
|
777
|
+
paddingRight: layout.insetRight,
|
|
778
|
+
};
|
|
779
|
+
|
|
640
780
|
return (
|
|
641
781
|
<View
|
|
642
782
|
style={[
|
|
@@ -649,21 +789,36 @@ const Screen = forwardRef(
|
|
|
649
789
|
},
|
|
650
790
|
]}
|
|
651
791
|
>
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
792
|
+
{useDuoGlass ? (
|
|
793
|
+
<DuoScrollGradient
|
|
794
|
+
animatedValue={sharedValue}
|
|
795
|
+
gradientColor={gradientColor}
|
|
796
|
+
headerBackground={headerBackground}
|
|
797
|
+
heightHeader={heightHeader}
|
|
798
|
+
extended={headerType === 'extended'}
|
|
799
|
+
followScroll={useQuickReturn}
|
|
800
|
+
/>
|
|
801
|
+
) : (
|
|
802
|
+
<HeaderExtendHeader
|
|
803
|
+
headerType={headerType}
|
|
804
|
+
heightHeader={heightHeader}
|
|
805
|
+
headerRightWidth={headerRightWidth}
|
|
806
|
+
animatedValue={sharedValue}
|
|
807
|
+
inputSearchProps={inputSearchProps}
|
|
808
|
+
navigation={navigation}
|
|
809
|
+
inputSearchRef={inputSearchRef}
|
|
810
|
+
useShadowHeader={useShadowHeader}
|
|
811
|
+
gradientColor={gradientColor}
|
|
812
|
+
headerBackground={headerBackground}
|
|
813
|
+
/>
|
|
814
|
+
)}
|
|
664
815
|
|
|
665
816
|
<KeyboardAvoidingView
|
|
666
|
-
style={
|
|
817
|
+
style={[
|
|
818
|
+
Styles.flex,
|
|
819
|
+
useDuoGlass &&
|
|
820
|
+
(!scrollable || !!Header) && { paddingTop: heightHeader },
|
|
821
|
+
]}
|
|
667
822
|
enabled={enableKeyboardAvoidingView}
|
|
668
823
|
keyboardVerticalOffset={keyboardVerticalOffset ?? keyboardOffset}
|
|
669
824
|
behavior={Platform.select({
|
|
@@ -679,10 +834,24 @@ const Screen = forwardRef(
|
|
|
679
834
|
showsVerticalScrollIndicator={false}
|
|
680
835
|
onScroll={handleScroll}
|
|
681
836
|
onScrollEndDrag={handleScrollEnd}
|
|
837
|
+
onMomentumScrollEnd={handleMomentumScrollEnd}
|
|
682
838
|
scrollEventThrottle={16}
|
|
683
|
-
style={[
|
|
839
|
+
style={[
|
|
840
|
+
Styles.flex,
|
|
841
|
+
!scrollable && contentInsetStyle,
|
|
842
|
+
!scrollable &&
|
|
843
|
+
!Footer &&
|
|
844
|
+
isTab &&
|
|
845
|
+
!!duoTabInset && { paddingBottom: duoTabInset },
|
|
846
|
+
]}
|
|
684
847
|
contentContainerStyle={[
|
|
685
848
|
scrollable && !Footer && !isTab && { paddingBottom: bottomInset },
|
|
849
|
+
scrollable &&
|
|
850
|
+
!Footer &&
|
|
851
|
+
isTab &&
|
|
852
|
+
!!duoTabInset && { paddingBottom: duoTabInset },
|
|
853
|
+
scrollable && contentInsetStyle,
|
|
854
|
+
useDuoGlass && !Header && { paddingTop: heightHeader },
|
|
686
855
|
scrollViewProps?.contentContainerStyle,
|
|
687
856
|
]}
|
|
688
857
|
>
|
|
@@ -692,28 +861,51 @@ const Screen = forwardRef(
|
|
|
692
861
|
</Component>
|
|
693
862
|
|
|
694
863
|
{floatingButtonProps && (
|
|
695
|
-
<View
|
|
864
|
+
<View
|
|
865
|
+
style={{
|
|
866
|
+
marginLeft: layout.insetLeft,
|
|
867
|
+
marginRight: layout.insetRight,
|
|
868
|
+
}}
|
|
869
|
+
>
|
|
696
870
|
<FloatingButton
|
|
697
871
|
{...floatingButtonProps}
|
|
698
872
|
animatedValue={sharedValue}
|
|
699
|
-
bottom={
|
|
873
|
+
bottom={
|
|
874
|
+
Footer || isTab
|
|
875
|
+
? 12 + (Footer ? 0 : duoTabInset)
|
|
876
|
+
: bottomInset + Spacing.S
|
|
877
|
+
}
|
|
700
878
|
/>
|
|
701
879
|
</View>
|
|
702
880
|
)}
|
|
703
881
|
|
|
704
882
|
{Footer && (
|
|
883
|
+
// with side insets, the clip keeps the shadow off the side bar, only the top one shows
|
|
705
884
|
<View
|
|
885
|
+
pointerEvents={'box-none'}
|
|
706
886
|
style={[
|
|
707
|
-
styles.
|
|
887
|
+
hasContentInset && styles.footerClip,
|
|
708
888
|
{
|
|
709
|
-
|
|
710
|
-
|
|
889
|
+
marginLeft: layout.insetLeft,
|
|
890
|
+
marginRight: layout.insetRight,
|
|
711
891
|
},
|
|
712
892
|
]}
|
|
713
893
|
>
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
894
|
+
<View
|
|
895
|
+
style={[
|
|
896
|
+
styles.shadow,
|
|
897
|
+
{
|
|
898
|
+
paddingBottom:
|
|
899
|
+
(isTab && duoTabInset ? duoTabInset : bottomInset) +
|
|
900
|
+
Spacing.S,
|
|
901
|
+
backgroundColor: theme.colors.background.surface,
|
|
902
|
+
},
|
|
903
|
+
]}
|
|
904
|
+
>
|
|
905
|
+
{/* The footer inset is a caller decision, not a platform one — a footer
|
|
906
|
+
that carries its own horizontal padding passes `marginFooter={false}`. */}
|
|
907
|
+
<Section useMargin={marginFooter}>{Footer}</Section>
|
|
908
|
+
</View>
|
|
717
909
|
</View>
|
|
718
910
|
)}
|
|
719
911
|
</KeyboardAvoidingView>
|
package/Layout/Section.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
import { useGridSystem } from './utils';
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, ViewProps } from 'react-native';
|
|
3
|
+
import { useGridSystem, useScreenLayout } from './utils';
|
|
4
4
|
import { GridContextProps } from './types';
|
|
5
5
|
import { GridContext } from './index';
|
|
6
|
-
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
7
6
|
import styles from './styles';
|
|
8
7
|
import { Image } from '../Image';
|
|
9
8
|
import { Spacing } from '../Consts';
|
|
@@ -34,18 +33,15 @@ const Section: React.FC<SectionProps> = ({
|
|
|
34
33
|
style,
|
|
35
34
|
...props
|
|
36
35
|
}) => {
|
|
37
|
-
const { showGrid } = useContext(ApplicationContext);
|
|
38
36
|
const { numberOfColumns } = useGridSystem();
|
|
37
|
+
const { contentWidth } = useScreenLayout();
|
|
39
38
|
|
|
40
39
|
const gutterSize = 12;
|
|
41
40
|
let margin = 0;
|
|
42
41
|
if (useMargin) {
|
|
43
42
|
margin = 12;
|
|
44
43
|
}
|
|
45
|
-
|
|
46
|
-
if (useMargin) {
|
|
47
|
-
widthSection = widthSection - margin * 2;
|
|
48
|
-
}
|
|
44
|
+
const widthSection = contentWidth - margin * 2;
|
|
49
45
|
|
|
50
46
|
const sizePerSpan =
|
|
51
47
|
(widthSection - gutterSize * (numberOfColumns - 1)) / numberOfColumns -
|
|
@@ -60,13 +56,6 @@ const Section: React.FC<SectionProps> = ({
|
|
|
60
56
|
},
|
|
61
57
|
};
|
|
62
58
|
|
|
63
|
-
/**
|
|
64
|
-
* render overlay only dev mode
|
|
65
|
-
*/
|
|
66
|
-
const renderOverlay = () => {
|
|
67
|
-
return <View pointerEvents={'none'} style={styles.boxGridSection} />;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
59
|
return (
|
|
71
60
|
<GridContext.Provider value={gridContext}>
|
|
72
61
|
<View
|
|
@@ -90,9 +79,7 @@ const Section: React.FC<SectionProps> = ({
|
|
|
90
79
|
style={styles.imageBackground}
|
|
91
80
|
/>
|
|
92
81
|
)}
|
|
93
|
-
{/* Render only allowed children as valid React elements */}
|
|
94
82
|
{children}
|
|
95
|
-
{showGrid && renderOverlay()}
|
|
96
83
|
</View>
|
|
97
84
|
</GridContext.Provider>
|
|
98
85
|
);
|
package/Layout/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Card from './Card';
|
|
2
2
|
import Section from './Section';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { useScreenLayout, validateChildren } from './utils';
|
|
4
|
+
import type { ScreenLayout, SideBarEdge, SideBarLayout } from './utils';
|
|
5
5
|
import { createContext } from 'react';
|
|
6
6
|
import { GridContextProps } from './types';
|
|
7
7
|
import Item from './Item';
|
|
@@ -18,14 +18,14 @@ const GridContext = createContext<GridContextProps>({
|
|
|
18
18
|
getSizeSpan: () => 0,
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
export type { ScreenProps };
|
|
21
|
+
export type { ScreenProps, ScreenLayout, SideBarEdge, SideBarLayout };
|
|
22
22
|
|
|
23
23
|
export {
|
|
24
24
|
GridContext,
|
|
25
25
|
Card,
|
|
26
26
|
Section,
|
|
27
|
-
GridSystem,
|
|
28
27
|
validateChildren,
|
|
28
|
+
useScreenLayout,
|
|
29
29
|
Item,
|
|
30
30
|
ItemList,
|
|
31
31
|
ItemSectionList,
|
package/Layout/styles.ts
CHANGED