@momo-kits/foundation 0.167.1-duo.1 → 0.167.1-duo.13
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/DuoBarCompression.tsx +135 -0
- package/Application/BottomTab/DuoTabBar.tsx +462 -0
- package/Application/BottomTab/index.tsx +150 -134
- package/Application/Components/DuoGlassBackground.tsx +179 -0
- package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
- package/Application/Components/HeaderExtendHeader.tsx +75 -28
- package/Application/Components/HeaderLeft.tsx +38 -0
- package/Application/Components/HeaderRight.tsx +142 -9
- package/Application/Components/HeaderTitle.tsx +67 -17
- package/Application/Components/OptionalGlassView.ts +11 -0
- package/Application/Components/SearchHeader.tsx +22 -15
- package/Application/Components/SideBarButton.tsx +139 -0
- package/Application/ModalScreen.tsx +16 -2
- package/Application/NavigationContainer.tsx +36 -45
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/WidgetContainer.tsx +9 -7
- 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 +5 -6
- 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 +244 -48
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +5 -0
- package/Layout/utils.ts +465 -5
- package/Popup/PopupNotify.tsx +33 -22
- package/Popup/PopupPromotion.tsx +20 -8
- package/Popup/utils.ts +32 -0
- package/Text/index.tsx +2 -11
- package/Text/utils.ts +1 -2
- package/package.json +4 -3
- package/Consts/designSystemFont.ts +0 -38
- 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,24 @@ 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
|
+
}
|
|
528
|
+
if (layout.statusBarClearance) {
|
|
529
|
+
searchWidth -=
|
|
530
|
+
layout.statusBarClearance.left + layout.statusBarClearance.right;
|
|
531
|
+
}
|
|
429
532
|
const options: StackNavigationOptions = {
|
|
430
533
|
headerRight: undefined,
|
|
431
534
|
headerTitleContainerStyle: {
|
|
@@ -437,10 +540,10 @@ const Screen = forwardRef(
|
|
|
437
540
|
marginHorizontal: 0,
|
|
438
541
|
marginVertical: 0,
|
|
439
542
|
margin: 0,
|
|
440
|
-
left:
|
|
543
|
+
left: searchLeft,
|
|
441
544
|
},
|
|
442
545
|
headerLeft: (props: any) =>
|
|
443
|
-
params?.hiddenBack ? null : <HeaderLeft {...props} />,
|
|
546
|
+
params?.hiddenBack ? null : <HeaderLeft {...props} floating />,
|
|
444
547
|
headerTitle: () => (
|
|
445
548
|
<SearchHeader {...params} animatedValue={sharedValue} />
|
|
446
549
|
),
|
|
@@ -540,8 +643,36 @@ const Screen = forwardRef(
|
|
|
540
643
|
* handle scroll end
|
|
541
644
|
* @param e
|
|
542
645
|
*/
|
|
646
|
+
/**
|
|
647
|
+
* a half-shown quick return header settles fully in or out
|
|
648
|
+
*/
|
|
649
|
+
const snapQuickReturnHeader = (offsetY: number) => {
|
|
650
|
+
const hide = headerHide.value;
|
|
651
|
+
// above heightHeader the header still sits on the content
|
|
652
|
+
if (
|
|
653
|
+
!useQuickReturn ||
|
|
654
|
+
offsetY < heightHeader ||
|
|
655
|
+
hide <= 0 ||
|
|
656
|
+
hide >= heightHeader
|
|
657
|
+
) {
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
headerHide.value = withTiming(
|
|
661
|
+
hide > heightHeader / 2 ? heightHeader : 0,
|
|
662
|
+
{ duration: 200 },
|
|
663
|
+
);
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
const handleMomentumScrollEnd = (
|
|
667
|
+
e: NativeSyntheticEvent<NativeScrollEvent>,
|
|
668
|
+
) => {
|
|
669
|
+
snapQuickReturnHeader(e.nativeEvent.contentOffset.y);
|
|
670
|
+
scrollViewProps?.onMomentumScrollEnd?.(e);
|
|
671
|
+
};
|
|
672
|
+
|
|
543
673
|
const handleScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
544
674
|
const offsetY = e.nativeEvent.contentOffset.y;
|
|
675
|
+
snapQuickReturnHeader(offsetY);
|
|
545
676
|
if (inputSearchProps && offsetY < 100 && offsetY > 0) {
|
|
546
677
|
Animated.timing(animatedValue.current, {
|
|
547
678
|
toValue: 0,
|
|
@@ -591,6 +722,8 @@ const Screen = forwardRef(
|
|
|
591
722
|
key={`ScreenItem${index}`}
|
|
592
723
|
style={{
|
|
593
724
|
marginTop: space,
|
|
725
|
+
marginLeft: layout.insetLeft,
|
|
726
|
+
marginRight: layout.insetRight,
|
|
594
727
|
flex: item.props?.expanded ? 1 : undefined,
|
|
595
728
|
}}
|
|
596
729
|
onLayout={item.props?.onLayout}
|
|
@@ -611,6 +744,8 @@ const Screen = forwardRef(
|
|
|
611
744
|
key={`ScreenItem`}
|
|
612
745
|
style={{
|
|
613
746
|
marginTop: space,
|
|
747
|
+
marginLeft: layout.insetLeft,
|
|
748
|
+
marginRight: layout.insetRight,
|
|
614
749
|
flex: item?.props?.expanded ? 1 : undefined,
|
|
615
750
|
}}
|
|
616
751
|
onLayout={item?.props?.onLayout}
|
|
@@ -637,6 +772,15 @@ const Screen = forwardRef(
|
|
|
637
772
|
return newHeight;
|
|
638
773
|
};
|
|
639
774
|
|
|
775
|
+
// without the grid, the content container keeps clear of the horizontal insets.
|
|
776
|
+
// Only set when there are insets, so a caller's paddingHorizontal is never overridden.
|
|
777
|
+
const hasContentInset = layout.insetLeft > 0 || layout.insetRight > 0;
|
|
778
|
+
const contentInsetStyle = !useGridLayout &&
|
|
779
|
+
hasContentInset && {
|
|
780
|
+
paddingLeft: layout.insetLeft,
|
|
781
|
+
paddingRight: layout.insetRight,
|
|
782
|
+
};
|
|
783
|
+
|
|
640
784
|
return (
|
|
641
785
|
<View
|
|
642
786
|
style={[
|
|
@@ -649,21 +793,36 @@ const Screen = forwardRef(
|
|
|
649
793
|
},
|
|
650
794
|
]}
|
|
651
795
|
>
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
796
|
+
{useDuoGlass ? (
|
|
797
|
+
<DuoScrollGradient
|
|
798
|
+
animatedValue={sharedValue}
|
|
799
|
+
gradientColor={gradientColor}
|
|
800
|
+
headerBackground={headerBackground}
|
|
801
|
+
heightHeader={heightHeader}
|
|
802
|
+
extended={headerType === 'extended'}
|
|
803
|
+
followScroll={useQuickReturn}
|
|
804
|
+
/>
|
|
805
|
+
) : (
|
|
806
|
+
<HeaderExtendHeader
|
|
807
|
+
headerType={headerType}
|
|
808
|
+
heightHeader={heightHeader}
|
|
809
|
+
headerRightWidth={headerRightWidth}
|
|
810
|
+
animatedValue={sharedValue}
|
|
811
|
+
inputSearchProps={inputSearchProps}
|
|
812
|
+
navigation={navigation}
|
|
813
|
+
inputSearchRef={inputSearchRef}
|
|
814
|
+
useShadowHeader={useShadowHeader}
|
|
815
|
+
gradientColor={gradientColor}
|
|
816
|
+
headerBackground={headerBackground}
|
|
817
|
+
/>
|
|
818
|
+
)}
|
|
664
819
|
|
|
665
820
|
<KeyboardAvoidingView
|
|
666
|
-
style={
|
|
821
|
+
style={[
|
|
822
|
+
Styles.flex,
|
|
823
|
+
useDuoGlass &&
|
|
824
|
+
(!scrollable || !!Header) && { paddingTop: heightHeader },
|
|
825
|
+
]}
|
|
667
826
|
enabled={enableKeyboardAvoidingView}
|
|
668
827
|
keyboardVerticalOffset={keyboardVerticalOffset ?? keyboardOffset}
|
|
669
828
|
behavior={Platform.select({
|
|
@@ -679,10 +838,24 @@ const Screen = forwardRef(
|
|
|
679
838
|
showsVerticalScrollIndicator={false}
|
|
680
839
|
onScroll={handleScroll}
|
|
681
840
|
onScrollEndDrag={handleScrollEnd}
|
|
841
|
+
onMomentumScrollEnd={handleMomentumScrollEnd}
|
|
682
842
|
scrollEventThrottle={16}
|
|
683
|
-
style={[
|
|
843
|
+
style={[
|
|
844
|
+
Styles.flex,
|
|
845
|
+
!scrollable && contentInsetStyle,
|
|
846
|
+
!scrollable &&
|
|
847
|
+
!Footer &&
|
|
848
|
+
isTab &&
|
|
849
|
+
!!duoTabInset && { paddingBottom: duoTabInset },
|
|
850
|
+
]}
|
|
684
851
|
contentContainerStyle={[
|
|
685
852
|
scrollable && !Footer && !isTab && { paddingBottom: bottomInset },
|
|
853
|
+
scrollable &&
|
|
854
|
+
!Footer &&
|
|
855
|
+
isTab &&
|
|
856
|
+
!!duoTabInset && { paddingBottom: duoTabInset },
|
|
857
|
+
scrollable && contentInsetStyle,
|
|
858
|
+
useDuoGlass && !Header && { paddingTop: heightHeader },
|
|
686
859
|
scrollViewProps?.contentContainerStyle,
|
|
687
860
|
]}
|
|
688
861
|
>
|
|
@@ -692,28 +865,51 @@ const Screen = forwardRef(
|
|
|
692
865
|
</Component>
|
|
693
866
|
|
|
694
867
|
{floatingButtonProps && (
|
|
695
|
-
<View
|
|
868
|
+
<View
|
|
869
|
+
style={{
|
|
870
|
+
marginLeft: layout.insetLeft,
|
|
871
|
+
marginRight: layout.insetRight,
|
|
872
|
+
}}
|
|
873
|
+
>
|
|
696
874
|
<FloatingButton
|
|
697
875
|
{...floatingButtonProps}
|
|
698
876
|
animatedValue={sharedValue}
|
|
699
|
-
bottom={
|
|
877
|
+
bottom={
|
|
878
|
+
Footer || isTab
|
|
879
|
+
? 12 + (Footer ? 0 : duoTabInset)
|
|
880
|
+
: bottomInset + Spacing.S
|
|
881
|
+
}
|
|
700
882
|
/>
|
|
701
883
|
</View>
|
|
702
884
|
)}
|
|
703
885
|
|
|
704
886
|
{Footer && (
|
|
887
|
+
// with side insets, the clip keeps the shadow off the side bar, only the top one shows
|
|
705
888
|
<View
|
|
889
|
+
pointerEvents={'box-none'}
|
|
706
890
|
style={[
|
|
707
|
-
styles.
|
|
891
|
+
hasContentInset && styles.footerClip,
|
|
708
892
|
{
|
|
709
|
-
|
|
710
|
-
|
|
893
|
+
marginLeft: layout.insetLeft,
|
|
894
|
+
marginRight: layout.insetRight,
|
|
711
895
|
},
|
|
712
896
|
]}
|
|
713
897
|
>
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
898
|
+
<View
|
|
899
|
+
style={[
|
|
900
|
+
styles.shadow,
|
|
901
|
+
{
|
|
902
|
+
paddingBottom:
|
|
903
|
+
(isTab && duoTabInset ? duoTabInset : bottomInset) +
|
|
904
|
+
Spacing.S,
|
|
905
|
+
backgroundColor: theme.colors.background.surface,
|
|
906
|
+
},
|
|
907
|
+
]}
|
|
908
|
+
>
|
|
909
|
+
{/* The footer inset is a caller decision, not a platform one — a footer
|
|
910
|
+
that carries its own horizontal padding passes `marginFooter={false}`. */}
|
|
911
|
+
<Section useMargin={marginFooter}>{Footer}</Section>
|
|
912
|
+
</View>
|
|
717
913
|
</View>
|
|
718
914
|
)}
|
|
719
915
|
</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