@momo-kits/foundation 0.167.1-duotest.3 → 0.167.1-duotest.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -75,13 +75,15 @@ const StackScreen: React.FC<any> = props => {
75
75
  */
76
76
  const canAutoLayout = Platform.OS === 'ios' && !bottomTab;
77
77
  const Observer: React.ComponentType<any> = ScrollObserverView ?? View;
78
- const headerClaimed = useRef(false);
78
+ // screens that drive the header themselves: a root <Screen>, a BottomTab
79
+ const [headerClaims] = useState(() => new Set<object>());
80
+ const contentRef = useRef<View>(null);
79
81
  const [autoHeader, setAutoHeader] = useState(false);
80
82
  const syncHeader = useCallback(() => {
81
83
  setAutoHeader(
82
- canAutoLayout && layout.isIPhoneDuo && !headerClaimed.current,
84
+ canAutoLayout && layout.isIPhoneDuo && headerClaims.size === 0,
83
85
  );
84
- }, [canAutoLayout, layout.isIPhoneDuo]);
86
+ }, [canAutoLayout, layout.isIPhoneDuo, headerClaims]);
85
87
  // parent effects run after the screen's, so a claim made on mount is already in
86
88
  useEffect(syncHeader, [syncHeader]);
87
89
  const headerScroll = useHeaderScrollState({ navigation }, autoHeader);
@@ -441,10 +443,16 @@ const StackScreen: React.FC<any> = props => {
441
443
  onSetParams: (item: ScreenTrackingParams) => {
442
444
  tracking.current.params = item;
443
445
  },
444
- claimHeader: () => {
445
- headerClaimed.current = true;
446
+ claimHeader: (owner: object = headerClaims) => {
447
+ headerClaims.add(owner);
448
+ },
449
+ releaseHeader: (owner: object) => {
450
+ if (headerClaims.delete(owner)) {
451
+ syncHeader();
452
+ }
446
453
  },
447
454
  syncHeader,
455
+ contentRef,
448
456
  }}
449
457
  >
450
458
  <TooltipPortalProvider>
@@ -458,7 +466,9 @@ const StackScreen: React.FC<any> = props => {
458
466
  >
459
467
  {headerScroll.background}
460
468
  <Animated.View style={[styles.flex, headerScroll.contentStyle]}>
461
- <Component heightHeader={heightHeader} {...data} />
469
+ <View ref={contentRef} collapsable={false} style={styles.flex}>
470
+ <Component heightHeader={heightHeader} {...data} />
471
+ </View>
462
472
  </Animated.View>
463
473
  </Observer>
464
474
  ) : (
package/Layout/Screen.tsx CHANGED
@@ -10,6 +10,7 @@ import React, {
10
10
  useEffect,
11
11
  useImperativeHandle,
12
12
  useRef,
13
+ useState,
13
14
  } from 'react';
14
15
  import {
15
16
  Animated,
@@ -213,9 +214,28 @@ const Screen = forwardRef(
213
214
  ref: any,
214
215
  ) => {
215
216
  const screenRef = useRef<View | ScrollView>(null);
216
- const layout = useScreenLayout();
217
+ const rootRef = useRef<View>(null);
217
218
  const { theme } = useContext(ApplicationContext);
218
219
  const screen: any = useContext(ScreenContext);
220
+ const screenLayout = useScreenLayout();
221
+
222
+ /**
223
+ * iPhone Duo: a Screen nested in the route's content (e.g. a TabView page) is not
224
+ * the route's screen. The route keeps clear of the side bar and drives the header,
225
+ * the nested Screen lays out as plain content.
226
+ */
227
+ const [headerOwner] = useState(() => ({}));
228
+ const nested = useRef(false);
229
+ const [isNested, setIsNested] = useState(false);
230
+ const layout = isNested
231
+ ? {
232
+ ...screenLayout,
233
+ insetLeft: 0,
234
+ insetRight: 0,
235
+ sideBar: undefined,
236
+ statusBarClearance: undefined,
237
+ }
238
+ : screenLayout;
219
239
  const insets = useSafeAreaInsets();
220
240
  const frame = useSafeAreaFrame();
221
241
  const heightHeader = useHeaderHeight();
@@ -293,9 +313,30 @@ const Screen = forwardRef(
293
313
  */
294
314
  screen?.onSetParams?.(trackingParams);
295
315
  // the screen drives its header, the stack screen's scroll observer stays off
296
- screen?.claimHeader?.();
316
+ if (!nested.current) {
317
+ screen?.claimHeader?.(headerOwner);
318
+ }
297
319
  useEffect(() => {
320
+ // passive: the stack screen's content ref attaches after this screen's layout
321
+ const content = screen?.contentRef?.current;
322
+ if (!screenLayout.sideBar || !content || !rootRef.current) {
323
+ return;
324
+ }
325
+ rootRef.current.measureLayout(content, (x, y) => {
326
+ if (Math.abs(x) > 1 || Math.abs(y) > 1) {
327
+ nested.current = true;
328
+ setIsNested(true);
329
+ screen?.releaseHeader?.(headerOwner);
330
+ }
331
+ });
332
+ // eslint-disable-next-line react-hooks/exhaustive-deps
333
+ }, [!!screenLayout.sideBar]);
334
+ useEffect(() => {
335
+ if (!nested.current) {
336
+ screen?.claimHeader?.(headerOwner);
337
+ }
298
338
  screen?.syncHeader?.();
339
+ return () => screen?.releaseHeader?.(headerOwner);
299
340
  // eslint-disable-next-line react-hooks/exhaustive-deps
300
341
  }, []);
301
342
 
@@ -536,7 +577,9 @@ const Screen = forwardRef(
536
577
  StatusBar.setBarStyle(barStyle, true);
537
578
  });
538
579
 
539
- if (animatedHeader) {
580
+ if (nested.current) {
581
+ // the route drives the header
582
+ } else if (animatedHeader) {
540
583
  setAnimatedHeader(animatedHeader);
541
584
  } else if (inputSearchProps) {
542
585
  setAnimatedSearch();
@@ -556,6 +599,7 @@ const Screen = forwardRef(
556
599
  setAnimatedHeader,
557
600
  setAnimatedSearch,
558
601
  setHeaderType,
602
+ isNested,
559
603
  ]);
560
604
 
561
605
  /**
@@ -596,7 +640,7 @@ const Screen = forwardRef(
596
640
  if (offsetY > 50) {
597
641
  color = Colors.black_17;
598
642
  }
599
- if (color !== currentTint.current) {
643
+ if (!nested.current && color !== currentTint.current) {
600
644
  currentTint.current = color;
601
645
  navigation?.setOptions({
602
646
  headerTintColor: color,
@@ -734,6 +778,7 @@ const Screen = forwardRef(
734
778
 
735
779
  return (
736
780
  <View
781
+ ref={rootRef}
737
782
  style={[
738
783
  Styles.flex,
739
784
  {
@@ -754,18 +799,20 @@ const Screen = forwardRef(
754
799
  followScroll={useQuickReturn}
755
800
  />
756
801
  ) : (
757
- <HeaderExtendHeader
758
- headerType={headerType}
759
- heightHeader={heightHeader}
760
- headerRightWidth={headerRightWidth}
761
- animatedValue={sharedValue}
762
- inputSearchProps={inputSearchProps}
763
- navigation={navigation}
764
- inputSearchRef={inputSearchRef}
765
- useShadowHeader={useShadowHeader}
766
- gradientColor={gradientColor}
767
- headerBackground={headerBackground}
768
- />
802
+ !isNested && (
803
+ <HeaderExtendHeader
804
+ headerType={headerType}
805
+ heightHeader={heightHeader}
806
+ headerRightWidth={headerRightWidth}
807
+ animatedValue={sharedValue}
808
+ inputSearchProps={inputSearchProps}
809
+ navigation={navigation}
810
+ inputSearchRef={inputSearchRef}
811
+ useShadowHeader={useShadowHeader}
812
+ gradientColor={gradientColor}
813
+ headerBackground={headerBackground}
814
+ />
815
+ )
769
816
  )}
770
817
 
771
818
  <KeyboardAvoidingView
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.167.1-duotest.3",
3
+ "version": "0.167.1-duotest.4",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},