@granite-js/react-native 1.0.36 → 1.0.37
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @granite-js/react-native
|
|
2
2
|
|
|
3
|
+
## 1.0.37
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e60a630: fix(react-native): stop forwarding InView API props to the host view
|
|
8
|
+
- Updated dependencies [2096242]
|
|
9
|
+
- @granite-js/mpack@1.0.37
|
|
10
|
+
- @granite-js/cli@1.0.37
|
|
11
|
+
- @granite-js/blur-view@1.0.37
|
|
12
|
+
- @granite-js/brownfield-module@1.0.37
|
|
13
|
+
- @granite-js/jest@1.0.37
|
|
14
|
+
- @granite-js/native@1.0.37
|
|
15
|
+
- @granite-js/plugin-core@1.0.37
|
|
16
|
+
- @granite-js/style-utils@1.0.37
|
|
17
|
+
- @granite-js/video@1.0.37
|
|
18
|
+
|
|
3
19
|
## 1.0.36
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granite-js/react-native",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.37",
|
|
4
4
|
"description": "The Granite Framework",
|
|
5
5
|
"bin": {
|
|
6
6
|
"granite": "./bin/cli.js"
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"@babel/core": "7.28.5",
|
|
92
92
|
"@babel/preset-env": "7.28.5",
|
|
93
93
|
"@babel/preset-typescript": "7.28.5",
|
|
94
|
-
"@granite-js/native": "1.0.
|
|
95
|
-
"@granite-js/vitest": "1.0.
|
|
94
|
+
"@granite-js/native": "1.0.37",
|
|
95
|
+
"@granite-js/vitest": "1.0.37",
|
|
96
96
|
"@testing-library/dom": "^10.4.0",
|
|
97
97
|
"@testing-library/react": "^16.1.0",
|
|
98
98
|
"@types/babel__core": "^7",
|
|
@@ -114,21 +114,21 @@
|
|
|
114
114
|
"zod": "^4.1.12"
|
|
115
115
|
},
|
|
116
116
|
"peerDependencies": {
|
|
117
|
-
"@granite-js/native": "1.0.
|
|
117
|
+
"@granite-js/native": "1.0.37",
|
|
118
118
|
"@types/react": "*",
|
|
119
119
|
"brick-module": "*",
|
|
120
120
|
"react": "*",
|
|
121
121
|
"react-native": "*"
|
|
122
122
|
},
|
|
123
123
|
"dependencies": {
|
|
124
|
-
"@granite-js/blur-view": "1.0.
|
|
125
|
-
"@granite-js/brownfield-module": "1.0.
|
|
126
|
-
"@granite-js/cli": "1.0.
|
|
127
|
-
"@granite-js/jest": "1.0.
|
|
128
|
-
"@granite-js/mpack": "1.0.
|
|
129
|
-
"@granite-js/plugin-core": "1.0.
|
|
130
|
-
"@granite-js/style-utils": "1.0.
|
|
131
|
-
"@granite-js/video": "1.0.
|
|
124
|
+
"@granite-js/blur-view": "1.0.37",
|
|
125
|
+
"@granite-js/brownfield-module": "1.0.37",
|
|
126
|
+
"@granite-js/cli": "1.0.37",
|
|
127
|
+
"@granite-js/jest": "1.0.37",
|
|
128
|
+
"@granite-js/mpack": "1.0.37",
|
|
129
|
+
"@granite-js/plugin-core": "1.0.37",
|
|
130
|
+
"@granite-js/style-utils": "1.0.37",
|
|
131
|
+
"@granite-js/video": "1.0.37",
|
|
132
132
|
"@standard-schema/spec": "^1.0.0",
|
|
133
133
|
"es-toolkit": "^1.39.8",
|
|
134
134
|
"react-native-url-polyfill": "3.0.0"
|
|
@@ -330,6 +330,12 @@ function ImpressionAreaImpl({
|
|
|
330
330
|
return (
|
|
331
331
|
<InView
|
|
332
332
|
onChange={(inView, currentThreshold) => {
|
|
333
|
+
// Guard against non-observer invocations (e.g. a bubbling native event reaching
|
|
334
|
+
// the callback): a wrong `false` here sticks forever because the observer only
|
|
335
|
+
// re-notifies when its own `inView` value changes.
|
|
336
|
+
if (typeof inView !== 'boolean' || typeof currentThreshold !== 'number') {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
333
339
|
const isVisible = inView && currentThreshold >= areaThreshold;
|
|
334
340
|
setInviewImpressed(isVisible);
|
|
335
341
|
}}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { render } from '@testing-library/react';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
2
3
|
import { View } from 'react-native';
|
|
3
4
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
5
|
import IOContext, { IOContextValue } from './IOContext';
|
|
@@ -147,6 +148,33 @@ describe('InView', () => {
|
|
|
147
148
|
expect(outer.unobserve).toHaveBeenCalledTimes(1);
|
|
148
149
|
});
|
|
149
150
|
|
|
151
|
+
it('does not forward its own API props (onChange, triggerOnce) to the rendered view', () => {
|
|
152
|
+
const manager = new FakeIntersectionObserverRegistry();
|
|
153
|
+
const onChange = vi.fn();
|
|
154
|
+
const received: Record<string, unknown>[] = [];
|
|
155
|
+
const CaptureView = forwardRef<View, Record<string, unknown>>((props, ref) => {
|
|
156
|
+
received.push(props);
|
|
157
|
+
return <View ref={ref} />;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
render(
|
|
161
|
+
<IOContext.Provider value={{ manager: manager.asManager, parent: { manager: null } }}>
|
|
162
|
+
<InView as={CaptureView} triggerOnce onChange={onChange} testID="target">
|
|
163
|
+
<View />
|
|
164
|
+
</InView>
|
|
165
|
+
</IOContext.Provider>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const props = received.at(-1);
|
|
169
|
+
// API props must not leak: `onChange` on a host View is a bubbling event handler,
|
|
170
|
+
// so change events from descendants (e.g. TextInput) would call the observer
|
|
171
|
+
// callback with a SyntheticEvent.
|
|
172
|
+
expect(props).not.toHaveProperty('onChange');
|
|
173
|
+
expect(props).not.toHaveProperty('triggerOnce');
|
|
174
|
+
// Regular ViewProps still pass through.
|
|
175
|
+
expect(props).toHaveProperty('testID', 'target');
|
|
176
|
+
});
|
|
177
|
+
|
|
150
178
|
it('with triggerOnce, stops observing all ancestors once visible', () => {
|
|
151
179
|
const inner = new FakeIntersectionObserverRegistry();
|
|
152
180
|
const outer = new FakeIntersectionObserverRegistry();
|
|
@@ -257,7 +257,12 @@ class InView<T = ViewProps> extends PureComponent<InViewProps<T>> {
|
|
|
257
257
|
};
|
|
258
258
|
|
|
259
259
|
render() {
|
|
260
|
-
|
|
260
|
+
// `onChange` and `triggerOnce` are InView's own API props and must not reach the
|
|
261
|
+
// rendered view. In React Native `onChange` is a bubbling event (`topChange`), so
|
|
262
|
+
// passing it through would make change events from descendants (e.g. a typing
|
|
263
|
+
// `TextInput`) invoke the observer callback with a SyntheticEvent instead of
|
|
264
|
+
// `(inView, intersectionRatio)`.
|
|
265
|
+
const { as, children, triggerOnce, onChange, ...props } = this.props;
|
|
261
266
|
if (typeof children === 'function') {
|
|
262
267
|
return null;
|
|
263
268
|
}
|