@react-navigation/elements 2.4.6 → 2.5.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.
@@ -33,6 +33,7 @@ export function SafeAreaProviderCompat({
33
33
  }) {
34
34
  const insets = React.useContext(SafeAreaInsetsContext);
35
35
  children = /*#__PURE__*/_jsx(FrameSizeProvider, {
36
+ initialFrame: initialMetrics.frame,
36
37
  children: children
37
38
  });
38
39
  if (insets) {
@@ -1 +1 @@
1
- {"version":3,"names":["React","Dimensions","Platform","StyleSheet","View","initialWindowMetrics","SafeAreaInsetsContext","SafeAreaProvider","FrameSizeProvider","jsx","_jsx","width","height","get","initialMetrics","OS","frame","x","y","insets","top","left","right","bottom","SafeAreaProviderCompat","children","style","useContext","styles","container","create","flex"],"sourceRoot":"../../src","sources":["SafeAreaProviderCompat.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SACEC,UAAU,EACVC,QAAQ,EAERC,UAAU,EACVC,IAAI,QAEC,cAAc;AACrB,SACEC,oBAAoB,EACpBC,qBAAqB,EACrBC,gBAAgB,QACX,gCAAgC;AAEvC,SAASC,iBAAiB,QAAQ,mBAAgB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAOnD,MAAM;EAAEC,KAAK,GAAG,CAAC;EAAEC,MAAM,GAAG;AAAE,CAAC,GAAGX,UAAU,CAACY,GAAG,CAAC,QAAQ,CAAC;;AAE1D;AACA;AACA;AACA,MAAMC,cAAc,GAClBZ,QAAQ,CAACa,EAAE,KAAK,KAAK,IAAIV,oBAAoB,IAAI,IAAI,GACjD;EACEW,KAAK,EAAE;IAAEC,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEP,KAAK;IAAEC;EAAO,CAAC;EACpCO,MAAM,EAAE;IAAEC,GAAG,EAAE,CAAC;IAAEC,IAAI,EAAE,CAAC;IAAEC,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE;AACjD,CAAC,GACDlB,oBAAoB;AAE1B,OAAO,SAASmB,sBAAsBA,CAAC;EAAEC,QAAQ;EAAEC;AAAa,CAAC,EAAE;EACjE,MAAMP,MAAM,GAAGnB,KAAK,CAAC2B,UAAU,CAACrB,qBAAqB,CAAC;EAEtDmB,QAAQ,gBAAGf,IAAA,CAACF,iBAAiB;IAAAiB,QAAA,EAAEA;EAAQ,CAAoB,CAAC;EAE5D,IAAIN,MAAM,EAAE;IACV;IACA;IACA;IACA,oBAAOT,IAAA,CAACN,IAAI;MAACsB,KAAK,EAAE,CAACE,MAAM,CAACC,SAAS,EAAEH,KAAK,CAAE;MAAAD,QAAA,EAAEA;IAAQ,CAAO,CAAC;EAClE;EAEA,oBACEf,IAAA,CAACH,gBAAgB;IAACO,cAAc,EAAEA,cAAe;IAACY,KAAK,EAAEA,KAAM;IAAAD,QAAA,EAC5DA;EAAQ,CACO,CAAC;AAEvB;AAEAD,sBAAsB,CAACV,cAAc,GAAGA,cAAc;AAEtD,MAAMc,MAAM,GAAGzB,UAAU,CAAC2B,MAAM,CAAC;EAC/BD,SAAS,EAAE;IACTE,IAAI,EAAE;EACR;AACF,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["React","Dimensions","Platform","StyleSheet","View","initialWindowMetrics","SafeAreaInsetsContext","SafeAreaProvider","FrameSizeProvider","jsx","_jsx","width","height","get","initialMetrics","OS","frame","x","y","insets","top","left","right","bottom","SafeAreaProviderCompat","children","style","useContext","initialFrame","styles","container","create","flex"],"sourceRoot":"../../src","sources":["SafeAreaProviderCompat.tsx"],"mappings":";;AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SACEC,UAAU,EACVC,QAAQ,EAERC,UAAU,EACVC,IAAI,QAEC,cAAc;AACrB,SACEC,oBAAoB,EACpBC,qBAAqB,EACrBC,gBAAgB,QACX,gCAAgC;AAEvC,SAASC,iBAAiB,QAAQ,mBAAgB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAOnD,MAAM;EAAEC,KAAK,GAAG,CAAC;EAAEC,MAAM,GAAG;AAAE,CAAC,GAAGX,UAAU,CAACY,GAAG,CAAC,QAAQ,CAAC;;AAE1D;AACA;AACA;AACA,MAAMC,cAAc,GAClBZ,QAAQ,CAACa,EAAE,KAAK,KAAK,IAAIV,oBAAoB,IAAI,IAAI,GACjD;EACEW,KAAK,EAAE;IAAEC,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEP,KAAK;IAAEC;EAAO,CAAC;EACpCO,MAAM,EAAE;IAAEC,GAAG,EAAE,CAAC;IAAEC,IAAI,EAAE,CAAC;IAAEC,KAAK,EAAE,CAAC;IAAEC,MAAM,EAAE;EAAE;AACjD,CAAC,GACDlB,oBAAoB;AAE1B,OAAO,SAASmB,sBAAsBA,CAAC;EAAEC,QAAQ;EAAEC;AAAa,CAAC,EAAE;EACjE,MAAMP,MAAM,GAAGnB,KAAK,CAAC2B,UAAU,CAACrB,qBAAqB,CAAC;EAEtDmB,QAAQ,gBACNf,IAAA,CAACF,iBAAiB;IAACoB,YAAY,EAAEd,cAAc,CAACE,KAAM;IAAAS,QAAA,EACnDA;EAAQ,CACQ,CACpB;EAED,IAAIN,MAAM,EAAE;IACV;IACA;IACA;IACA,oBAAOT,IAAA,CAACN,IAAI;MAACsB,KAAK,EAAE,CAACG,MAAM,CAACC,SAAS,EAAEJ,KAAK,CAAE;MAAAD,QAAA,EAAEA;IAAQ,CAAO,CAAC;EAClE;EAEA,oBACEf,IAAA,CAACH,gBAAgB;IAACO,cAAc,EAAEA,cAAe;IAACY,KAAK,EAAEA,KAAM;IAAAD,QAAA,EAC5DA;EAAQ,CACO,CAAC;AAEvB;AAEAD,sBAAsB,CAACV,cAAc,GAAGA,cAAc;AAEtD,MAAMe,MAAM,GAAG1B,UAAU,CAAC4B,MAAM,CAAC;EAC/BD,SAAS,EAAE;IACTE,IAAI,EAAE;EACR;AACF,CAAC,CAAC","ignoreList":[]}
@@ -1,22 +1,24 @@
1
1
  "use strict";
2
2
 
3
3
  import * as React from 'react';
4
- import { Dimensions, Platform, StyleSheet } from 'react-native';
4
+ import { Platform, StyleSheet } from 'react-native';
5
+ import { SafeAreaListener,
5
6
  // eslint-disable-next-line no-restricted-imports
6
- import { useSafeAreaFrame } from 'react-native-safe-area-context';
7
+ useSafeAreaFrame } from 'react-native-safe-area-context';
7
8
  import useLatestCallback from 'use-latest-callback';
8
9
  import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
9
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
10
11
  const FrameContext = /*#__PURE__*/React.createContext(undefined);
11
- export function useFrameSize(selector, debounce) {
12
+ export function useFrameSize(selector, throttle) {
12
13
  const context = React.useContext(FrameContext);
13
14
  if (context == null) {
14
15
  throw new Error('useFrameSize must be used within a FrameSizeProvider');
15
16
  }
16
- const value = useSyncExternalStoreWithSelector(debounce ? context.subscribeDebounced : context.subscribe, context.getCurrent, context.getCurrent, selector);
17
+ const value = useSyncExternalStoreWithSelector(throttle ? context.subscribeThrottled : context.subscribe, context.getCurrent, context.getCurrent, selector);
17
18
  return value;
18
19
  }
19
20
  export function FrameSizeProvider({
21
+ initialFrame,
20
22
  children
21
23
  }) {
22
24
  const context = React.useContext(FrameContext);
@@ -25,87 +27,116 @@ export function FrameSizeProvider({
25
27
  return children;
26
28
  }
27
29
  return /*#__PURE__*/_jsx(FrameSizeProviderInner, {
30
+ initialFrame: initialFrame,
28
31
  children: children
29
32
  });
30
33
  }
31
34
  function FrameSizeProviderInner({
35
+ initialFrame,
32
36
  children
33
37
  }) {
34
- const listeners = React.useRef(new Set());
35
- const {
36
- element,
37
- get
38
- } = useResizeListener(size => {
39
- listeners.current.forEach(listener => listener(size));
38
+ const frameRef = React.useRef({
39
+ width: initialFrame.width,
40
+ height: initialFrame.height
40
41
  });
41
- const getCurrent = useLatestCallback(get);
42
+ const listeners = React.useRef(new Set());
43
+ const getCurrent = useLatestCallback(() => frameRef.current);
42
44
  const subscribe = useLatestCallback(listener => {
43
45
  listeners.current.add(listener);
44
46
  return () => {
45
47
  listeners.current.delete(listener);
46
48
  };
47
49
  });
48
- const subscribeDebounced = useLatestCallback(listener => {
50
+ const subscribeThrottled = useLatestCallback(listener => {
51
+ const delay = 100; // Throttle delay in milliseconds
52
+
49
53
  let timer;
50
- const debouncedListener = size => {
54
+ let updated = false;
55
+ let waiting = false;
56
+ const throttledListener = () => {
51
57
  clearTimeout(timer);
52
- timer = setTimeout(() => {
53
- listener(size);
54
- }, 100);
58
+ updated = true;
59
+ if (waiting) {
60
+ // Schedule a timer to call the listener at the end
61
+ timer = setTimeout(() => {
62
+ if (updated) {
63
+ updated = false;
64
+ listener();
65
+ }
66
+ }, delay);
67
+ } else {
68
+ waiting = true;
69
+ setTimeout(function () {
70
+ waiting = false;
71
+ }, delay);
72
+
73
+ // Call the listener immediately at start
74
+ updated = false;
75
+ listener();
76
+ }
55
77
  };
56
- listeners.current.add(debouncedListener);
78
+ const unsubscribe = subscribe(throttledListener);
57
79
  return () => {
80
+ unsubscribe();
58
81
  clearTimeout(timer);
59
- listeners.current.delete(debouncedListener);
60
82
  };
61
83
  });
62
84
  const context = React.useMemo(() => ({
63
85
  getCurrent,
64
86
  subscribe,
65
- subscribeDebounced
66
- }), [subscribe, subscribeDebounced, getCurrent]);
67
- return /*#__PURE__*/_jsxs(FrameContext.Provider, {
68
- value: context,
69
- children: [element, children]
87
+ subscribeThrottled
88
+ }), [subscribe, subscribeThrottled, getCurrent]);
89
+ const onChange = useLatestCallback(frame => {
90
+ if (frameRef.current.height === frame.height && frameRef.current.width === frame.width) {
91
+ return;
92
+ }
93
+ frameRef.current = {
94
+ width: frame.width,
95
+ height: frame.height
96
+ };
97
+ listeners.current.forEach(listener => listener());
98
+ });
99
+ return /*#__PURE__*/_jsxs(_Fragment, {
100
+ children: [Platform.OS === 'web' ? /*#__PURE__*/_jsx(FrameSizeListenerWeb, {
101
+ onChange: onChange
102
+ }) : typeof SafeAreaListener === 'undefined' ? /*#__PURE__*/_jsx(FrameSizeListenerNativeFallback, {
103
+ onChange: onChange
104
+ }) : /*#__PURE__*/_jsx(SafeAreaListener, {
105
+ onChange: ({
106
+ frame
107
+ }) => onChange(frame),
108
+ style: StyleSheet.absoluteFill
109
+ }), /*#__PURE__*/_jsx(FrameContext.Provider, {
110
+ value: context,
111
+ children: children
112
+ })]
70
113
  });
71
114
  }
72
- const useResizeListener = Platform.OS === 'web' ? useResizeListenerWeb : useResizeListenerNative;
73
- function useResizeListenerNative(onChange) {
115
+
116
+ // SafeAreaListener is available only on newer versions
117
+ // Fallback to an effect-based shim for older versions
118
+ function FrameSizeListenerNativeFallback({
119
+ onChange
120
+ }) {
74
121
  const frame = useSafeAreaFrame();
75
122
  React.useLayoutEffect(() => {
76
123
  onChange(frame);
77
124
  }, [frame, onChange]);
78
- return {
79
- element: null,
80
- get: () => frame
81
- };
125
+ return null;
82
126
  }
83
- const {
84
- width = 0,
85
- height = 0
86
- } = Dimensions.get('window');
87
127
 
88
128
  // FIXME: On the Web, the safe area frame value doesn't update on resize
89
129
  // So we workaround this by measuring the frame on resize
90
- function useResizeListenerWeb(onChange) {
91
- const frameRef = React.useRef({
92
- width,
93
- height
94
- });
130
+ function FrameSizeListenerWeb({
131
+ onChange
132
+ }) {
95
133
  const elementRef = React.useRef(null);
96
134
  React.useEffect(() => {
97
135
  if (elementRef.current == null) {
98
136
  return;
99
137
  }
100
- const update = size => {
101
- if (frameRef.current.width === size.width && frameRef.current.height === size.height) {
102
- return;
103
- }
104
- frameRef.current = size;
105
- onChange(size);
106
- };
107
138
  const rect = elementRef.current.getBoundingClientRect();
108
- update({
139
+ onChange({
109
140
  width: rect.width,
110
141
  height: rect.height
111
142
  });
@@ -116,7 +147,7 @@ function useResizeListenerWeb(onChange) {
116
147
  width,
117
148
  height
118
149
  } = entry.contentRect;
119
- update({
150
+ onChange({
120
151
  width,
121
152
  height
122
153
  });
@@ -127,7 +158,7 @@ function useResizeListenerWeb(onChange) {
127
158
  observer.disconnect();
128
159
  };
129
160
  }, [onChange]);
130
- const element = /*#__PURE__*/_jsx("div", {
161
+ return /*#__PURE__*/_jsx("div", {
131
162
  ref: elementRef,
132
163
  style: {
133
164
  ...StyleSheet.absoluteFillObject,
@@ -135,9 +166,5 @@ function useResizeListenerWeb(onChange) {
135
166
  visibility: 'hidden'
136
167
  }
137
168
  });
138
- return {
139
- element,
140
- get: () => frameRef.current
141
- };
142
169
  }
143
170
  //# sourceMappingURL=useFrameSize.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["React","Dimensions","Platform","StyleSheet","useSafeAreaFrame","useLatestCallback","useSyncExternalStoreWithSelector","jsx","_jsx","jsxs","_jsxs","FrameContext","createContext","undefined","useFrameSize","selector","debounce","context","useContext","Error","value","subscribeDebounced","subscribe","getCurrent","FrameSizeProvider","children","FrameSizeProviderInner","listeners","useRef","Set","element","get","useResizeListener","size","current","forEach","listener","add","delete","timer","debouncedListener","clearTimeout","setTimeout","useMemo","Provider","OS","useResizeListenerWeb","useResizeListenerNative","onChange","frame","useLayoutEffect","width","height","frameRef","elementRef","useEffect","update","rect","getBoundingClientRect","observer","ResizeObserver","entries","entry","contentRect","observe","disconnect","ref","style","absoluteFillObject","pointerEvents","visibility"],"sourceRoot":"../../src","sources":["useFrameSize.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","Platform","StyleSheet","SafeAreaListener","useSafeAreaFrame","useLatestCallback","useSyncExternalStoreWithSelector","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","FrameContext","createContext","undefined","useFrameSize","selector","throttle","context","useContext","Error","value","subscribeThrottled","subscribe","getCurrent","FrameSizeProvider","initialFrame","children","FrameSizeProviderInner","frameRef","useRef","width","height","listeners","Set","current","listener","add","delete","delay","timer","updated","waiting","throttledListener","clearTimeout","setTimeout","unsubscribe","useMemo","onChange","frame","forEach","OS","FrameSizeListenerWeb","FrameSizeListenerNativeFallback","style","absoluteFill","Provider","useLayoutEffect","elementRef","useEffect","rect","getBoundingClientRect","observer","ResizeObserver","entries","entry","contentRect","observe","disconnect","ref","absoluteFillObject","pointerEvents","visibility"],"sourceRoot":"../../src","sources":["useFrameSize.tsx"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"SafeAreaProviderCompat.d.ts","sourceRoot":"","sources":["../../../src/SafeAreaProviderCompat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAGL,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAStB,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAeF,wBAAgB,sBAAsB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,2CAiBhE;yBAjBe,sBAAsB"}
1
+ {"version":3,"file":"SafeAreaProviderCompat.d.ts","sourceRoot":"","sources":["../../../src/SafeAreaProviderCompat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAGL,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAStB,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAeF,wBAAgB,sBAAsB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,KAAK,2CAqBhE;yBArBe,sBAAsB"}
@@ -1,11 +1,15 @@
1
1
  import * as React from 'react';
2
- type Size = {
2
+ import { type StyleProp, type ViewStyle } from 'react-native';
3
+ type Frame = {
3
4
  width: number;
4
5
  height: number;
5
6
  };
6
- export declare function useFrameSize<T>(selector: (size: Size) => T, debounce?: boolean): T;
7
- export declare function FrameSizeProvider({ children }: {
7
+ export declare function useFrameSize<T>(selector: (frame: Frame) => T, throttle?: boolean): T;
8
+ type FrameSizeProviderProps = {
9
+ initialFrame: Frame;
8
10
  children: React.ReactNode;
9
- }): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
11
+ style?: StyleProp<ViewStyle>;
12
+ };
13
+ export declare function FrameSizeProvider({ initialFrame, children, }: FrameSizeProviderProps): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
10
14
  export {};
11
15
  //# sourceMappingURL=useFrameSize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFrameSize.d.ts","sourceRoot":"","sources":["../../../src/useFrameSize.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAO/B,KAAK,IAAI,GAAG;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAgBF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,EAC3B,QAAQ,CAAC,EAAE,OAAO,GACjB,CAAC,CAeH;AAED,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,yTAS5E"}
1
+ {"version":3,"file":"useFrameSize.d.ts","sourceRoot":"","sources":["../../../src/useFrameSize.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAEL,KAAK,SAAS,EAEd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAStB,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAgBF,wBAAgB,YAAY,CAAC,CAAC,EAC5B,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,CAAC,EAC7B,QAAQ,CAAC,EAAE,OAAO,GACjB,CAAC,CAeH;AAED,KAAK,sBAAsB,GAAG;IAC5B,YAAY,EAAE,KAAK,CAAC;IACpB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,EAChC,YAAY,EACZ,QAAQ,GACT,EAAE,sBAAsB,yTAaxB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@react-navigation/elements",
3
3
  "description": "UI Components for React Navigation",
4
- "version": "2.4.6",
4
+ "version": "2.5.1",
5
5
  "keywords": [
6
6
  "react-native",
7
7
  "react-navigation",
@@ -49,7 +49,7 @@
49
49
  "devDependencies": {
50
50
  "@jest/globals": "^30.0.0",
51
51
  "@react-native-masked-view/masked-view": "0.3.2",
52
- "@react-navigation/native": "^7.1.13",
52
+ "@react-navigation/native": "^7.1.14",
53
53
  "@testing-library/react-native": "^13.2.0",
54
54
  "@types/react": "~19.0.10",
55
55
  "@types/use-sync-external-store": "^1.5.0",
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "peerDependencies": {
64
64
  "@react-native-masked-view/masked-view": ">= 0.2.0",
65
- "@react-navigation/native": "^7.1.13",
65
+ "@react-navigation/native": "^7.1.14",
66
66
  "react": ">= 18.2.0",
67
67
  "react-native": "*",
68
68
  "react-native-safe-area-context": ">= 4.0.0"
@@ -90,5 +90,5 @@
90
90
  ]
91
91
  ]
92
92
  },
93
- "gitHead": "0eea403da627af2624d8dc0d985d00d92c79f569"
93
+ "gitHead": "0508fba46d6ea4823de28f35e981d5cc8f15e93a"
94
94
  }
@@ -36,7 +36,11 @@ const initialMetrics =
36
36
  export function SafeAreaProviderCompat({ children, style }: Props) {
37
37
  const insets = React.useContext(SafeAreaInsetsContext);
38
38
 
39
- children = <FrameSizeProvider>{children}</FrameSizeProvider>;
39
+ children = (
40
+ <FrameSizeProvider initialFrame={initialMetrics.frame}>
41
+ {children}
42
+ </FrameSizeProvider>
43
+ );
40
44
 
41
45
  if (insets) {
42
46
  // If we already have insets, don't wrap the stack in another safe area provider
@@ -1,23 +1,31 @@
1
1
  import * as React from 'react';
2
- import { Dimensions, Platform, StyleSheet } from 'react-native';
3
- // eslint-disable-next-line no-restricted-imports
4
- import { useSafeAreaFrame } from 'react-native-safe-area-context';
2
+ import {
3
+ Platform,
4
+ type StyleProp,
5
+ StyleSheet,
6
+ type ViewStyle,
7
+ } from 'react-native';
8
+ import {
9
+ SafeAreaListener,
10
+ // eslint-disable-next-line no-restricted-imports
11
+ useSafeAreaFrame,
12
+ } from 'react-native-safe-area-context';
5
13
  import useLatestCallback from 'use-latest-callback';
6
14
  import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector';
7
15
 
8
- type Size = {
16
+ type Frame = {
9
17
  width: number;
10
18
  height: number;
11
19
  };
12
20
 
13
- type Listener = (size: Size) => void;
21
+ type Listener = () => void;
14
22
 
15
23
  type RemoveListener = () => void;
16
24
 
17
25
  type FrameContextType = {
18
- getCurrent: () => Size;
19
- subscribe: (listener: Listener, debounce?: boolean) => RemoveListener;
20
- subscribeDebounced: (listener: Listener) => RemoveListener;
26
+ getCurrent: () => Frame;
27
+ subscribe: (listener: Listener) => RemoveListener;
28
+ subscribeThrottled: (listener: Listener) => RemoveListener;
21
29
  };
22
30
 
23
31
  const FrameContext = React.createContext<FrameContextType | undefined>(
@@ -25,8 +33,8 @@ const FrameContext = React.createContext<FrameContextType | undefined>(
25
33
  );
26
34
 
27
35
  export function useFrameSize<T>(
28
- selector: (size: Size) => T,
29
- debounce?: boolean
36
+ selector: (frame: Frame) => T,
37
+ throttle?: boolean
30
38
  ): T {
31
39
  const context = React.useContext(FrameContext);
32
40
 
@@ -35,7 +43,7 @@ export function useFrameSize<T>(
35
43
  }
36
44
 
37
45
  const value = useSyncExternalStoreWithSelector(
38
- debounce ? context.subscribeDebounced : context.subscribe,
46
+ throttle ? context.subscribeThrottled : context.subscribe,
39
47
  context.getCurrent,
40
48
  context.getCurrent,
41
49
  selector
@@ -44,7 +52,16 @@ export function useFrameSize<T>(
44
52
  return value;
45
53
  }
46
54
 
47
- export function FrameSizeProvider({ children }: { children: React.ReactNode }) {
55
+ type FrameSizeProviderProps = {
56
+ initialFrame: Frame;
57
+ children: React.ReactNode;
58
+ style?: StyleProp<ViewStyle>;
59
+ };
60
+
61
+ export function FrameSizeProvider({
62
+ initialFrame,
63
+ children,
64
+ }: FrameSizeProviderProps) {
48
65
  const context = React.useContext(FrameContext);
49
66
 
50
67
  if (context != null) {
@@ -52,21 +69,25 @@ export function FrameSizeProvider({ children }: { children: React.ReactNode }) {
52
69
  return children;
53
70
  }
54
71
 
55
- return <FrameSizeProviderInner>{children}</FrameSizeProviderInner>;
72
+ return (
73
+ <FrameSizeProviderInner initialFrame={initialFrame}>
74
+ {children}
75
+ </FrameSizeProviderInner>
76
+ );
56
77
  }
57
78
 
58
79
  function FrameSizeProviderInner({
80
+ initialFrame,
59
81
  children,
60
- }: {
61
- children: React.ReactNode;
62
- }): React.JSX.Element {
63
- const listeners = React.useRef<Set<Listener>>(new Set());
64
-
65
- const { element, get } = useResizeListener((size) => {
66
- listeners.current.forEach((listener) => listener(size));
82
+ }: FrameSizeProviderProps) {
83
+ const frameRef = React.useRef<Frame>({
84
+ width: initialFrame.width,
85
+ height: initialFrame.height,
67
86
  });
68
87
 
69
- const getCurrent = useLatestCallback(get);
88
+ const listeners = React.useRef<Set<Listener>>(new Set());
89
+
90
+ const getCurrent = useLatestCallback(() => frameRef.current);
70
91
 
71
92
  const subscribe = useLatestCallback((listener: Listener): RemoveListener => {
72
93
  listeners.current.add(listener);
@@ -76,22 +97,44 @@ function FrameSizeProviderInner({
76
97
  };
77
98
  });
78
99
 
79
- const subscribeDebounced = useLatestCallback(
100
+ const subscribeThrottled = useLatestCallback(
80
101
  (listener: Listener): RemoveListener => {
102
+ const delay = 100; // Throttle delay in milliseconds
103
+
81
104
  let timer: ReturnType<typeof setTimeout>;
105
+ let updated = false;
106
+ let waiting = false;
82
107
 
83
- const debouncedListener = (size: Size) => {
108
+ const throttledListener = () => {
84
109
  clearTimeout(timer);
85
- timer = setTimeout(() => {
86
- listener(size);
87
- }, 100);
110
+
111
+ updated = true;
112
+
113
+ if (waiting) {
114
+ // Schedule a timer to call the listener at the end
115
+ timer = setTimeout(() => {
116
+ if (updated) {
117
+ updated = false;
118
+ listener();
119
+ }
120
+ }, delay);
121
+ } else {
122
+ waiting = true;
123
+ setTimeout(function () {
124
+ waiting = false;
125
+ }, delay);
126
+
127
+ // Call the listener immediately at start
128
+ updated = false;
129
+ listener();
130
+ }
88
131
  };
89
132
 
90
- listeners.current.add(debouncedListener);
133
+ const unsubscribe = subscribe(throttledListener);
91
134
 
92
135
  return () => {
136
+ unsubscribe();
93
137
  clearTimeout(timer);
94
- listeners.current.delete(debouncedListener);
95
138
  };
96
139
  }
97
140
  );
@@ -100,45 +143,63 @@ function FrameSizeProviderInner({
100
143
  () => ({
101
144
  getCurrent,
102
145
  subscribe,
103
- subscribeDebounced,
146
+ subscribeThrottled,
104
147
  }),
105
- [subscribe, subscribeDebounced, getCurrent]
148
+ [subscribe, subscribeThrottled, getCurrent]
106
149
  );
107
150
 
151
+ const onChange = useLatestCallback((frame: Frame) => {
152
+ if (
153
+ frameRef.current.height === frame.height &&
154
+ frameRef.current.width === frame.width
155
+ ) {
156
+ return;
157
+ }
158
+
159
+ frameRef.current = { width: frame.width, height: frame.height };
160
+ listeners.current.forEach((listener) => listener());
161
+ });
162
+
108
163
  return (
109
- <FrameContext.Provider value={context}>
110
- {element}
111
- {children}
112
- </FrameContext.Provider>
164
+ <>
165
+ {Platform.OS === 'web' ? (
166
+ <FrameSizeListenerWeb onChange={onChange} />
167
+ ) : typeof SafeAreaListener === 'undefined' ? (
168
+ <FrameSizeListenerNativeFallback onChange={onChange} />
169
+ ) : (
170
+ <SafeAreaListener
171
+ onChange={({ frame }) => onChange(frame)}
172
+ style={StyleSheet.absoluteFill}
173
+ />
174
+ )}
175
+ <FrameContext.Provider value={context}>{children}</FrameContext.Provider>
176
+ </>
113
177
  );
114
178
  }
115
179
 
116
- const useResizeListener =
117
- Platform.OS === 'web' ? useResizeListenerWeb : useResizeListenerNative;
118
-
119
- function useResizeListenerNative(onChange: (size: Size) => void) {
180
+ // SafeAreaListener is available only on newer versions
181
+ // Fallback to an effect-based shim for older versions
182
+ function FrameSizeListenerNativeFallback({
183
+ onChange,
184
+ }: {
185
+ onChange: (frame: Frame) => void;
186
+ }) {
120
187
  const frame = useSafeAreaFrame();
121
188
 
122
189
  React.useLayoutEffect(() => {
123
190
  onChange(frame);
124
191
  }, [frame, onChange]);
125
192
 
126
- return {
127
- element: null,
128
- get: () => frame,
129
- };
193
+ return null;
130
194
  }
131
195
 
132
- const { width = 0, height = 0 } = Dimensions.get('window');
133
-
134
196
  // FIXME: On the Web, the safe area frame value doesn't update on resize
135
197
  // So we workaround this by measuring the frame on resize
136
- function useResizeListenerWeb(onChange: (size: Size) => void) {
137
- const frameRef = React.useRef<Size>({
138
- width,
139
- height,
140
- });
141
-
198
+ function FrameSizeListenerWeb({
199
+ onChange,
200
+ }: {
201
+ onChange: (frame: Frame) => void;
202
+ }) {
142
203
  const elementRef = React.useRef<HTMLDivElement>(null);
143
204
 
144
205
  React.useEffect(() => {
@@ -146,21 +207,9 @@ function useResizeListenerWeb(onChange: (size: Size) => void) {
146
207
  return;
147
208
  }
148
209
 
149
- const update = (size: Size) => {
150
- if (
151
- frameRef.current.width === size.width &&
152
- frameRef.current.height === size.height
153
- ) {
154
- return;
155
- }
156
-
157
- frameRef.current = size;
158
- onChange(size);
159
- };
160
-
161
210
  const rect = elementRef.current.getBoundingClientRect();
162
211
 
163
- update({
212
+ onChange({
164
213
  width: rect.width,
165
214
  height: rect.height,
166
215
  });
@@ -171,7 +220,7 @@ function useResizeListenerWeb(onChange: (size: Size) => void) {
171
220
  if (entry) {
172
221
  const { width, height } = entry.contentRect;
173
222
 
174
- update({ width, height });
223
+ onChange({ width, height });
175
224
  }
176
225
  });
177
226
 
@@ -182,7 +231,7 @@ function useResizeListenerWeb(onChange: (size: Size) => void) {
182
231
  };
183
232
  }, [onChange]);
184
233
 
185
- const element = (
234
+ return (
186
235
  <div
187
236
  ref={elementRef}
188
237
  style={{
@@ -192,9 +241,4 @@ function useResizeListenerWeb(onChange: (size: Size) => void) {
192
241
  }}
193
242
  />
194
243
  );
195
-
196
- return {
197
- element,
198
- get: () => frameRef.current,
199
- };
200
244
  }